在使用passport-saml进行身份验证后,如何重定向回原始请求的url



抱歉,如果这是一个愚蠢的问题,但我有一些麻烦理解我如何可能重定向客户端浏览器回到任何URL最初请求与我们的SAML身份提供程序(IdP)成功的身份验证后。我用的是最新版本的passport-saml、passport和express。

例如,假设客户端最初从另一个未受保护的页面上的链接请求/foo/bar,但由于这是一个受保护的资源,我响应重定向到/login,这是我调用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) {
    ...
});

该调用将浏览器重定向到我的IdP的登录页面,并且在成功的身份验证之后,IdP将返回到我的/login/callback路由。在该路由中,我再次使用passport.authenticate(saml)来验证响应SAML,如果一切正常,我就可以将浏览器重定向回所请求的资源…但是我怎么知道请求的资源是什么呢?因为它是POST回调,所以我丢失了与原始请求相关的任何状态。

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

passport-saml自述文件中的示例仅显示了硬编码重定向回根资源,但我希望重定向回原始请求的URL (/foo/bar)。

我可以发送一个url,或一些其他值,到IdP将得到往返和张贴回响应SAML?如果是这样,我如何在/login/callback路由中访问它?

或者有更好的,快递/护照的方式来做到这一点,我错过了?

您能提供的任何帮助将是最感激的!

我可以发送一个url,或一些其他值,到IdP将获得在响应SAML中往返和post ?如果有,怎么能我在我的/login/callback路由中访问它?

要通过IdP往返一个值,需要使用RelayState。这是一个您可以发送给IdP的值,如果您这样做了,他们有义务将其原样发回。

下面是SAML规范必须说的:

3.1.1 RelayState 的使用

一些绑定定义了一个"RelayState"机制来保存和传递状态信息。当这种机制被用于将请求消息作为SAML协议的初始步骤来传递,那么它就可以对装订的选择和使用提出了要求随后用来传达回应。也就是说,如果一个SAML请求消息伴随着RelayState数据,然后是SAML响应器必须返回它的SAML协议响应使用绑定也支持RelayState机制,并且必须放置准确的将它接收到的RelayState数据与请求转换成相应的状态

要在passport-saml中使用它,必须将其添加为additionalParams值。下面的代码显示了这种情况。

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

上面的代码来自一个多租户的示例实现,所以我将tenant.key作为RelayState参数发送。然后,我从IdP返回的post主体中检索该值,并使用它来重新建立所需的所有状态。

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

你的情况可能更简单。您可能希望将最终目的地url存储在有时间限制的缓存中,然后将缓存键作为RelayState参数发送。

无论如何,如果您只使用原始的SAML请求id作为缓存键,则可以完全避免使用RelayState。这个值总是通过InResponseTo字段发送给你。

如果您想在每个请求的基础上指定RelayState,您可能会认为您可以这样做:

passport.authenticate('saml', { additionalParams: { RelayState: "foo" } })

但这不起作用。如果您查看实现:https://github.com/bergie/passport-saml/blob/6d1215bf96e9e352c25e92d282cba513ed8e876c/lib/passport-saml/saml.js#L326,您将看到additionParams是从初始配置选项或从req对象(但不是从每个请求选项)中拾取的。

但幸运的是,Passport SAML策略为每个请求执行此操作:

var RelayState = req.query && req.query.RelayState || req.body && req.body.RelayState;

然后在配置选项中查找更多(全局)additionalParams。

所以如果你想在每个请求的基础上指定RelayParams,你必须在调用authorize之前将它们加载到req中。在我的例子中,我在路由处理程序的中做了这样的:

req.query.RelayState = req.params.redirect_to;
passport.authenticate('saml')(req, res, next);

然后,当重定向的请求从SAML IdP返回时,您应该能够使用req.body.RelayParams来访问每个请求的状态。

注意,如果RelayParams值是一个对象,你可能不得不使用JSON。将其编码为RelayParams和JSON。解析它解码回来(我必须这样做,在我的情况下)。

相关内容

  • 没有找到相关文章

最新更新