Add sudo-mode 'confirm password' prompt

This commit is contained in:
Shane Kilkelly 2017-05-10 10:05:48 +01:00
parent 91f06cfc28
commit 029c96c7cc
4 changed files with 128 additions and 0 deletions

View file

@ -0,0 +1,58 @@
UserLocator = require "../User/UserLocator"
Settings = require "settings-sharelatex"
logger = require 'logger-sharelatex'
SudoModeHandler = require './SudoModeHandler'
AuthenticationController = require '../Authentication/AuthenticationController'
AuthenticationManager = require '../Authentication/AuthenticationManager'
ObjectId = require('../../infrastructure/Mongoose').mongo.ObjectId
UserGetter = require '../User/UserGetter'
module.exports = SudoModeController =
sudoModePrompt: (req, res, next) ->
userId = AuthenticationController.getLoggedInUserId(req)
logger.log {userId}, "[SudoMode] rendering sudo mode password page"
SudoModeHandler.isSudoModeActive userId, (err, isActive) ->
if err?
logger.err {err, userId}, "[SudoMode] error checking if sudo mode is active"
return next(err)
if isActive
logger.log {userId}, "[SudoMode] sudo mode already active, redirecting"
return res.redirect('/project')
res.render 'sudo_mode/sudo_mode_prompt', title: 'confirm_your_password'
submitPassword: (req, res, next) ->
userId = AuthenticationController.getLoggedInUserId(req)
redir = AuthenticationController._getRedirectFromSession(req) || "/project"
password = req.body.password
if !password
logger.log {userId}, "[SudoMode] no password supplied, failed authentication"
return next(new Error('no password supplied'))
logger.log {userId, redir}, "[SudoMode] checking user password"
UserGetter.getUser ObjectId(userId), {email: 1}, (err, userRecord) ->
if err?
logger.err {err, userId}, "[SudoMode] error getting user"
return next(err)
AuthenticationManager.authenticate email: userRecord.email, password, (err, user) ->
if err?
logger.err {err, userId}, "[SudoMode] error authenticating user"
return next(err)
if user?
logger.log {userId}, "[SudoMode] authenticated user, activating sudo mode"
SudoModeHandler.activateSudoMode userId, (err) ->
if err?
logger.err {err, userId}, "[SudoMode] error activating sudo mode"
return next(err)
return res.json {
redir: redir
}
else
logger.log {userId}, "[SudoMode] authentication failed for user"
return res.json {
message: {
text: req.i18n.translate("invalid_password"),
type: 'error'
}
}

View file

@ -0,0 +1,27 @@
RedisWrapper = require('../../infrastructure/RedisWrapper')
rclient = RedisWrapper.client('sudomode')
logger = require('logger-sharelatex')
TIMEOUT_IN_SECONDS = 60 * 10
module.exports = SudoModeHandler =
_buildKey: (userId) ->
"SudoMode:{#{userId}}"
activateSudoMode: (userId, callback=(err)->) ->
if !userId?
return callback(new Error('[SudoMode] user must not be supplied'))
duration = TIMEOUT_IN_SECONDS
logger.log {userId, duration}, "[SudoMode] activating sudo mode for user"
rclient.set SudoModeHandler._buildKey(userId), '1', 'EX', duration, callback
isSudoModeActive: (userId, callback=(err, isActive)->) ->
if !userId?
return callback(new Error('[SudoMode] user must not be supplied'))
rclient.get SudoModeHandler._buildKey(userId), (err, result) ->
if err?
return callback(err)
callback(null, result == '1')

View file

@ -38,6 +38,7 @@ ContactRouter = require("./Features/Contacts/ContactRouter")
ReferencesController = require('./Features/References/ReferencesController') ReferencesController = require('./Features/References/ReferencesController')
AuthorizationMiddlewear = require('./Features/Authorization/AuthorizationMiddlewear') AuthorizationMiddlewear = require('./Features/Authorization/AuthorizationMiddlewear')
BetaProgramController = require('./Features/BetaProgram/BetaProgramController') BetaProgramController = require('./Features/BetaProgram/BetaProgramController')
SudoModeController = require('./Features/SudoMode/SudoModeController')
AnalyticsRouter = require('./Features/Analytics/AnalyticsRouter') AnalyticsRouter = require('./Features/Analytics/AnalyticsRouter')
AnnouncementsController = require("./Features/Announcements/AnnouncementsController") AnnouncementsController = require("./Features/Announcements/AnnouncementsController")
@ -238,6 +239,9 @@ module.exports = class Router
webRouter.get "/beta/participate", AuthenticationController.requireLogin(), BetaProgramController.optInPage webRouter.get "/beta/participate", AuthenticationController.requireLogin(), BetaProgramController.optInPage
webRouter.post "/beta/opt-in", AuthenticationController.requireLogin(), BetaProgramController.optIn webRouter.post "/beta/opt-in", AuthenticationController.requireLogin(), BetaProgramController.optIn
webRouter.post "/beta/opt-out", AuthenticationController.requireLogin(), BetaProgramController.optOut webRouter.post "/beta/opt-out", AuthenticationController.requireLogin(), BetaProgramController.optOut
webRouter.get "/confirm-password", AuthenticationController.requireLogin(), SudoModeController.sudoModePrompt
webRouter.post "/confirm-password/submit", AuthenticationController.requireLogin(), SudoModeController.submitPassword
#Admin Stuff #Admin Stuff
webRouter.get '/admin', AuthorizationMiddlewear.ensureUserIsSiteAdmin, AdminController.index webRouter.get '/admin', AuthorizationMiddlewear.ensureUserIsSiteAdmin, AdminController.index

View file

@ -0,0 +1,39 @@
extends ../layout
block content
.content.content-alt
.container
.row
.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
.card
.page-header.text-centered
h1 Confirm your password to continue
div
.container-fluid
.row
.col-md-8.col-md-offset-2
form(async-form="confirmPassword", name="confirmPassword",
action='/confirm-password/submit', method="POST", ng-cloak)
input(name='_csrf', type='hidden', value=csrfToken)
form-messages(for="confirmPassword")
.form-group
label
| #{translate('password')}
input.form-control(
type='password',
name='password',
required,
placeholder='********',
ng-model="password"
)
span.small.text-primary(
ng-show="confirmPassword.password.$invalid && confirmPassword.password.$dirty"
)
| #{translate("required")}
.actions
button.btn-primary.btn(
style="width: 100%",
type='submit',
ng-disabled="confirmPassword.inflight"
)
span #{translate("confirm")}