mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 14:43:46 +01:00
Merge pull request #2249 from overleaf/bg-create-session-validation-token-for-all-sessions
move session validation into SessionStoreManager GitOrigin-RevId: 438ec738f0ccaf9f072629d6203a334cb8439b83
This commit is contained in:
@@ -8,6 +8,7 @@ const Settings = require('settings-sharelatex')
|
||||
const basicAuth = require('basic-auth-connect')
|
||||
const UserHandler = require('../User/UserHandler')
|
||||
const UserSessionsManager = require('../User/UserSessionsManager')
|
||||
const SessionStoreManager = require('../../infrastructure/SessionStoreManager')
|
||||
const Analytics = require('../Analytics/AnalyticsManager')
|
||||
const passport = require('passport')
|
||||
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
|
||||
@@ -42,51 +43,6 @@ const AuthenticationController = (module.exports = {
|
||||
cb(null, user)
|
||||
},
|
||||
|
||||
computeSessionValidationToken(req) {
|
||||
// this should be a deterministic function of the client-side sessionID,
|
||||
// prepended with a version number in case we want to change it later
|
||||
return 'v1:' + req.sessionID.slice(-4)
|
||||
},
|
||||
|
||||
setSessionValidationToken(req) {
|
||||
req.session.validationToken = AuthenticationController.computeSessionValidationToken(
|
||||
req
|
||||
)
|
||||
},
|
||||
|
||||
checkSessionValidationToken(req) {
|
||||
if (req.session) {
|
||||
const token = req.session.validationToken
|
||||
if (token) {
|
||||
const clientToken = AuthenticationController.computeSessionValidationToken(
|
||||
req
|
||||
)
|
||||
// Reject invalid sessions. If you change the method for computing the
|
||||
// token (above) then you need to either check or ignore previous
|
||||
// versions of the token.
|
||||
if (token === clientToken) {
|
||||
Metrics.inc('security.session', 1, { status: 'ok' })
|
||||
return true
|
||||
} else {
|
||||
logger.error(
|
||||
{
|
||||
token: token,
|
||||
clientToken: clientToken,
|
||||
req: req,
|
||||
sessionID: req.sessionID
|
||||
},
|
||||
'session token validation failed'
|
||||
)
|
||||
Metrics.inc('security.session', 1, { status: 'error' })
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
Metrics.inc('security.session', 1, { status: 'missing' })
|
||||
}
|
||||
}
|
||||
return true // fallback to allowing session
|
||||
},
|
||||
|
||||
afterLoginSessionSetup(req, user, callback) {
|
||||
if (callback == null) {
|
||||
callback = function() {}
|
||||
@@ -108,14 +64,14 @@ const AuthenticationController = (module.exports = {
|
||||
return callback(err)
|
||||
}
|
||||
req.sessionStore.generate(req)
|
||||
// Note: the validation token is not writable, so it does not get
|
||||
// transferred to the new session below.
|
||||
for (let key in oldSession) {
|
||||
const value = oldSession[key]
|
||||
if (key !== '__tmp') {
|
||||
req.session[key] = value
|
||||
}
|
||||
}
|
||||
// generate an identifier from the sessionID
|
||||
AuthenticationController.setSessionValidationToken(req)
|
||||
req.session.save(function(err) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
@@ -299,7 +255,7 @@ const AuthenticationController = (module.exports = {
|
||||
},
|
||||
|
||||
getSessionUser(req) {
|
||||
if (!AuthenticationController.checkSessionValidationToken(req)) {
|
||||
if (!SessionStoreManager.checkValidationToken(req)) {
|
||||
return null
|
||||
}
|
||||
const sessionUser = _.get(req, ['session', 'user'])
|
||||
|
||||
@@ -13,6 +13,7 @@ const Csrf = require('./Csrf')
|
||||
|
||||
const sessionsRedisClient = UserSessionsRedis.client()
|
||||
|
||||
const SessionStoreManager = require('./SessionStoreManager')
|
||||
const session = require('express-session')
|
||||
const RedisStore = require('connect-redis')(session)
|
||||
const bodyParser = require('body-parser')
|
||||
@@ -111,6 +112,9 @@ webRouter.use(
|
||||
})
|
||||
)
|
||||
|
||||
// patch the session store to generate a validation token for every new session
|
||||
SessionStoreManager.enableValidationToken(sessionStore)
|
||||
|
||||
// passport
|
||||
webRouter.use(passport.initialize())
|
||||
webRouter.use(passport.session())
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
const Metrics = require('metrics-sharelatex')
|
||||
const logger = require('logger-sharelatex')
|
||||
|
||||
function computeValidationToken(req) {
|
||||
// this should be a deterministic function of the client-side sessionID,
|
||||
// prepended with a version number in case we want to change it later
|
||||
return 'v1:' + req.sessionID.slice(-4)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
enableValidationToken(sessionStore) {
|
||||
// generate an identifier from the sessionID for every new session
|
||||
const originalGenerate = sessionStore.generate
|
||||
sessionStore.generate = function(req) {
|
||||
originalGenerate(req)
|
||||
// add the validation token as a property that cannot be overwritten
|
||||
Object.defineProperty(req.session, 'validationToken', {
|
||||
value: computeValidationToken(req),
|
||||
enumerable: true,
|
||||
writable: false
|
||||
})
|
||||
Metrics.inc('security.session', 1, { status: 'new' })
|
||||
}
|
||||
},
|
||||
|
||||
checkValidationToken(req) {
|
||||
if (req.session) {
|
||||
const sessionToken = req.session.validationToken
|
||||
if (sessionToken) {
|
||||
const clientToken = computeValidationToken(req)
|
||||
// Reject invalid sessions. If you change the method for computing the
|
||||
// token (above) then you need to either check or ignore previous
|
||||
// versions of the token.
|
||||
if (sessionToken === clientToken) {
|
||||
Metrics.inc('security.session', 1, { status: 'ok' })
|
||||
return true
|
||||
} else {
|
||||
logger.error(
|
||||
{
|
||||
sessionToken: sessionToken,
|
||||
clientToken: clientToken
|
||||
},
|
||||
'session token validation failed'
|
||||
)
|
||||
Metrics.inc('security.session', 1, { status: 'error' })
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
Metrics.inc('security.session', 1, { status: 'missing' })
|
||||
}
|
||||
}
|
||||
return true // fallback to allowing session
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user