WSO2IS + node.js passport-saml 集成错误

Posted

技术标签:

【中文标题】WSO2IS + node.js passport-saml 集成错误【英文标题】:WSO2IS + node.js passport-saml integration error 【发布时间】:2014-08-05 19:15:41 【问题描述】:

我现在正在尝试使用 wso2is 服务器和 node.js passport-saml 模块来测试 SAML2 集成。 但它认为在 wso2 方面不起作用。

node.js 服务器重定向到带有 SAML 断言的 wso2 服务器。 这是解码的 SAML 请求评估

<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_e62f87ab1740cab74c67" Version="2.0" IssueInstant="2014-06-16T01:16:54.199Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="https://localhost:3000/login/callback" Destination="https://localhost:9443/samlsso">
   <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">passport-saml</saml:Issuer>
   <samlp:RequestedAuthnContext Comparison="exact">
      <saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
   </samlp:RequestedAuthnContext>
   <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true" />
</samlp:AuthnRequest>

在我将用户 ID/密码输入 wso2 登录屏幕后。 我有一个错误

基于 SAML 2.0 的单点登录

处理认证请求时出错!

有人可以对此发表意见吗?

在 wso2is 配置中

SP 已注册,我只设置入站身份验证配置 > SAML2 Web SSO 配置 > 颁发者:passport-saml。 断言消费者 URL:http://localhost:3000/login/callback

这里是 node.js 代码

var express = require('express')
  , passport = require('passport-debug')
  , util = require('util')
  , SamlStrategy = require('../../lib/passport-saml/index').Strategy
  , fs = require('fs');


var users = [
     id: 1, givenName: 'bob', email: 'bob@example.com' 
  ,  id: 2, givenName: 'joe', email: 'joe@example.com' 
];

function findByEmail(email, fn) 
  for (var i = 0, len = users.length; i < len; i++) 
    var user = users[i];
    if (user.email === email) 
      return fn(null, user);
    
  
  return fn(null, null);



// Passport session setup.
//   To support persistent login sessions, Passport needs to be able to
//   serialize users into and deserialize users out of the session.  Typically,
//   this will be as simple as storing the user ID when serializing, and finding
//   the user by ID when deserializing.
passport.serializeUser(function(user, done) 
  done(null, user.email);
);

passport.deserializeUser(function(id, done) 
  findByEmail(id, function (err, user) 
    done(err, user);
  );
);

passport.use(new SamlStrategy(
  
    path: '/login/callback',
    entryPoint: 'https://localhost:9443/samlsso',
    issuer: 'passport-saml',

    //protocol: 'http://',
    //cert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w=='/*,
    //privateCert: fs.readFileSync('./cert.pem', 'utf-8')*/
  ,
  function(profile, done) 
    console.log("Auth with", profile);
    if (!profile.email) 
      return done(new Error("No email found"), null);
    
    // asynchronous verification, for effect...
    process.nextTick(function () 
      findByEmail(profile.email, function(err, user) 
        if (err) 
          return done(err);
        
        if (!user) 
          // "Auto-registration"
          users.push(profile);
          return done(null, profile);
        
        return done(null, user);
      )
    );
  
));

var app = express.createServer();

// configure Express
app.configure(function() 
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.use(express.logger());
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.session( secret: 'keyboard cat' ));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
  app.use(express.static(__dirname + '/../../public'));
);


app.get('/', function(req, res)
  res.render('index',  user: req.user );
);

app.get('/account', ensureAuthenticated, function(req, res)
  res.render('account',  user: req.user );
);

app.get('/login',
  passport.authenticate('saml',  failureRedirect: '/error', failureFlash: true,samlFallback:'login-request' ),
  function(req, res) 
    res.redirect('/idc');
  
);

app.post('/login/callback',
  passport.authenticate('saml',  failureRedirect: '/', failureFlash: true ),
  function(req, res) 
    res.redirect('/idc');
  
);

app.get('/logout', function(req, res)
  req.logout();
  res.redirect('/');
);

app.listen(3000, function () 
  console.log("Server listening in http://localhost:3000");
);

// Simple route middleware to ensure user is authenticated.
//   Use this route middleware on any resource that needs to be protected.  If
//   the request is authenticated (typically via a persistent login session),
//   the request will proceed.  Otherwise, the user will be redirected to the
//   login page.
function ensureAuthenticated(req, res, next) 
  if (req.isAuthenticated())  return next(); 
  res.redirect('/login')


附加评论。 在我修复了 node.js 代码之后。 护照.use(新的 SamlStrategy(

  
    path: '/login/callback',
    entryPoint: 'https://localhost:9443/samlsso',
    issuer: 'passport-saml',
    protocol: 'http://'

wso2 (idp) 对 node.js passport-saml 回调模块的响应 SAML 响应断言 这是来自 wso2 的 SAML 响应断言

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://localhost:3000/login/callback" ID="nnjiingggcmkbagmbndjpcaignnlkcickjadcomp" InResponseTo="_4ca6c18350670c605fa7" IssueInstant="2014-06-16T01:55:28.312Z" Version="2.0">
   <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">localhost</saml2:Issuer>
   <saml2p:Status>
      <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
   </saml2p:Status>
   <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="bpplnakjbmabobeeimjihmelgdebhgcinikjfped" IssueInstant="2014-06-16T01:55:28.312Z" Version="2.0">
      <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">localhost</saml2:Issuer>
      <saml2:Subject>
         <saml2:NameID>admin</saml2:NameID>
         <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
            <saml2:SubjectConfirmationData InResponseTo="_4ca6c18350670c605fa7" NotOnOrAfter="2014-06-16T02:00:28.312Z" Recipient="http://localhost:3000/login/callback" />
         </saml2:SubjectConfirmation>
      </saml2:Subject>
      <saml2:Conditions NotBefore="2014-06-16T01:55:28.312Z" NotOnOrAfter="2014-06-16T02:00:28.312Z">
         <saml2:AudienceRestriction>
            <saml2:Audience>passport-saml</saml2:Audience>
         </saml2:AudienceRestriction>
      </saml2:Conditions>
      <saml2:AuthnStatement AuthnInstant="2014-06-16T01:55:28.312Z">
         <saml2:AuthnContext>
            <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
         </saml2:AuthnContext>
      </saml2:AuthnStatement>
   </saml2:Assertion>
</saml2p:Response>

但我从护照-saml 方面收到这样的错误

127.0.0.1 - - [Mon, 16 Jun 2014 01:55:28 GMT] "GET /login HTTP/1.1" 302 1282 "-"
 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chr
ome/35.0.1916.114 Safari/537.36"
SAML:authentication has benn called
SAML:authenticate:error:[object Object]
SAML:authenticate:error:[object Object]
SAML authenticate:PostResponse[object Object]
TypeError: Cannot read property 'Format' of undefined
    at C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passport-saml\lib\passpo
rt-saml\saml.js:425:24
    at Parser.<anonymous> (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\pass
port-saml\node_modules\xml2js\lib\xml2js.js:384:20)
    at Parser.EventEmitter.emit (events.js:95:17)
    at Object.onclosetag (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passp
ort-saml\node_modules\xml2js\lib\xml2js.js:348:26)
    at emit (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passport-saml\node
_modules\xml2js\node_modules\sax\lib\sax.js:615:33)
    at emitNode (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passport-saml\
node_modules\xml2js\node_modules\sax\lib\sax.js:620:3)
    at closeTag (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passport-saml\
node_modules\xml2js\node_modules\sax\lib\sax.js:861:5)
    at Object.write (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passport-s
aml\node_modules\xml2js\node_modules\sax\lib\sax.js:1294:29)
    at Parser.exports.Parser.Parser.parseString (C:\Users\bw.cho\AppData\Roaming
\npm\node_modules\passport-saml\node_modules\xml2js\lib\xml2js.js:403:31)
    at Parser.parseString (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\pass
port-saml\node_modules\xml2js\lib\xml2js.js:6:61)
127.0.0.1 - - [Mon, 16 Jun 2014 01:55:28 GMT] "POST /login/callback HTTP/1.1" 50
0 1310 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/35.0.1916.114 Safari/537.36"

奇怪的是,在 WSO2 中是服务器 SAML 断言响应。

<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">localhost</saml2:Issuer>

我将 Issuer 编码为“passport-saml”,但在 SAML 响应中它已更改为 localhost 你对此有什么想法吗?


添加评论。 元素中缺少 SAML 响应属性“格式”。

<saml2:NameID>admin</saml2:NameID>

所以我更改了 WSO2 SAML 配置中的配置。 我用“urn:oasis:names:tc:SAML:2.0:nameid-format:entity”添加了“NameID 格式” 在那之后它似乎有效。 此外,在 SAML 响应中,它不会在 SAML 响应断言中发送“电子邮件”,我做了如下的小代码更改。 (而不是使用电子邮件,它使用用户 ID)

passport.use(new SamlStrategy(
  
    path: '/login/callback',
    entryPoint: 'https://localhost:9443/samlsso',
    issuer: 'passport-saml',
    protocol: 'http://',
    //identifierFormat :'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
    identifierFormat :'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
    //cert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w=='/*,
    //privateCert: fs.readFileSync('./cert.pem', 'utf-8')*/
  ,
  function(profile, done) 
    console.log("Auth with", profile);
    console.log('Name Id',profile.nameID);
    if (!profile.nameID) 
      return done(new Error("No nameId found"), null);
    
    // asynchronous verification, for effect...
    process.nextTick(function () 
      findByEmail(profile.nameID, function(err, user) 
            console.log('User ',user);
        if (err) 
          return done(err);
        
        if (!user) 
          // "Auto-registration"
          users.push(profile);
          return done(null, profile);
        
        return done(null, user);
      )
    );
  
));

但我仍然在护照 SAML 中遇到错误

127.0.0.1 - - [Mon, 16 Jun 2014 02:38:05 GMT] "GET /login HTTP/1.1" 302 1322 "-"
 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chr
ome/35.0.1916.114 Safari/537.36"
SAML:authentication has benn called
SAML:authenticate:error:[object Object]
SAML:authenticate:error:[object Object]
SAML authenticate:PostResponse[object Object]
SAML:authenticate:errornull
Auth with  issuer:
    _: 'localhost',
     '$':  Format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'  ,
  nameID: 'admin',
  nameIDFormat: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity' 
Name Id admin
User   id: 1, givenName: 'bob', email: 'admin' 

TypeError: object is not a function
    at pass (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passport-debug\lib
\passport\index.js:249:14)
    at Passport.serializeUser (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\
passport-debug\lib\passport\index.js:251:5)
    at IncomingMessage.req.login.req.logIn (C:\Users\bw.cho\AppData\Roaming\npm\
node_modules\passport-saml\node_modules\passport\lib\http\request.js:48:29)
    at Context.delegate.success (C:\Users\bw.cho\AppData\Roaming\npm\node_module
s\passport-debug\lib\passport\middleware\authenticate.js:194:13)
    at Context.actions.success (C:\Users\bw.cho\AppData\Roaming\npm\node_modules
\passport-debug\lib\passport\context\http\actions.js:21:25)
    at verified (C:\Users\bw.cho\AppData\Roaming\npm\node_modules\passport-saml\
lib\passport-saml\strategy.js:55:14)
    at C:\dev\workspaces\node_js\SAML2\app.js:68:16
    at findByEmail (C:\dev\workspaces\node_js\SAML2\app.js:17:14)
    at C:\dev\workspaces\node_js\SAML2\app.js:58:7
    at process._tickCallback (node.js:415:13)

【问题讨论】:

【参考方案1】:

我可以回答为什么主题名称需要格式属性的部分——这是一个错误,我已在https://github.com/bergie/passport-saml/issues/40 提交。

很高兴听到您成功了!

【讨论】:

【参考方案2】:

我解决了问题。 将“passport-debug”模块替换为“passport”模块后,它可以工作 完整的源代码是https://github.com/bwcho75/node.js_study/tree/master/WSO2SAML2 享受

【讨论】:

以上是关于WSO2IS + node.js passport-saml 集成错误的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 和 Passport 对象没有方法 validPassword

Express Passport (node.js) 错误处理

使用 Sails.JS 框架的 Node.JS -- Passport:没有在名称下注册策略:facebook

为移动应用程序进行 facebook 登录的正确方法是啥(使用 node.js/passport.js 服务器)

带有 Passport 的 Node.js 身份验证:如果缺少字段,如何闪烁消息?

在带有 React.js 前端的 Node.js 上使用 Passport.js 进行身份验证