Node.js ExpressJS/Passport SAML单次注销直接重新登录

Node.js ExpressJS/Passport SAML单次注销直接重新登录,node.js,express,passport.js,adfs,passport-saml,Node.js,Express,Passport.js,Adfs,Passport Saml,目前,我正在NodeJS应用程序中开发passport saml实现。 这样做的原因是让我们的客户能够连接到他们的AD FS系统并利用SingleSignOn(SSO) 因为我们还想提供注销功能,所以我正在研究这个逻辑。然而,我似乎无法让这个简单的功能正常工作。我已经在谷歌上搜索了很多,尝试了很多变体和配置,但不幸的是,它不起作用 我想为我们的客户提供一种同时由SP和IdP驱动的单点注销(SLO)的可能性。这是我的出发点。在调试和开发过程中,我已经后退了一步,试图终止本地会话,但即使这样似乎也不

目前,我正在NodeJS应用程序中开发passport saml实现。 这样做的原因是让我们的客户能够连接到他们的AD FS系统并利用SingleSignOn(SSO)

因为我们还想提供注销功能,所以我正在研究这个逻辑。然而,我似乎无法让这个简单的功能正常工作。我已经在谷歌上搜索了很多,尝试了很多变体和配置,但不幸的是,它不起作用

我想为我们的客户提供一种同时由SP和IdP驱动的单点注销(SLO)的可能性。这是我的出发点。在调试和开发过程中,我已经后退了一步,试图终止本地会话,但即使这样似乎也不可能

这是我为SAML配置的路由的相关代码:

const isAuthenticated = (req, res, next) => {
    if (req.isAuthenticated()) {
      // User logged in, pass on to next middleware
      console.info('User authenticated');
      return next();
    }
    // User not logged in, redirect to login page
    console.info('User not authenticated');
    return res.redirect('/login');
  };

// GET-routes
  app.get('/',
    isAuthenticated,
    (req, res) => {
      res.send('Authenticated');
    });

  app.get('/login',
    passport.authenticate('saml', {
      successRedirect: '/',
      failureRedirect: '/login/fail',
    }));

  app.get('/logout',
    (req, res) => {
      passport._strategy('saml').logout(req, (err, url) => {
        return res.redirect(url);
      });
    });

// POST-routes
  app.post('/adfs/callback',
    (req, res, next) => {
      passport.authenticate('saml', (err, user) => {
        // If error occurred redirect to failure URL
        if (err) return res.redirect('/login/fail');
        // If no user could be found, redirect to failure URL
        if (!user) return res.redirect('/login/fail');
        // User found, handle registration of user on request
        req.logIn(user, (loginErr) => {
          if (loginErr) return res.status(400).send(err);
          // Request session set, put in store
          store.set(req.sessionID, req.session, (storeErr) => {
            if (storeErr) return res.status(400).send(storeErr);
            return res.redirect('/');
          });
        });
      })(req, res, next);
    });

  app.post('/logout/callback', (req, res) => {
    // Destroy session and cookie
    store.destroy(req.sessionID, async (err) => {
      req.logout();
      return res.redirect('/');
    });
  });

可以看出,我控制了会话存储处理(设置和销毁会话,但如果这是不明智的,请给出建议)。 实现的会话存储是MemoryStore()

当用户登录时,一切正常。 然后一个请求被发送到route/logout,一些东西发生了,我可以看到会话发生了变化,会话ID以及passport saml的相关参数(nameID,sessionIndex)发生了变化,然后用户被重新路由到“/”

但是,用户将被视为未经身份验证,并被重新路由到“/login”。有人会争辩说,它到此为止,因为必须重新输入凭证。 情况并非如此,因为用户将直接再次登录,而无需重新输入凭据,我不知道如何防止这种情况

我真希望任何人都知道发生了什么:)
如果需要更多的信息,我很乐意听到。

经过大量的研究和调查,我确实找到了解决这个问题的方法。 诀窍在于passport saml包的定义,特别是authncontext参数

因此,之前我将SamlStrategy选项定义为:

{
  // URL that should be configured inside the AD FS as return URL for authentication requests
  callbackUrl: `<URL>`,
  // URL on which the AD FS should be reached
  entryPoint: <URL>,
  // Identifier for the CIR-COO application in the AD FS
  issuer: <identifier>,
  identifierFormat: null,
  // CIR-COO private certificate
  privateCert: <private_cert_path>,
  // Identity Provider's public key
  cert: <cert_path>,
  authnContext: ["urn:federation:authentication:windows"],
  // AD FS signature hash algorithm with which the response is encrypted
  signatureAlgorithm: <algorithm>,
  // Single Log Out URL AD FS
  logoutUrl: <URL>,
  // Single Log Out callback URL
  logoutCallbackUrl: `<URL>`,
}
{
//应在AD FS中配置为身份验证请求返回URL的URL
callbackUrl:``,
//应在其上访问AD FS的URL
入口点:,
//AD FS中CIR-COO应用程序的标识符
发行人:,
地址:null,
//CIR-COO专用证书
私人证书:,
//身份提供者的公钥
证书:,
authnContext:[“urn:federation:authentication:windows”],
//用于加密响应的AD FS签名哈希算法
签名算法:,
//单个注销URL AD FS
注销URL:,
//单个注销回调URL
logoutCallbackUrl:``,
}
但经过大量研究,我意识到这种身份验证:windows选项是罪魁祸首,因此我将其改为:

{
  // URL that should be configured inside the AD FS as return URL for authentication requests
  callbackUrl: `<URL>`,
  // URL on which the AD FS should be reached
  entryPoint: <URL>,
  // Identifier for the CIR-COO application in the AD FS
  issuer: <identifier>,
  identifierFormat: null,
  // CIR-COO private certificate
  privateCert: <private_cert_path>,
  // Identity Provider's public key
  cert: <cert_path>,
  authnContext: ["urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
    "urn:federation:authentication:windows"],
  // AD FS signature hash algorithm with which the response is encrypted
  signatureAlgorithm: <algorithm>,
  // Single Log Out URL AD FS
  logoutUrl: <URL>,
  // Single Log Out callback URL
  logoutCallbackUrl: `<URL>`,
},
{
//应在AD FS中配置为身份验证请求返回URL的URL
callbackUrl:``,
//应在其上访问AD FS的URL
入口点:,
//AD FS中CIR-COO应用程序的标识符
发行人:,
地址:null,
//CIR-COO专用证书
私人证书:,
//身份提供者的公钥
证书:,
authnContext:[“urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport”,
“urn:federation:authentication:windows”],
//用于加密响应的AD FS签名哈希算法
签名算法:,
//单个注销URL AD FS
注销URL:,
//单个注销回调URL
logoutCallbackUrl:``,
},

这基本上意味着它不会检索默认登录到系统的用户的Windows凭据,从而重定向到ADFS服务器的登录屏幕。

因此,经过大量研究和调查,我确实找到了解决此问题的方法。 诀窍在于passport saml包的定义,特别是authncontext参数

因此,之前我将SamlStrategy选项定义为:

{
  // URL that should be configured inside the AD FS as return URL for authentication requests
  callbackUrl: `<URL>`,
  // URL on which the AD FS should be reached
  entryPoint: <URL>,
  // Identifier for the CIR-COO application in the AD FS
  issuer: <identifier>,
  identifierFormat: null,
  // CIR-COO private certificate
  privateCert: <private_cert_path>,
  // Identity Provider's public key
  cert: <cert_path>,
  authnContext: ["urn:federation:authentication:windows"],
  // AD FS signature hash algorithm with which the response is encrypted
  signatureAlgorithm: <algorithm>,
  // Single Log Out URL AD FS
  logoutUrl: <URL>,
  // Single Log Out callback URL
  logoutCallbackUrl: `<URL>`,
}
{
//应在AD FS中配置为身份验证请求返回URL的URL
callbackUrl:``,
//应在其上访问AD FS的URL
入口点:,
//AD FS中CIR-COO应用程序的标识符
发行人:,
地址:null,
//CIR-COO专用证书
私人证书:,
//身份提供者的公钥
证书:,
authnContext:[“urn:federation:authentication:windows”],
//用于加密响应的AD FS签名哈希算法
签名算法:,
//单个注销URL AD FS
注销URL:,
//单个注销回调URL
logoutCallbackUrl:``,
}
但经过大量研究,我意识到这种身份验证:windows选项是罪魁祸首,因此我将其改为:

{
  // URL that should be configured inside the AD FS as return URL for authentication requests
  callbackUrl: `<URL>`,
  // URL on which the AD FS should be reached
  entryPoint: <URL>,
  // Identifier for the CIR-COO application in the AD FS
  issuer: <identifier>,
  identifierFormat: null,
  // CIR-COO private certificate
  privateCert: <private_cert_path>,
  // Identity Provider's public key
  cert: <cert_path>,
  authnContext: ["urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
    "urn:federation:authentication:windows"],
  // AD FS signature hash algorithm with which the response is encrypted
  signatureAlgorithm: <algorithm>,
  // Single Log Out URL AD FS
  logoutUrl: <URL>,
  // Single Log Out callback URL
  logoutCallbackUrl: `<URL>`,
},
{
//应在AD FS中配置为身份验证请求返回URL的URL
callbackUrl:``,
//应在其上访问AD FS的URL
入口点:,
//AD FS中CIR-COO应用程序的标识符
发行人:,
地址:null,
//CIR-COO专用证书
私人证书:,
//身份提供者的公钥
证书:,
authnContext:[“urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport”,
“urn:federation:authentication:windows”],
//用于加密响应的AD FS签名哈希算法
签名算法:,
//单个注销URL AD FS
注销URL:,
//单个注销回调URL
logoutCallbackUrl:``,
},
这基本上意味着它不会检索默认登录到系统的用户的Windows凭据,从而重定向到ADFS服务器的登录屏幕。

使用authnContext:[“urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport”]在会话中,安装程序将在注销后再次显示用户名和密码页面

已注销https://adfs-url/adfs/ls/?wa=wsignout1.0.

再次登录后将创建新会话id。

使用authnContext: