N
N
NickTaylor982021-06-22 13:04:50
Node.js
NickTaylor98, 2021-06-22 13:04:50

Passport SAML. How to skip getSamlOptions call after successful authentication?

I'm trying to screw SSO into my project. There is a federation that provides me with a list of IdPs through which I can authenticate. I use passport-saml for authentication .

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);
};

Next, I will show the processing of requests related to authentication:
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
  );
};

My problem is the following.
1. First, the user goes to the authentication form provided by the federation, where he can select some IdP
2. This form sends a request to our server with the IdP identifier ( entityID parameter ) , so that our server redirects the user to the IdP server.
3. Our server gets the entityId, finds the referral URL in its database, and redirects the user to that URL.
4. The user enters their credentials and authenticates within the IdP. IdP sends information about the user to the URL GET /auth/saml/callback

Next, we actually face a problem. getSamlOptions functioncalled even after authenticating to the IdP. And if we disassemble the above code, it will be clear that we have an attempt to access the entityID , which the IdP itself no longer sends to our server, so I always get an error that entityID is undefined. Please help with advice on how to bypass the getSamlOptions call after IdP authentication or how can I get the entityID in the callback.

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question