Regenerate session on login, protect against session-fixation attack.

This commit is contained in:
Shane Kilkelly 2016-09-21 13:03:37 +01:00
parent bb71433727
commit dde5b7b830
2 changed files with 31 additions and 4 deletions

View file

@ -39,7 +39,19 @@ module.exports = AuthenticationController =
return next(err) return next(err)
if user # `user` is either a user object or false if user # `user` is either a user object or false
req.login user, (err) -> req.login user, (err) ->
res.json {redir: req._redir} # Regenerate the session to get a new sessionID (cookie value) to
# protect against session fixation attacks
oldSession = req.session
req.session.destroy()
req.sessionStore.generate(req)
for key, value of oldSession
req.session[key] = value
req.session.save (err) ->
if err?
logger.err {user_id: user._id}, "error saving regenerated session after login"
return next(err)
UserSessionsManager.trackSession(user, req.sessionID, () ->)
res.json {redir: req._redir}
else else
res.json message: info res.json message: info
)(req, res, next) )(req, res, next)
@ -60,9 +72,8 @@ module.exports = AuthenticationController =
LoginRateLimiter.recordSuccessfulLogin(email) LoginRateLimiter.recordSuccessfulLogin(email)
AuthenticationController._recordSuccessfulLogin(user._id) AuthenticationController._recordSuccessfulLogin(user._id)
Analytics.recordEvent(user._id, "user-logged-in") 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" logger.log email: email, user_id: user._id.toString(), "successful log in"
req.session.justLoggedIn = true
# capture the request ip for use when creating the session # capture the request ip for use when creating the session
user._login_req_ip = req.ip user._login_req_ip = req.ip
req._redir = redir req._redir = redir

View file

@ -20,7 +20,7 @@ describe "AuthenticationController", ->
"../Security/LoginRateLimiter": @LoginRateLimiter = { processLoginRequest:sinon.stub(), recordSuccessfulLogin:sinon.stub() } "../Security/LoginRateLimiter": @LoginRateLimiter = { processLoginRequest:sinon.stub(), recordSuccessfulLogin:sinon.stub() }
"../User/UserHandler": @UserHandler = {setupLoginData:sinon.stub()} "../User/UserHandler": @UserHandler = {setupLoginData:sinon.stub()}
"../Analytics/AnalyticsManager": @AnalyticsManager = { recordEvent: sinon.stub() } "../Analytics/AnalyticsManager": @AnalyticsManager = { recordEvent: sinon.stub() }
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() } "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub(), err: sinon.stub() }
"settings-sharelatex": {} "settings-sharelatex": {}
"passport": @passport = "passport": @passport =
authenticate: sinon.stub().returns(sinon.stub()) authenticate: sinon.stub().returns(sinon.stub())
@ -50,6 +50,10 @@ describe "AuthenticationController", ->
@info = null @info = null
@req.login = sinon.stub().callsArgWith(1, null) @req.login = sinon.stub().callsArgWith(1, null)
@res.json = sinon.stub() @res.json = sinon.stub()
@req.session = @session = {test: 'test'}
@req.session.destroy = sinon.stub()
@req.session.save = sinon.stub().callsArgWith(0, null)
@req.sessionStore = {generate: sinon.stub()}
@passport.authenticate.callsArgWith(1, null, @user, @info) @passport.authenticate.callsArgWith(1, null, @user, @info)
it 'should call passport.authenticate', () -> it 'should call passport.authenticate', () ->
@ -85,6 +89,18 @@ describe "AuthenticationController", ->
@res.json.callCount.should.equal 1 @res.json.callCount.should.equal 1
@res.json.calledWith({redir: @req._redir}).should.equal true @res.json.calledWith({redir: @req._redir}).should.equal true
describe 'when session.save produces an error', () ->
beforeEach ->
@req.session.save = sinon.stub().callsArgWith(0, new Error('woops'))
it 'should return next with an error', () ->
@AuthenticationController.passportLogin @req, @res, @next
@next.calledWith(@err).should.equal true
it 'should not return json', () ->
@AuthenticationController.passportLogin @req, @res, @next
@res.json.callCount.should.equal 0
describe 'when authenticate does not produce a user', -> describe 'when authenticate does not produce a user', ->
beforeEach -> beforeEach ->