Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I redirect back to the originally-requested url after authentication with passport-saml?

Sorry if this is a bonehead question, but I'm having some trouble understanding how I might redirect the client browser back to whatever URL was originally requested after a successful authentication with our SAML identity provider (IdP). I'm using the latest versions of passport-saml, passport, and express.

For example, say the client originally requested /foo/bar from a link on another unprotected page, but since that is a protected resource, I respond with a redirect to /login, which is where I call passport.authenticate('saml').

app.get('/login', passport.authenticate('saml'));  function ensureAuth(req, res, next) {     if (req.user.isAuthenticated()) {return next();}     else {res.redirect('/login');} }  app.get('/foo/bar', ensureAuth, function(req, res) {     ... }); 

That call will redirect the browser to my IdP's sign-on page, and after a successful authentication, the IdP POSTs back to my /login/callback route. In that route, I again use passport.authenticate(saml) to validate the response SAML, and if all is good, I then get to redirect the browser back to the requested resource...but how do I know what that requested resource was? Because it's a POST callback, I've lost any state associated with the original request.

app.post('/login/callback', passport.authenticate('saml'), function(req, res) {     res.redirect('...can I know which url to redirect back to?...'); }); 

The example in the passport-saml readme just shows a hard-coded redirect back to the root resource, but I would want to redirect back to the originally-requested URL (/foo/bar).

Can I send a url, or some other value, to the IdP that will get round-tripped and POSTed back in the response SAML? And if so, how can I access it in my /login/callback route?

Or is there some better, express/passport way to do this that I'm missing?

Any help you can provide would be most appreciated!

like image 940
Dave Stearns Avatar asked Jul 06 '14 23:07

Dave Stearns


People also ask

What is redirect URL in SAML?

HTTP redirect enables SAML protocol messages to be transmitted within URL parameters. It enables SAML requestors and responders to communicate by using an HTTP user agent as an intermediary.

What is SAML target URL?

It is the end point where the service provider sends its SAML authentication request and where the user is authenticated. This information is commonly referred to by service providers as the Identity Provider Target URL , SSO Login URL , Redirect URL , or Identity Provider Endpoint .

How does Passport SAML work?

Cache ProviderWhen InResponseTo validation is turned on, Passport-SAML will store generated request ids used in SAML requests to the IdP. The implementation of how things are stored, checked to see if they exist, and eventually removed is from the Cache Provider used by Passport-SAML.


1 Answers

Can I send a url, or some other value, to the IdP that will get round-tripped and POSTed back in the response SAML? And if so, how can I access it in my /login/callback route?

To round-trip a value via the IdP you need to use RelayState. This is a value that you can send to the IdP and, if you do, they are obliged to send it back without alterations.

Here is the what the SAML specifications has to say:

3.1.1 Use of RelayState

Some bindings define a "RelayState" mechanism for preserving and conveying state information. When such a mechanism is used in conveying a request message as the initial step of a SAML protocol, it places requirements on the selection and use of the binding subsequently used to convey the response. Namely, if a SAML request message is accompanied by RelayState data, then the SAML responder MUST return its SAML protocol response using a binding that also supports a RelayState mechanism, and it MUST place the exact RelayState data it received with the request into the corresponding RelayState parameter in the response.

To use this with passport-saml you must add it as an additionalParams value. The code below shows this happening.

saml = new SamlStrategy     path: appConfig.passport.saml.path     decryptionPvk: fs.readFileSync(appConfig.passport.saml.privateKeyFile)     issuer: appConfig.passport.saml.issuer     identifierFormat: tenant.strategy.identifierFormat     entryPoint: tenant.strategy.entryPoint     additionalParams:{'RelayState':tenant.key}     ,     (profile, next) ->          # get the user from the profile 

The code above is from a multi-tenant saml implementation so I am sending my tenant.key as the RelayState param. I then retrieve this value from the body of POSTed return from the IdP and use it to re-establish all the state I need.

getTenantKey: (req, next) ->     key = req.body?.RelayState ? routes.match(req.path).params.tenentKey     next null, key 

Your case might be simpler. You will probably want to store the final-destination url in a time limited cache and then send the cache-key as the RelayState param.

For what it is worth, you can avoid using RelayState altogether if you just use the original SAML request-id as your cache key. This value is always sent back to you via the InResponseTo field.

like image 130
biofractal Avatar answered Oct 06 '22 07:10

biofractal