(function(module) { "use strict"; var user = module.parent.require('./user'), meta = module.parent.require('./meta'), db = module.parent.require('../src/database'), passport = module.parent.require('passport'), passportSAML = require('passport-saml').Strategy, fs = module.parent.require('fs'), path = module.parent.require('path'), nconf = module.parent.require('nconf'), async = module.parent.require('async'), winston = require('winston'); var constants = Object.freeze({ 'name': "SAML", 'admin': { 'route': '/plugins/sso-saml', 'icon': 'fa-university' } }); var master_config = {}; var SAML = {}; var samlObj; SAML.init = function(params, callback) { function render(req, res, next) { res.render('admin/plugins/sso-saml', {}); } params.router.get('/admin/plugins/sso-saml', params.middleware.admin.buildHeader, render); params.router.get('/api/admin/plugins/sso-saml', render); meta.settings.get('sso_saml', function(err, options) { console.log('[sso-saml] got options', options); master_config = options; }); samlObj = new passportSAML({ path: master_config.callback_path, entryPoint: master_config.idp_entry_point, issuer: master_config.issuer, callbackUrl: nconf.get('url') + master_config.callback_path, disableRequestedAuthnContext: true, identifierFormat: null }, function(profile, done) { console.log("[sso-saml] profile, ", profile); var user = { nameID: profile.nameID, nameIDFormat: profile.nameIDFormat, sn: profile['urn:oid:2.5.4.4'], // sn //sn: profile.sn, cn: profile['urn:oid:2.5.4.42'], // givenname //cn: profile.cn, //mail: profile.mail, //eduPersonAffiliation: profile.eduPersonAffiliation, email: profile.mail, //email: profile.email, username: profile['urn:oid:1.3.6.1.4.1.5923.1.1.1.2'], // eduPersonNickname //username: profile.eduPersonNickname }; SAML.login(user,function(err, user) { if (err) { return done(err); } done(null, user); }); } ); console.log("[sso-saml] samlObj", samlObj); if (samlObj){ if (master_config.metadata) { params.router.get(master_config.metadata, function(req, res) { if (master_config.server_crt){ var cert = fs.readFileSync(master_config.server_crt, 'utf-8'); res.header("Content-Type", "application/xml"); res.send(samlObj.generateServiceProviderMetadata(cert)) } else{ res.send("No servercrt specified. Please enter it at nodebb admin panel."); } }); } params.router.post(master_config.callback_path, passport.authenticate('saml'), function(req, res, next){ if (master_config.login_redirect_url){ res.redirect(master_config.login_redirect_url); } else{ res.redirect("/"); } } ); if (master_config.logout_url) { params.router.get(master_config.logout_url,function(req,res){ if (req.user && parseInt(req.user.uid, 10) > 0) { winston.info('[Auth] Session ' + req.sessionID + ' logout (uid: ' + req.user.uid + ')'); var ws = module.parent.require('./socket.io'); ws.logoutUser(req.user.uid); req.logout(); if (master_config.logout_redirect_url){ res.redirect(master_config.logout_redirect_url); } else{ res.redirect("/"); } } }); } } else { console.log("[sso-saml] Cannot create samlObj"); } console.log("[sso-saml] init done"); callback(); }; SAML.get_config = function(options, callback) { meta.settings.get('sso_saml', function(err, settings) { if (err) { return callback(null, options); } master_config = settings; options.sso_saml = settings; callback(null, options); }); }, SAML.getStrategy = function(strategies, callback) { if (samlObj){ passport.use(samlObj); strategies.push({ name: 'saml', url: '/auth/saml', callbackURL: master_config.callback_path, icon: constants.admin.icon, scope: '' }); } callback(null, strategies); }; SAML.login = function(userdata, callback) { SAML.getUidBySAMLId(userdata.username, function(err, uid) { if(err) { return callback(err); } if (uid !== null) { // Existing User callback(null, { uid: uid }); } else { console.log(userdata); // New User user.create({ username: userdata.username, email: userdata.email, fullname : userdata.first_name + " " + userdata.last_name }, function(err, uid) { if(err) { return callback(err); } user.setUserField(uid, 'samlid', userdata.username); db.setObjectField('samlid:uid', userdata.username, uid); callback(null, { uid: uid }); }); } }); }; SAML.getUidBySAMLId = function(samlid, callback) { db.getObjectField('samlid:uid', samlid, function(err, uid) { if (err) { return callback(err); } callback(null, uid); }); }; SAML.addMenuItem = function(custom_header, callback) { custom_header.authentication.push({ "route": constants.admin.route, "icon": constants.admin.icon, "name": constants.name }); callback(null, custom_header); }; SAML.deleteUserData = function(uid, callback) { async.waterfall([ async.apply(user.getUserField, uid, 'samlid'), function(idToDelete, next) { db.deleteObjectField('samlid:uid', idToDelete, next); } ], function(err) { if (err) { winston.error('[sso-saml] Could not remove user data for uid ' + uid + '. Error: ' + err); return callback(err); } callback(null, uid); }); }; module.exports = SAML; }(module));