0

尝试在我的项目上设置 Passport-SAML。这是一个代码示例

export const samlFederationAuthentication = () => {
  const multiSamlStrategy: MultiSamlStrategy = new MultiSamlStrategy(
    {
      passReqToCallback: true,
      getSamlOptions: async (req: Express.Request, done: SamlOptionsCallback) => {
        const entityID: string = decodeURIComponent((req.query.entityID as string) || '');

        if (!entityID) {
          return done(
            CustomError(
              'Not supported',
              'SAML AUTH',
              `EntityID is undefined`
            )
          );
        }

        const config = await samlFederation.getConfig(); // getting entrypoint and certificate

        if (!config[entityID]) {
          return done(
            CustomError(
              'Not supported',
              'SAML AUTH',
              `EntityID is not supported by IDp`
            )
          );
        }

        return done(null, {
          ...config[entityID],
          callbackUrl: envConfig.samlFederation.callbackURL,
          issuer: envConfig.samlFederation.issuer,
        });
      },
    },
    async (req: Express.Request, profile, done) => {
      try {
        const profileUsername: string = samlFederation.getProfileUsername(profile || {});

        if (!profileUsername) {
          return done(
            CustomError(
              'Username and email are undefined',
              'SAML AUTH',
              `Username or email should be defined in SAML profile`
            )
          );
        }

        const dbUser = await userService.getUserByUsername(profileUsername);

        if (!!dbUser) {
          return done(null, dbUser);
        }


        const createdUser: IUser = await userService.createUser(profile || {});

        return done(null, createdUser as Record<string, any>);
      } catch (err) {
        return done(err);
      }
    }
  );

  Passport.use('multi-saml', multiSamlStrategy);
};

和路线:

export const addSamlFederationRoutes = (app: Express.Application) => {
  app.get('/auth/saml', Passport.authenticate('multi-saml'));
  app.post(
    '/auth/saml/callback',
    Passport.authorize('multi-saml', { failureRedirect: '/', failureFlash: true }),
    userHandler // some handler with user data
  );
};

所以现在我描述我的问题。

  1. 用户进入联合表单并选择他们想要进行身份验证的一些特殊 IdP
  2. GET /auth/saml联合表单使用 EntityID向我们的服务器发送请求以查询外部 IdP。
  3. 我们的服务器查看数据库所需的配置参数并将用户重定向到 IdP 表单。

当用户转到 IdP 并输入他们的凭据时,他们会使用 url 重定向到我们的服务器auth/saml/callback。这很好,但我们调用中间件passport.authorize会导致调用getSamlOptionsMultiSamlStrategy 中的函数。但是 IdP 不会entityID在 params 中发送给我,而且我的函数总是发送 error Entity ID is undefined。所以,我的问题是如何避免getSamlOptions在 IdP 上进行身份验证后调用。

4

1 回答 1

1

我最近必须实现MultiSamlStrategy并且能够getSamlOptions通过使用配置使其工作而无需避免第二次调用RelayStatesaml最初,我使用查询变量“org”来指定要使用的配置。我将标识实体的参数传递到RelayState变量中。然后在第二次调用中,使用RelayState正确路由到预期的配置。这是一个例子:

passport.use('saml', new MultiSamlStrategy(
    {
        passReqToCallback: true, // makes req available in callback
        getSamlOptions: function (request, done) {
            var config;
            var org;

            if (request.query.org) {
                org = request.query.org;
                request.query.RelayState = JSON.stringify({ProviderName: request.query.org});

            } else {
                const relayState = JSON.parse(request.body.RelayState);
                org = relayState.ProviderName;
            }  

            if (org == "config1" ) {
                config = {
                    issuer: "http://localhost:80",
                    protocol: 'http://',
                    path: '<whatever path you setup>',
                    entryPoint: '<config1 entry point URL>',
                    cert: fs.readFileSync('./cert1.pem','utf-8'),
                    additionalParams: { 'RelayState': request.query.org }
                }
            } else if (org == "config2") {
                config = {
                    issuer: "http://localhost:80",
                    protocol: 'http://',
                    path: '<whatever path you setup>',
                    entryPoint: '<config2 entry point URL>',
                    cert: fs.readFileSync('./cert2.pem', 'utf-8'),
                    additionalParams: { 'RelayState': request.query.org }
                }
            }
            done(null, config);
        }
    },
    function (req, profile, done) {
        // for signon
        done(null, profile)
    },
    function (req, profile, done) {
        // for logout
        done(null, profile)
    }
));
于 2022-01-20T16:07:47.207 回答