@openiap/nodebb-plugin-sso-oidc
Version:
NodeBB Plugin that allows users to login/register via their OpenID Connect account.
290 lines (254 loc) • 8.39 kB
JavaScript
(function (module) {
'use strict';
var user = require.main.require('./src/user'),
meta = require.main.require('./src/meta'),
db = require.main.require('./src/database'),
passport = require.main.require('passport'),
passportOpenID = require('passport-openidconnect').Strategy,
passportLocal = require.main.require('passport-local').Strategy,
controllers = require.main.require("./src/controllers"),
nconf = require.main.require('nconf'),
winston = require.main.require('winston');
var authenticationController = require.main.require('./src/controllers/authentication');
var constants = Object.freeze({
'name': 'OIDC',
'admin': {
'route': '/plugins/sso-oidc',
'icon': 'fa-openid'
}
});
var Oidc = {
settings: undefined
};
/**
* Initializes the plugin
*
* @param {Object} data
* @param {Function} callback
*/
Oidc.init = function(params, callback) {
winston.info('Setting up OpenID Connect UI routes...');
var hostHelpers = require.main.require('./src/routes/helpers');
function render(req, res, next) {
res.render('admin/plugins/sso-oidc', {
baseUrl: nconf.get('url'),
});
}
params.router.get('/admin/plugins/sso-oidc', params.middleware.admin.buildHeader, render);
params.router.get('/api/admin/plugins/sso-oidc', render);
hostHelpers.setupPageRoute(params.router, '/deauth/oidc', params.middleware, [params.middleware.requireUser], function (req, res) {
res.render('plugins/sso-oidc/deauth', {
service: "OIDC",
});
});
/*
params.router.post('/deauth/oidc', [params.middleware.requireUser, params.middleware.applyCSRF], function (req, res, next) {
Oidc.deleteUserData({
uid: req.user.uid,
}, function (err) {
if (err) {
return next(err);
}
res.redirect(nconf.get('relative_path') + '/me/edit');
});
});
*/
meta.settings.get('sso-oidc', function (err, settings) {
Oidc.settings = settings;
callback();
});
};
/**
* Creates the Passport Strategy to login with OpenID Connect.
*
* @param {Array} strategies
* @param {Function} callback
*/
Oidc.getStrategy = function (strategies, callback) {
winston.info('Setting up openid strategy');
if (Oidc.settings !== undefined &&
Oidc.settings.client_id && Oidc.settings.client_secret &&
Oidc.settings.base_url && Oidc.settings.login_authorize &&
Oidc.settings.token && Oidc.settings.user_info) {
var baseurl = nconf.get('url');
passport.use(new passportOpenID({
issuer: Oidc.settings.base_url,
authorizationURL: Oidc.settings.login_authorize,
tokenURL: Oidc.settings.token,
userInfoURL: Oidc.settings.user_info,
clientID: Oidc.settings.client_id,
clientSecret: Oidc.settings.client_secret,
callbackURL: baseurl + '/auth/oidc/callback',
scope: 'openid email profile',
passReqToCallback: true,
}, function (req, iss, sub, profile, accessToken, refreshToken, verified) {
if (req.hasOwnProperty('user') && req.user.hasOwnProperty('uid') && req.user.uid > 0) {
// Save specific information to the user
User.setUserField(req.user.uid, 'oidcid', profile.id);
db.setObjectField('oidcid:uid', profile.id, req.user.uid);
return verified(null, req.user);
}
Oidc.login(profile.id, profile._json.user_name, profile._json.email, function (err, user) {
if (err) {
return verified(err);
}
authenticationController.onSuccessfulLogin(req, user.uid);
verified(null, user);
});
}));
// if(Oidc.settings.local_login === 'off') {
strategies.push({
name: 'openidconnect',
url: '/auth/oidc',
callbackURL: '/auth/oidc/callback',
icon: constants.admin.icon,
checkState: false
});
// }
}
callback(null, strategies);
};
/**
* Logins a user.
*
* @param {String} oidcid
* @param {String} username
* @param {String} email
* @param {Function} callback
*/
Oidc.login = function (oidcid, username, email, callback) {
Oidc.getUidByOidc(oidcid, function (err, uid) {
if (err) {
return callback(err);
}
if (uid !== null) {
// Existing user
callback(null, {
uid: uid
});
} else {
// New User
var success = function (uid) {
// Save specific information to the user
user.setUserField(uid, 'oidcid', oidcid);
db.setObjectField('oidcid:uid', oidcid, uid);
callback(null, {
uid: uid
});
};
user.getUidByEmail(email, function (err, uid) {
if (err) {
return callback(err);
}
if (!uid) {
if (!username) username = email;
if (username && username.indexOf('@') > -1) {
username = username.split('@');
} else if (username && username.indexOf(' ') > -1) {
username = username.split(' ');
}
user.create({ username: username[0], email: email }, function (err, uid) {
if (err) {
return callback(err);
}
success(uid);
});
} else {
success(uid);
}
});
}
});
};
/**
* If the local_login setting is on, this creates the login
* strategy as the Local Login.
*/
// Oidc.localLogin = function() {
// if(Oidc.settings.local_login === 'on') {
// winston.info('[login] Registering new local login strategy');
// passport.use(new passportLocal({passReqToCallback: true}, function (req, iss, sub, profile, accessToken, refreshToken, verified) {
// if (req.hasOwnProperty('user') && req.user.hasOwnProperty('uid') && req.user.uid > 0) {
// // Save specific information to the user
// User.setUserField(req.user.uid, 'oidcid', profile.id);
// db.setObjectField('oidcid:uid', profile.id, req.user.uid);
// return verified(null, req.user);
// }
// Oidc.login(profile.id, profile._json.user_name, profile._json.email, function (err, user) {
// if (err) {
// return verified(err);
// }
// authenticationController.onSuccessfulLogin(req, user.uid);
// verified(null, user);
// });
// }));
// } else {
// passport.use(new passportLocal({ passReqToCallback: true }, controllers.authentication.localLogin));
// }
// };
/**
* Adds the login vía OpenID and the Icon.
*
* @param {Array} custom_header
* @param {Function} callback
*/
Oidc.addMenuItem = function(custom_header, callback) {
custom_header.authentication.push({
'route': constants.admin.route,
'icon': constants.admin.icon,
'name': constants.name
});
callback(null, custom_header);
};
/**
* Gets the User's Uid in NodeBB by its Oidc.
*
* @param {String} oidcid
* @param {Function} callback
*/
Oidc.getUidByOidc = function (oidcid, callback) {
db.getObjectField('oidcid:uid', oidcid, function (err, uid) {
if (err) {
return callback(err);
}
callback(null, uid);
});
};
/**
* Enables nested replies
*
* @param {Object} config
* @param {Function} callback
*/
Oidc.enableNestedReplies = function (config, callback) {
config.showNestedReplies = true;
setImmediate(callback, null, config);
}
/**
* Deletes the User's data.
*
* @param {Object} data
* @param {Function} callback
*/
/*
Oidc.deleteUserData = function (data, callback) {
var uid = data.uid;
async.waterfall([
async.apply(User.getUserField, uid, 'gplusid'),
function (oAuthIdToDelete, next) {
db.deleteObjectField('gplusid:uid', oAuthIdToDelete, next);
},
function (next) {
db.deleteObjectField('user:' + uid, 'gplusid', next);
},
], function (err) {
if (err) {
winston.error('[sso-google] Could not remove OAuthId data for uid ' + uid + '. Error: ' + err);
return callback(err);
}
callback(null, uid);
});
};
*/
module.exports = Oidc;
}(module));