From 69a9f7ca38875dc110697960a8f9db5ac2bcd97c Mon Sep 17 00:00:00 2001 From: BoHong Li Date: Wed, 12 Apr 2017 05:41:14 +0800 Subject: refactor(app.js, auth.js): Extract all auth method to individual modules --- lib/web/auth/dropbox/index.js | 29 +++++++++++++++++ lib/web/auth/email/index.js | 74 ++++++++++++++++++++++++++++++++++++++++++ lib/web/auth/facebook/index.js | 29 +++++++++++++++++ lib/web/auth/github/index.js | 28 ++++++++++++++++ lib/web/auth/gitlab/index.js | 36 ++++++++++++++++++++ lib/web/auth/google/index.js | 27 +++++++++++++++ lib/web/auth/index.js | 26 +++++++++++++++ lib/web/auth/ldap/index.js | 74 ++++++++++++++++++++++++++++++++++++++++++ lib/web/auth/twitter/index.js | 29 +++++++++++++++++ lib/web/auth/utils.js | 53 ++++++++++++++++++++++++++++++ 10 files changed, 405 insertions(+) create mode 100644 lib/web/auth/dropbox/index.js create mode 100644 lib/web/auth/email/index.js create mode 100644 lib/web/auth/facebook/index.js create mode 100644 lib/web/auth/github/index.js create mode 100644 lib/web/auth/gitlab/index.js create mode 100644 lib/web/auth/google/index.js create mode 100644 lib/web/auth/index.js create mode 100644 lib/web/auth/ldap/index.js create mode 100644 lib/web/auth/twitter/index.js create mode 100644 lib/web/auth/utils.js (limited to 'lib/web/auth') diff --git a/lib/web/auth/dropbox/index.js b/lib/web/auth/dropbox/index.js new file mode 100644 index 00000000..c03fbc57 --- /dev/null +++ b/lib/web/auth/dropbox/index.js @@ -0,0 +1,29 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const DropboxStrategy = require('passport-dropbox-oauth2').Strategy +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let dropboxAuth = module.exports = Router() + +passport.use(new DropboxStrategy({ + apiVersion: '2', + clientID: config.dropbox.clientID, + clientSecret: config.dropbox.clientSecret, + callbackURL: config.serverurl + '/auth/dropbox/callback' +}, passportGeneralCallback)) + +dropboxAuth.get('/auth/dropbox', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('dropbox-oauth2')(req, res, next) +}) + +// dropbox auth callback +dropboxAuth.get('/auth/dropbox/callback', + passport.authenticate('dropbox-oauth2', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/email/index.js b/lib/web/auth/email/index.js new file mode 100644 index 00000000..760075f8 --- /dev/null +++ b/lib/web/auth/email/index.js @@ -0,0 +1,74 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const validator = require('validator') +const LocalStrategy = require('passport-local').Strategy +const config = require('../../../config') +const models = require('../../../models') +const logger = require('../../../logger') +const {setReturnToFromReferer} = require('../utils') +const {urlencodedParser} = require('../../utils') +const response = require('../../../response') + +let emailAuth = module.exports = Router() + +passport.use(new LocalStrategy({ + usernameField: 'email' +}, function (email, password, done) { + if (!validator.isEmail(email)) return done(null, false) + models.User.findOne({ + where: { + email: email + } + }).then(function (user) { + if (!user) return done(null, false) + if (!user.verifyPassword(password)) return done(null, false) + return done(null, user) + }).catch(function (err) { + logger.error(err) + return done(err) + }) +})) + +if (config.allowemailregister) { + emailAuth.post('/register', urlencodedParser, function (req, res, next) { + if (!req.body.email || !req.body.password) return response.errorBadRequest(res) + if (!validator.isEmail(req.body.email)) return response.errorBadRequest(res) + models.User.findOrCreate({ + where: { + email: req.body.email + }, + defaults: { + password: req.body.password + } + }).spread(function (user, created) { + if (user) { + if (created) { + logger.debug('user registered: ' + user.id) + req.flash('info', "You've successfully registered, please signin.") + } else { + logger.debug('user found: ' + user.id) + req.flash('error', 'This email has been used, please try another one.') + } + return res.redirect(config.serverurl + '/') + } + req.flash('error', 'Failed to register your account, please try again.') + return res.redirect(config.serverurl + '/') + }).catch(function (err) { + logger.error('auth callback failed: ' + err) + return response.errorInternalError(res) + }) + }) +} + +emailAuth.post('/login', urlencodedParser, function (req, res, next) { + if (!req.body.email || !req.body.password) return response.errorBadRequest(res) + if (!validator.isEmail(req.body.email)) return response.errorBadRequest(res) + setReturnToFromReferer(req) + passport.authenticate('local', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/', + failureFlash: 'Invalid email or password.' + })(req, res, next) +}) diff --git a/lib/web/auth/facebook/index.js b/lib/web/auth/facebook/index.js new file mode 100644 index 00000000..0e5474d8 --- /dev/null +++ b/lib/web/auth/facebook/index.js @@ -0,0 +1,29 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const FacebookStrategy = require('passport-facebook').Strategy + +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let facebookAuth = module.exports = Router() + +passport.use(new FacebookStrategy({ + clientID: config.facebook.clientID, + clientSecret: config.facebook.clientSecret, + callbackURL: config.serverurl + '/auth/facebook/callback' +}, passportGeneralCallback)) + +facebookAuth.get('/auth/facebook', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('facebook')(req, res, next) +}) + +// facebook auth callback +facebookAuth.get('/auth/facebook/callback', + passport.authenticate('facebook', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/github/index.js b/lib/web/auth/github/index.js new file mode 100644 index 00000000..2a26669c --- /dev/null +++ b/lib/web/auth/github/index.js @@ -0,0 +1,28 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const GithubStrategy = require('passport-github').Strategy +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let githubAuth = module.exports = Router() + +passport.use(new GithubStrategy({ + clientID: config.github.clientID, + clientSecret: config.github.clientSecret, + callbackURL: config.serverurl + '/auth/github/callback' +}, passportGeneralCallback)) + +githubAuth.get('/auth/github', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('github')(req, res, next) +}) + +// github auth callback +githubAuth.get('/auth/github/callback', + passport.authenticate('github', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/gitlab/index.js b/lib/web/auth/gitlab/index.js new file mode 100644 index 00000000..51de1602 --- /dev/null +++ b/lib/web/auth/gitlab/index.js @@ -0,0 +1,36 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const GitlabStrategy = require('passport-gitlab2').Strategy +const config = require('../../../config') +const response = require('../../../response') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let gitlabAuth = module.exports = Router() + +passport.use(new GitlabStrategy({ + baseURL: config.gitlab.baseURL, + clientID: config.gitlab.clientID, + clientSecret: config.gitlab.clientSecret, + scope: config.gitlab.scope, + callbackURL: config.serverurl + '/auth/gitlab/callback' +}, passportGeneralCallback)) + +gitlabAuth.get('/auth/gitlab', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('gitlab')(req, res, next) +}) + +// gitlab auth callback +gitlabAuth.get('/auth/gitlab/callback', + passport.authenticate('gitlab', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) + +if (!config.gitlab.scope || config.gitlab.scope === 'api') { + // gitlab callback actions + gitlabAuth.get('/auth/gitlab/callback/:noteId/:action', response.gitlabActions) +} diff --git a/lib/web/auth/google/index.js b/lib/web/auth/google/index.js new file mode 100644 index 00000000..bf2a260f --- /dev/null +++ b/lib/web/auth/google/index.js @@ -0,0 +1,27 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +var GoogleStrategy = require('passport-google-oauth20').Strategy +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let facebookAuth = module.exports = Router() + +passport.use(new GoogleStrategy({ + clientID: config.google.clientID, + clientSecret: config.google.clientSecret, + callbackURL: config.serverurl + '/auth/google/callback' +}, passportGeneralCallback)) + +facebookAuth.get('/auth/google', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('google', { scope: ['profile'] })(req, res, next) +}) + // google auth callback +facebookAuth.get('/auth/google/callback', + passport.authenticate('google', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/index.js b/lib/web/auth/index.js new file mode 100644 index 00000000..3a203800 --- /dev/null +++ b/lib/web/auth/index.js @@ -0,0 +1,26 @@ +'use strict' + +const Router = require('express').Router + +const config = require('../../config') +const logger = require('../../logger') + +const authRouter = module.exports = Router() + +if (config.facebook) authRouter.use('/', require('./facebook')) +if (config.twitter) authRouter.use('/', require('./twitter')) +if (config.github) authRouter.use('/', require('./github')) +if (config.gitlab) authRouter.use('/', require('./gitlab')) +if (config.dropbox) authRouter.use('/', require('./dropbox')) +if (config.google) authRouter.use('/', require('./google')) +if (config.ldap) authRouter.use('/', require('./ldap')) +if (config.email) authRouter.use('/', require('./email')) + +// logout +authRouter.get('/logout', function (req, res) { + if (config.debug && req.isAuthenticated()) { + logger.debug('user logout: ' + req.user.id) + } + req.logout() + res.redirect(config.serverurl + '/') +}) diff --git a/lib/web/auth/ldap/index.js b/lib/web/auth/ldap/index.js new file mode 100644 index 00000000..766c5cbc --- /dev/null +++ b/lib/web/auth/ldap/index.js @@ -0,0 +1,74 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const LDAPStrategy = require('passport-ldapauth') +const config = require('../../../config') +const models = require('../../../models') +const logger = require('../../../logger') +const {setReturnToFromReferer} = require('../utils') +const {urlencodedParser} = require('../../utils') +const response = require('../../../response') + +let ldapAuth = module.exports = Router() + +passport.use(new LDAPStrategy({ + server: { + url: config.ldap.url || null, + bindDn: config.ldap.bindDn || null, + bindCredentials: config.ldap.bindCredentials || null, + searchBase: config.ldap.searchBase || null, + searchFilter: config.ldap.searchFilter || null, + searchAttributes: config.ldap.searchAttributes || null, + tlsOptions: config.ldap.tlsOptions || null + } +}, function (user, done) { + var profile = { + id: 'LDAP-' + user.uidNumber, + username: user.uid, + displayName: user.displayName, + emails: user.mail ? [user.mail] : [], + avatarUrl: null, + profileUrl: null, + provider: 'ldap' + } + var stringifiedProfile = JSON.stringify(profile) + models.User.findOrCreate({ + where: { + profileid: profile.id.toString() + }, + defaults: { + profile: stringifiedProfile + } + }).spread(function (user, created) { + if (user) { + var needSave = false + if (user.profile !== stringifiedProfile) { + user.profile = stringifiedProfile + needSave = true + } + if (needSave) { + user.save().then(function () { + if (config.debug) { logger.debug('user login: ' + user.id) } + return done(null, user) + }) + } else { + if (config.debug) { logger.debug('user login: ' + user.id) } + return done(null, user) + } + } + }).catch(function (err) { + logger.error('ldap auth failed: ' + err) + return done(err, null) + }) +})) + +ldapAuth.post('/auth/ldap', urlencodedParser, function (req, res, next) { + if (!req.body.username || !req.body.password) return response.errorBadRequest(res) + setReturnToFromReferer(req) + passport.authenticate('ldapauth', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/', + failureFlash: true + })(req, res, next) +}) diff --git a/lib/web/auth/twitter/index.js b/lib/web/auth/twitter/index.js new file mode 100644 index 00000000..5429522d --- /dev/null +++ b/lib/web/auth/twitter/index.js @@ -0,0 +1,29 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const TwitterStrategy = require('passport-twitter').Strategy + +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let twitterAuth = module.exports = Router() + +passport.use(new TwitterStrategy({ + consumerKey: config.twitter.consumerKey, + consumerSecret: config.twitter.consumerSecret, + callbackURL: config.serverurl + '/auth/twitter/callback' +}, passportGeneralCallback)) + +twitterAuth.get('/auth/twitter', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('twitter')(req, res, next) +}) + +// twitter auth callback +twitterAuth.get('/auth/twitter/callback', + passport.authenticate('twitter', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/utils.js b/lib/web/auth/utils.js new file mode 100644 index 00000000..ff7a1237 --- /dev/null +++ b/lib/web/auth/utils.js @@ -0,0 +1,53 @@ +'use strict' + +const models = require('../../models') +const config = require('../../config') +const logger = require('../../logger') + +exports.setReturnToFromReferer = function setReturnToFromReferer (req) { + var referer = req.get('referer') + if (!req.session) req.session = {} + req.session.returnTo = referer +} + +exports.passportGeneralCallback = function callback (accessToken, refreshToken, profile, done) { + var stringifiedProfile = JSON.stringify(profile) + models.User.findOrCreate({ + where: { + profileid: profile.id.toString() + }, + defaults: { + profile: stringifiedProfile, + accessToken: accessToken, + refreshToken: refreshToken + } + }).spread(function (user, created) { + if (user) { + var needSave = false + if (user.profile !== stringifiedProfile) { + user.profile = stringifiedProfile + needSave = true + } + if (user.accessToken !== accessToken) { + user.accessToken = accessToken + needSave = true + } + if (user.refreshToken !== refreshToken) { + user.refreshToken = refreshToken + needSave = true + } + if (needSave) { + user.save().then(function () { + if (config.debug) { logger.info('user login: ' + user.id) } + return done(null, user) + }) + } else { + if (config.debug) { logger.info('user login: ' + user.id) } + return done(null, user) + } + } + }).catch(function (err) { + logger.error('auth callback failed: ' + err) + return done(err, null) + }) +} -- cgit v1.2.3 From d88502e3315f189af28ac6e86fccfa1406d75b52 Mon Sep 17 00:00:00 2001 From: BoHong Li Date: Wed, 12 Apr 2017 06:07:19 +0800 Subject: refactor(app.js): Move passport serialize and deserialize to auth module --- lib/web/auth/index.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'lib/web/auth') diff --git a/lib/web/auth/index.js b/lib/web/auth/index.js index 3a203800..18d70572 100644 --- a/lib/web/auth/index.js +++ b/lib/web/auth/index.js @@ -1,12 +1,34 @@ 'use strict' const Router = require('express').Router +const passport = require('passport') const config = require('../../config') const logger = require('../../logger') +const models = require('../../models') const authRouter = module.exports = Router() +// serialize and deserialize +passport.serializeUser(function (user, done) { + logger.info('serializeUser: ' + user.id) + return done(null, user.id) +}) + +passport.deserializeUser(function (id, done) { + models.User.findOne({ + where: { + id: id + } + }).then(function (user) { + logger.info('deserializeUser: ' + user.id) + return done(null, user) + }).catch(function (err) { + logger.error(err) + return done(err, null) + }) +}) + if (config.facebook) authRouter.use('/', require('./facebook')) if (config.twitter) authRouter.use('/', require('./twitter')) if (config.github) authRouter.use('/', require('./github')) -- cgit v1.2.3 From a7e3c4d535e15832b1fff5482582a4c644a00c26 Mon Sep 17 00:00:00 2001 From: BoHong Li Date: Wed, 12 Apr 2017 06:10:24 +0800 Subject: refactor(auth.js): Remove base path --- lib/web/auth/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib/web/auth') diff --git a/lib/web/auth/index.js b/lib/web/auth/index.js index 18d70572..8a4eb774 100644 --- a/lib/web/auth/index.js +++ b/lib/web/auth/index.js @@ -29,14 +29,14 @@ passport.deserializeUser(function (id, done) { }) }) -if (config.facebook) authRouter.use('/', require('./facebook')) -if (config.twitter) authRouter.use('/', require('./twitter')) -if (config.github) authRouter.use('/', require('./github')) -if (config.gitlab) authRouter.use('/', require('./gitlab')) -if (config.dropbox) authRouter.use('/', require('./dropbox')) -if (config.google) authRouter.use('/', require('./google')) -if (config.ldap) authRouter.use('/', require('./ldap')) -if (config.email) authRouter.use('/', require('./email')) +if (config.facebook) authRouter.use(require('./facebook')) +if (config.twitter) authRouter.use(require('./twitter')) +if (config.github) authRouter.use(require('./github')) +if (config.gitlab) authRouter.use(require('./gitlab')) +if (config.dropbox) authRouter.use(require('./dropbox')) +if (config.google) authRouter.use(require('./google')) +if (config.ldap) authRouter.use(require('./ldap')) +if (config.email) authRouter.use(require('./email')) // logout authRouter.get('/logout', function (req, res) { -- cgit v1.2.3 From ecb05336055a37ba8a03c119995cd37d96aad90d Mon Sep 17 00:00:00 2001 From: BoHong Li Date: Thu, 13 Apr 2017 01:57:55 +0800 Subject: refactor(config.js): Extract config file * Separate different config source to each files * Freeze config object --- lib/web/auth/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib/web/auth') diff --git a/lib/web/auth/index.js b/lib/web/auth/index.js index 8a4eb774..b5ca8434 100644 --- a/lib/web/auth/index.js +++ b/lib/web/auth/index.js @@ -29,14 +29,14 @@ passport.deserializeUser(function (id, done) { }) }) -if (config.facebook) authRouter.use(require('./facebook')) -if (config.twitter) authRouter.use(require('./twitter')) -if (config.github) authRouter.use(require('./github')) -if (config.gitlab) authRouter.use(require('./gitlab')) -if (config.dropbox) authRouter.use(require('./dropbox')) -if (config.google) authRouter.use(require('./google')) -if (config.ldap) authRouter.use(require('./ldap')) -if (config.email) authRouter.use(require('./email')) +if (config.isFacebookEnable) authRouter.use(require('./facebook')) +if (config.isTwitterEnable) authRouter.use(require('./twitter')) +if (config.isGitHubEnable) authRouter.use(require('./github')) +if (config.isGitLabEnable) authRouter.use(require('./gitlab')) +if (config.isDropboxEnable) authRouter.use(require('./dropbox')) +if (config.isGoogleEnable) authRouter.use(require('./google')) +if (config.isLDAPEnable) authRouter.use(require('./ldap')) +if (config.isEmailEnable) authRouter.use(require('./email')) // logout authRouter.get('/logout', function (req, res) { -- cgit v1.2.3