2016-03-01 26 views
0

我是nodejs的初學者,試圖讓單點登錄工作。單一登錄對我的本地應用程序運行正常,使用OpenIdp進行身份驗證。但是,不是爲了我的應用程序運行在虛擬機上並集成到ADFS公司。我不確定這裏有什麼問題。使用OpenIDP單點登錄可以正常工作,但不能與ADFS一起使用

以下是與代碼相關的代碼。

app.js:



    'use strict'; 

    require('./appRequire'); 

    var config = appRequire('/config-bootstrap').config; 
    var logger = appRequire('/lib/app-logger'); 
    var isAuthenticated = appRequire('routes/is-authenticated'); 

    var busboy = require('connect-busboy'); 
    var express = require('express'); 
    var morgan = require('morgan'); //express logger 
    var path = require('path'); 
    var swig = require('swig'); 
    var app = express(); 
    // required for passport authentication 
    var passportRoutines = appRequire('/lib/passport-routines'); 
    var bodyParser = require('body-parser'); 
    var session = require('express-session'); 
    var methodOverride = require('method-override'); 
    var cookieParser = require('cookie-parser'); 


    app.use(cookieParser()); 
    app.use(bodyParser.json({limit: '50mb'})); 
    app.use(bodyParser.urlencoded({ 
     extended: true, 
     limit: '50mb' 
    })); 
    app.use(session({ 
      secret: "this is not secret", 
      resave: true, 
      saveUninitialized: true 
     })); 
    var passport = passportRoutines.getPassport(); 
    app.use(passport.initialize()); 
    app.use(passport.session()); 
    app.use(methodOverride()); 
    app.use('/', express.static(__dirname + '/public')); 
    app.use('/public', express.static(__dirname + '/vendor/public')); 
    app.use(busboy()); 

    app.use(morgan('combined', { 
     stream: logger.stream, 
     skip: function(req, res) { 
     return res.statusCode user object not available. Auth is not successful.") 
      return res.redirect(APP_ROOT + '/not-authorised'); 
      } 
      req.logIn(user, function(err) { 
      if (err) { 
       return next(err); 
      } 
      res.redirect(APP_ROOT); 
      }); 
     })(req, res, next); 
     }); 



    var serv = require('./routes/serv'); 
    app.use(APP_ROOT, serv); 

    var ROUTES = ['employees', 'accounts', 'activities', 'admin']; 
    ROUTES.forEach(function (route) { 
     app.all(APP_ROOT + '/' + route + '*', isAuthenticated); 
     var routeModule = require('./routes/' + route); 
     app.use(APP_ROOT + '/' + route, routeModule); 
    }); 

    var errorHandler = require('./routes/errors'); 
    app.use(APP_ROOT, errorHandler.router); 

    // 404 HANDLING 
    app.use(function(req, res, next) { 
     var notFoundError = new Error('Page ' + req.url + ' cannot be found'); 
     notFoundError.status = 404; 
     next(notFoundError); 
    }); 

    // ERROR HANDLING 

    app.use(errorHandler.errorHandler()); 


    swig.setDefaults({ 
     locals: { 
     appAssetPaths: { 
      'js': '/javascript', 
      'js_vendor': '/javascript/vendor', 
      'style': '/css/generated', 
      'style_vendor': '/css/vendor', 
      'static': '/icons' 
     } 
     } 
    }); 

    app.engine('html', swig.renderFile); 
    app.set('view engine', 'html'); 
    app.set('views', __dirname + '/views'); 

    if (!config.data_source === 'json') { 
     throw 'data source not implemented (' + config.data_source + ')'; 
    } 

    module.exports = app; 

護照routines.js:



    'use strict'; 
    var config = appRequire('/config-bootstrap').config; 
    var passport = require('passport'); 
    var fs = require('fs'); 
    var logger = appRequire('lib/app-logger').AppLoger; 

    function searchUser(username, passwordhash) { 
     return (require('fs').readFileSync(config.passport.basic.auth_file,'utf-8').split('\n').map(function(e){ 
      return { name : e.split(':')[0], passwordhash : e.split(':')[1] }; 
     }).filter(function(e){ 
      return (e.name === username && e.passwordhash === passwordhash); 
     }).length == 1); 
    } 

    function getCertificate(){ 
    if(config.passport.saml.cert){ 
     logger.info("using the certficate file :", config.passport.saml.cert); 
     return fs.readFileSync(config.passport.saml.cert, 'utf-8') 
    }else{ 
     logger.info("Cert property is not defnied"); 
     return null; 
    } 
    } 

    function getPassportStrategy(){ 
     switch(config.passport.strategy){ 
     case "saml": 
      var saml = require('passport-saml').Strategy; 
      var saml_options = { 
      entryPoint : config.passport.saml.entryPoint, 
      issuer : config.passport.saml.issuer, 
      acceptedClockSkewMs : config.passport.saml.acceptedClockSkewMs, 
      callbackUrl : config.passport.saml.callbackUrl, 
      signatureAlgorithm : 'sha256', 
      cert: getCertificate(), 
      identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', 
      }; 
      if (config.passport.saml.cert) { 
      saml_options['cert'] = fs.readFileSync(config.passport.saml.cert, 'utf-8'); 
      } 
      return new saml(saml_options, function(profile, done) { 
       logger.info(" profile retrieved from ADFS :", JSON.stringify(profile)) 
       console.log(" --> profile retrieved from ADFS :", JSON.stringify(profile)) 
       return done(null, { 
       id : profile.uid, 
       email : profile.email, 
       displayName : profile.cn, 
       firstName : profile.givenName, 
       lastName : profile.sn, 
       }); 
      }); 
     case "basic": 
      var httpbasic = require('passport-http').BasicStrategy; 
      return new httpbasic(function(username, password, done) { 
      return done(null, searchUser(username, require('md5')(password))); 
      }); 
     case "noauth": 
      var noauth = appRequire("/lib/passport-noauth").Strategy; 
      return new noauth(); 
     default: 
      throw "No known passport strategy configured!"; 
     } 
    } 

    var isAuthorised = function(user){ 
     var data, authUsers; 
     try{ 
      logger.info('User returned from ADFS :', JSON.stringify(user)) 
      console.log('--> User returned from ADFS :', JSON.stringify(user)) 
      data = fs.readFileSync(config.passport.saml.auth_users_file,'utf-8'); 
      authUsers = JSON.parse(data); 
      logger.info('Authorised users :', authUsers); 
     }catch(err){ 
      logger.error("Either authorised-users.json file does not exist or it not in the right format") 
      logger.error(err); 
     } 

     return true; 
    } 

    var isUserAuthorised = function(user) { 
     logger.info('user in passport-routines. js :', JSON.stringify(user)) 
     var DEFAULT_AUTH = function() { 
     return true; 
     }; 
     switch(config.passport.strategy){ 
     case "saml": 
      return function() { 
       var authorised = isAuthorised(user) 
       return authorised 
      }; 
     case "basic": 
      return DEFAULT_AUTH; 
     case "noauth": 
      return DEFAULT_AUTH; 
     } 
    }; 

    exports.getPassport = function() { 
     passport.serializeUser(function(user, done) { 
      done(null, user); 
     }); 
     passport.deserializeUser(function(user, done) { 
      done(null, user); 
     }); 
     passport.use(getPassportStrategy()); 
     return passport; 
    } 

    exports.isUserAuthorised = isUserAuthorised; 

我用於OpenIDP在配置有:



    "passport" : { 
     "strategy" : "saml", 
     "saml" : { 
      "entryPoint" : "https://openidp.feide.no/simplesaml/saml2/idp/SSOService.php", 
      "issuer" : "http://myapp.com", 
      "acceptedClockSkewMs" : -1, 
      "callbackUrl" : "https://myapp.com:8081/authenticated/", 
     "auth_users_file":"/path/to/authorised-users.json" 
     }, 
     } 

配置用於VM和ADFS組合:

<pre><code> 
"passport" : { 
    "strategy" : "saml", 
    "saml" : { 
      "path": "/", 
      "entryPoint": "https://adfs.mycomapny.com/adfs/ls/", 
      "cert": "/path/to/key.pem", 
      "issuer": "https://myapp.com", 
      "acceptedClockSkewMs": -1, 
      "authnContext": "http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows", 
      "identifierFormat": null, 
      "callbackUrl": "https://myapp.com/authenticated/", 
      "auth_users_file":"/path/to/authorised-users.json" 
    }, 
    } 

在這種情況下本地+ OpenIDP,我能看到的日誌從OpenIDP返回console.log(" --> profile retrieved from ADFS :"的價值觀。但是,logger.info(" profile retrieved from ADFS :"不會打印任何內容。 我不知道爲什麼console.log工作,但不是logger.info爲2016-03-01T16:54:30.670Z - info: profile retrieved from ADFS :爲空。 另外,console.log('--> User returned from ADFS :記錄了用戶數據的JSON。

對於VM + ADFS,這兩個日誌都是空的。應用程序進入'/未授權'與此日誌記錄:「 - >用戶對象不可用。身份驗證不成功。」

在包含SAML選項identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'中的identifierFormat後,我能夠將SAML響應作爲兩種情況的成功。但是,對於OpenIDP,我可以在saml:AttributeStatement內看到像uid,givenName等的值,作爲saml:AttributeStatement的一部分。但是,在VM + ADFS的情況下,我只看到EncryptedAssertion。看起來我需要從IDP安裝一些密鑰,並將其用作SAML選項的一部分。

任何幫助在這裏將不勝感激。

+0

編輯添加更多與identifierFormat:'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'相關的細節。 – Nikki

回答

0

SAML通常按照Passport-saml readme.md使用SHA-1。

此外,還有一個ADFS令牌簽名證書,根據頁面和Tim Brody鏈接的文章。

ADFS如何配置?

ADFS事件日誌中是否有任何事件?

如果您使用Firefox SAML示蹤劑,您是否收到回覆?

+0

我沒有ADFS配置的具體細節,但我現在能夠獲得認證。仍然用戶配置文件的詳細信息不可用。 ADFS日誌說認證成功。 SAML示蹤器顯示響應,但它是'EncryptedAssertion'。我想我需要從IDP(ADFS)安裝公鑰或證書。 – Nikki

+0

否 - 如果它已加密,則應擁有該證書。有人必須在ADFS中配置證書。 – nzpcmad

+0

謝謝@nzpcmad。您是對的:它使用sudo openssl req -x509 -newkey rsa:2048 -keyout app-key.pem -out app-cert.pem -days 3650'在託管應用程序的計算機上生成。 'app-cert.pem'提供給ADFS團隊。 'app-key.pem'作爲saml選項中'cert'的值讀入。不知道爲什麼我仍然無法獲取用戶個人資料。還有其他建議嗎?謝謝。 – Nikki

相關問題