Same passport js strategy with different configuration (SAML)
Asked Answered
W

2

7

I'm trying to create SSO in my Nest.js application using Okta as Identity Provider and passport-saml library. I read documentation of Nest authentication and passport-saml. I have no problems with understanding of examples, but I really need to use SAML strategy with different configuration which depend on request body value of POST api/auth/saml. In other words, I have one strategy, but with different entryPoint, issuer, cert params for my custom LoginSSOStrategy class which extends PassportStrategy class of Nest.js. Any ideas how can I handle this?

Wrinkle answered 9/12, 2019 at 13:3 Comment(1)
hi, do you have any update? I am facing the same issueEliott
P
2

I'm not quite sure if this is a good approach, but if you want, you can make the class request scoped and inject the request via the constructor, then have access to the request object and be able to work with a new instance of your passport strategy each request. You can use the request to pass req.whatever to the super() class's constructor.

@Injectable({ scope: Scope.REQUEST })
export class LoginSSOStrategy exends PassportStrategy(Strategy) {

  constructor(@Inject(REQUEST) request: Request, ...) {
    super({/* options matching to request.field */});
  }

  validate(/* validate params*/) {
    /* validate functionality */
  }
}

This seems like something you'll want to do a lot of testing around and making sure it works with concurrent requests, but overall it could work, in theory at least.

Polynesian answered 9/12, 2019 at 19:47 Comment(0)
T
0

I think this issue is similar to this GitHub issue. Due to the global nature of Passport.js and the fact that Nest is unable to determine which routes use a Passport passport strategy it is not possible to create a request scoped Passport strategy by using @Injectable({ scope: Scope.REQUEST }).

Recently, I had to implement a Azure Active Directory login with a dynamic redirect URL based on some data from the incoming request. Depending on the Strategy you use, you might be able to overwrite some options when calling the authenticate method of a Passport Strategy by using the (undocumented) extraAuthReqQueryParams property. One way to know wether or not you're able to overwrite some options is to check the documentation, if you're feeling lucky you could look in the source code of the Passport strategy you're using. After reading about the undocumented feature and seeing these lines in the source code of the Azure AD Passport strategy (in particular lines #1355 and #1374) I was able to change the value I previously specified in the redirectUrl property by using the redirect_uri property (note the slight difference here).

@Injectable()
export class AzureOIDCStrategy extends PassportStrategy(OIDCStrategy,'AzureOIDC') {
  constructor() {
    super({
      // Even though it is overwritten in the 'authenticate' method the Passport Strategy expects this to be set to a valid URL.
      redirectUrl: `https://your-backend-domain.com/auth/azure/callback`,
      // This ensures we have access to the request in the `authenticate` method
      passReqToCallback: true,
    });
  }

  authenticate(req: Request, options: Record<string, any>): void {
    return super.authenticate(req, {
      // `options` may contain more options for the `authenticate` method in Passport.
      ...options,
      extraAuthReqQueryParams: {
        // This overwrites the `redirectUrl` specified in the constructor
        redirect_uri: `https://${req.headers.host}/auth/callback`,
      },
    });
  }
}

I hope you will be able to apply this 'strategy' to update the entryPoint, issuer and cert params.

In an Express app you could do something like this:

app.get('/login', 
  (req, res, next) =>
    passport.authenticate('azure-ad', {
      extraAuthReqQueryParams: {
        redirect_uri: `https://${req.headers.host}/auth/callback`,
      },
  })(req, res, next)
);
Tuneless answered 9/3, 2021 at 19:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.