From e4f432515099a15df00df4aeeca39cbc4482cdf7 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Fri, 2 Sep 2016 16:17:37 +0100 Subject: [PATCH] Basic passport integration --- .../AuthenticationController.coffee | 48 +++++++++++++++++++ .../Features/Project/ProjectController.coffee | 8 ++-- .../Features/User/UserController.coffee | 1 + .../app/coffee/infrastructure/Server.coffee | 20 ++++++++ services/web/app/coffee/router.coffee | 10 ++-- services/web/package.json | 2 + 6 files changed, 82 insertions(+), 7 deletions(-) diff --git a/services/web/app/coffee/Features/Authentication/AuthenticationController.coffee b/services/web/app/coffee/Features/Authentication/AuthenticationController.coffee index 4972144737..a31d0eb45e 100644 --- a/services/web/app/coffee/Features/Authentication/AuthenticationController.coffee +++ b/services/web/app/coffee/Features/Authentication/AuthenticationController.coffee @@ -16,6 +16,54 @@ module.exports = AuthenticationController = login: (req, res, next = (error) ->) -> AuthenticationController.doLogin req.body, req, res, next + serializeUser: (user, callback) -> + console.log ">> serialize", user._id + lightUser = + _id: user._id + first_name: user.first_name + last_name: user.last_name + isAdmin: user.isAdmin + email: user.email + referal_id: user.referal_id + session_created: (new Date()).toISOString() + ip_address: user._login_req_ip + callback(null, lightUser) + + deserializeUser: (user, cb) -> + console.log ">> de-serialize", user._id + cb(null, user) + + doPassportLogin: (req, username, password, done) -> + email = username.toLowerCase() + redir = Url.parse(req?.body?.redir or "/project").path + console.log ">> doing passport login", username, password, redir + LoginRateLimiter.processLoginRequest email, (err, isAllowed)-> + return done(err) if err? + if !isAllowed + logger.log email:email, "too many login requests" + return done(null, null, {message: req.i18n.translate("to_many_login_requests_2_mins"), type: 'error'}) + AuthenticationManager.authenticate email: email, password, (error, user) -> + return done(error) if error? + if user? + # async actions + UserHandler.setupLoginData(user, ()->) + LoginRateLimiter.recordSuccessfulLogin(email) + AuthenticationController._recordSuccessfulLogin(user._id) + Analytics.recordEvent(user._id, "user-logged-in") + UserSessionsManager.trackSession(user, req.sessionID, () ->) + req.session.justLoggedIn = true + logger.log email: email, user_id: user._id.toString(), "successful log in" + # capture the request ip for use when creating the session + user._login_req_ip = req.ip + req._redir = redir + console.log ">> done, returning user" + return done(null, user) + else + AuthenticationController._recordFailedLogin() + logger.log email: email, "failed log in" + return done(null, false, {message: req.i18n.translate("email_or_password_wrong_try_again"), type: 'error'}) + + doLogin: (options, req, res, next) -> email = options.email?.toLowerCase() password = options.password diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index d273516056..d28b5ca868 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -45,10 +45,10 @@ module.exports = ProjectController = async.series jobs, (error) -> return next(error) if error? res.sendStatus(204) - + updateProjectAdminSettings: (req, res, next) -> project_id = req.params.Project_id - + jobs = [] if req.body.publicAccessLevel? jobs.push (callback) -> @@ -149,7 +149,7 @@ module.exports = ProjectController = return next(err) logger.log results:results, user_id:user_id, "rendering project list" tags = results.tags[0] - notifications = require("underscore").map results.notifications, (notification)-> + notifications = require("underscore").map results.notifications, (notification)-> notification.html = req.i18n.translate(notification.templateKey, notification.messageOpts) return notification projects = ProjectController._buildProjectList results.projects[0], results.projects[1], results.projects[2] @@ -332,4 +332,4 @@ do generateThemeList = () -> for file in files if file.slice(-2) == "js" and file.match(/^theme-/) cleanName = file.slice(0,-3).slice(6) - THEME_LIST.push cleanName \ No newline at end of file + THEME_LIST.push cleanName diff --git a/services/web/app/coffee/Features/User/UserController.coffee b/services/web/app/coffee/Features/User/UserController.coffee index 546cea035e..25eb2afd4c 100644 --- a/services/web/app/coffee/Features/User/UserController.coffee +++ b/services/web/app/coffee/Features/User/UserController.coffee @@ -84,6 +84,7 @@ module.exports = UserController = logger.log user: req?.session?.user, "logging out" sessionId = req.sessionID user = req?.session?.user + req.logout?() # passport logout req.session.destroy (err)-> if err logger.err err: err, 'error destorying session' diff --git a/services/web/app/coffee/infrastructure/Server.coffee b/services/web/app/coffee/infrastructure/Server.coffee index 8ac543c698..49f272a821 100644 --- a/services/web/app/coffee/infrastructure/Server.coffee +++ b/services/web/app/coffee/infrastructure/Server.coffee @@ -21,6 +21,9 @@ cookieParser = require('cookie-parser') sessionStore = new RedisStore(client:rclient) +passport = require('passport') +LocalStrategy = require('passport-local').Strategy + Mongoose = require("./Mongoose") oneDayInMilliseconds = 86400000 @@ -32,6 +35,7 @@ Modules = require "./Modules" ErrorController = require "../Features/Errors/ErrorController" UserSessionsManager = require "../Features/User/UserSessionsManager" +AuthenticationController = require "../Features/Authentication/AuthenticationController" metrics.mongodb.monitor(Path.resolve(__dirname + "/../../../node_modules/mongojs/node_modules/mongodb"), logger) metrics.mongodb.monitor(Path.resolve(__dirname + "/../../../node_modules/mongoose/node_modules/mongodb"), logger) @@ -87,6 +91,22 @@ webRouter.use csrfProtection webRouter.use translations.expressMiddlewear webRouter.use translations.setLangBasedOnDomainMiddlewear +# passport +webRouter.use passport.initialize() +webRouter.use passport.session() + +passport.use(new LocalStrategy( + { + passReqToCallback: true, + usernameField: 'email', + passwordField: 'password' + }, + AuthenticationController.doPassportLogin +)) +passport.serializeUser(AuthenticationController.serializeUser) +passport.deserializeUser(AuthenticationController.deserializeUser) + + # Measure expiry from last request, not last login webRouter.use (req, res, next) -> req.session.touch() diff --git a/services/web/app/coffee/router.coffee b/services/web/app/coffee/router.coffee index e6de2e7183..adf45bc36a 100644 --- a/services/web/app/coffee/router.coffee +++ b/services/web/app/coffee/router.coffee @@ -43,6 +43,7 @@ AnalyticsRouter = require('./Features/Analytics/AnalyticsRouter') logger = require("logger-sharelatex") _ = require("underscore") +passport = require('passport') module.exports = class Router constructor: (webRouter, apiRouter)-> @@ -53,7 +54,10 @@ module.exports = class Router webRouter.get '/login', UserPagesController.loginPage AuthenticationController.addEndpointToLoginWhitelist '/login' - webRouter.post '/login', AuthenticationController.login + # webRouter.post '/login', AuthenticationController.login + webRouter.post '/login', passport.authenticate('local'), AuthenticationController.login, (req, res) -> + console.log ">> login done", req._redir + res.json {redir: req._redir} webRouter.get '/logout', UserController.logout webRouter.get '/restricted', AuthorizationMiddlewear.restricted @@ -71,7 +75,7 @@ module.exports = class Router RealTimeProxyRouter.apply(webRouter, apiRouter) ContactRouter.apply(webRouter, apiRouter) AnalyticsRouter.apply(webRouter, apiRouter) - + Modules.applyRouter(webRouter, apiRouter) @@ -182,7 +186,7 @@ module.exports = class Router webRouter.delete '/tag/:tag_id/project/:project_id', AuthenticationController.requireLogin(), TagsController.removeProjectFromTag webRouter.get '/notifications', AuthenticationController.requireLogin(), NotificationsController.getAllUnreadNotifications - webRouter.delete '/notifications/:notification_id', AuthenticationController.requireLogin(), NotificationsController.markNotificationAsRead + webRouter.delete '/notifications/:notification_id', AuthenticationController.requireLogin(), NotificationsController.markNotificationAsRead # Deprecated in favour of /internal/project/:project_id but still used by versioning apiRouter.get '/project/:project_id/details', AuthenticationController.httpAuth, ProjectApiController.getProjectDetails diff --git a/services/web/package.json b/services/web/package.json index 83381005f0..449039dcd2 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -46,6 +46,8 @@ "nodemailer-sendgrid-transport": "^0.2.0", "nodemailer-ses-transport": "^1.3.0", "optimist": "0.6.1", + "passport": "^0.3.2", + "passport-local": "^1.0.0", "pg": "^6.0.3", "pg-hstore": "^2.3.2", "redback": "0.4.0",