Express / Passport SAML身份验证重定向导致无限循环

时间:2018-10-19 19:00:49

标签: javascript passport.js saml adfs

尝试使用Passport-saml连接到ADFS。

SAML响应返回成功状态代码。

我们获得以下成功代码:

"<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status>"

但是我们的Passport IsAuthenicated总是生成错误的消息。

我在下面列出了用于此目的的所有文件,希望对您有所帮助。

server.js文件:

const express = require('express');
const http = require('http');
const path = require('path');
const passport = require('passport');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');

const session = require('express-session');
const errorhandler = require('errorhandler');

var env = process.env.NODE_ENV || 'development';

const config = require('./config/config')[env];

console.log('Using configuration', config);

require('./config/passport')(passport, config);

var app = express();

app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(cookieParser());
app.enable('trust proxy'); // add this line
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(session(
  {
    resave: true,
    saveUninitialized: true,
    secret: 'default',
    proxy: true // add this line
  }));
app.use(passport.initialize());
app.use(passport.session());
app.use(morgan('combined'));

function ensureAuthenticated(req, res, next) {
  if (//req.isAuthenticated()
	  true
	  ) { 
  console.log('req.isAuthenticated = ' + req.isAuthenticated());
  return next(); }
  else{
	console.log('req.isAuthenticated = ' + req.isAuthenticated());
    res.redirect('/login');
  }
}


app.set('port', config.app.port);

require('./config/routes')(app, config, passport);

//ensure that ensureAuthenticated is in the get function call before master build
//ie app.get('/*', ensureAuthenticated, (req, res)
app.use(express.static(path.join(__dirname, 'public')));
app.get('/*', ensureAuthenticated, (req, res) => {
      res.sendFile(path.join(__dirname, 'public/index.html'));
});

app.listen(app.get('port'), function () {
  console.log('Express server listening on port ' + app.get('port'));
});

routes.js

module.exports = function (app, config, passport) {

  app.get('/', function (req, res) {
      res.redirect('/home')
  });

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

  app.post('/',
    passport.authenticate(config.passport.strategy,
      {
        failureRedirect: '/',
        failureFlash: true
      }),
    function (req, res) {
      res.redirect('/');
    }
  );

  app.get('/logout', function (req, res) {
    req.logout();
    // TODO: invalidate session on IP
    res.redirect('https://redrectsite.com/?wa=signout1.0');
  });
  

};

config.js

module.exports = {
    development: {
      app: {
        name: 'Passport SAML strategy example',
        port: process.env.PORT || 80
      },
      passport: {
        strategy: 'saml',
        saml: {
          callbackUrl: process.env.SAML_CALLBACK_URL || 'https://oursite.com',
          entryPoint: process.env.SAML_ENTRY_POINT || 'https://oursite.com/adfs/ls/idpinitiatedsignon',
          issuer: process.env.SAML_ISSUER || 'https://oursite.com',
          identifierFormat: null,
		  signatureAlgorithm: 'sha256',
		  authnContext: 'http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows',
		  disableRequestedAuthnContext: true
          //cert: process.env.SAML_CERT || null
        }
      }
    }
  };

passport.js

const SamlStrategy = require('passport-saml').Strategy;

module.exports = function (passport, config) {

  passport.serializeUser(function (user, done) {
    done(null, user);
  });

  passport.deserializeUser(function (user, done) {
    done(null, user);
  });

  passport.use(new SamlStrategy(
    {
      callbackUrl: config.passport.saml.callbackUrl,
      entryPoint: config.passport.saml.entryPoint,
      issuer: config.passport.saml.issuer,
      cert: config.passport.saml.cert,
      identifierFormat: config.passport.saml.identifierFormat,
	  signatureAlgorithm: config.passport.saml.signatureAlgorithm,
	  authnContext: config.passport.saml.authnContext,
	  disableRequestedAuthnContext: config.passport.saml.disableRequestedAuthnContext

    },
    function (profile, done) {
      return done(null,
        {
          id: profile.uid,
          email: profile.email,
          displayName: profile.cn,
          firstName: profile.givenName,
          lastName: profile.sn
        });
    })
  );

};

1 个答案:

答案 0 :(得分:0)

我有一个类似的问题。如果您查看isAuthenticated()的功能,实际上只是在检查request.session对象内的属性。

https://github.com/jaredhanson/passport/blob/2327a36e7c005ccc7134ad157b2f258b57aa0912/lib/http/request.js#L86

req.isAuthenticated = function() {
  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }

  return (this[property]) ? true : false;
};

我不确定这是护照还是快速会话,但是一旦使用身份验证方法,用户对象将存储在request.session.passport.user中,因此,如果您愿意,可以直接验证它是否为非空而不是使用打包的isAuthenticated()方法,该方法似乎检查了错误的路径。

将我的代码更改为以下内容后,它开始工作。

if (_.get(req, 'session.passport.user', null)) {
    return next();
}

(破折号_.get用于简化对嵌套属性的null检查)