@NickTaylor98

Passport-SAML. Как пропустить вызов getSamlOptions после успешной аутентификации?

Пытаюсь вкрутить SSO в свой проект. Имеется федерация, которая предоставляет мне список IdP, через которые я могу аутентифицироваться. Использую для аутентификации 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. Данная форма отправляет запрос на наш сервер с идентификатором IdP (параметр entityID), чтобы наш сервер перенаправил пользователя на сервер IdP.
3. Наш сервер получает идентификатор entityId, находит в своей базе данных URL перехода и редиректит пользователя по этому URL.
4. Пользователь вводит свои данные и аутентифицируется внутри IdP. IdP отсылает инфу о пользователе по URL GET /auth/saml/callback

Далее собственно мы сталкиваемся с проблемой. Функция getSamlOptions вызывается даже после аутентификации на IdP. И если разобрать выше приведённый код, то понятно будет, что у нас имеется попытка обратиться к entityID, который собственно IdP на наш сервер уже не отсылает, поэтому всегда я получаю ошибку о том, что entityID is undefined. Помогите советом, как обойти вызов getSamlOptions после аутентификации на IdP или как мне достать entityID в коллбэке.
  • Вопрос задан
  • 90 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы