feat(xo-server/api): close connection when session expires (#4071)

See xoa-support#1389
This commit is contained in:
Julien Fontanet 2019-03-27 10:36:15 +01:00 committed by GitHub
parent 9f6fc785bc
commit 851bcf9816
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 10 deletions

View File

@ -5,8 +5,16 @@ import { getUserPublicProperties } from '../utils'
// ===================================================================
export async function signIn(credentials) {
const user = await this.authenticateUser(credentials)
this.session.set('user_id', user.id)
const { session } = this
const { user, expiration } = await this.authenticateUser(credentials)
session.set('user_id', user.id)
if (expiration === undefined) {
session.unset('expiration')
} else {
session.set('expiration', expiration)
}
return getUserPublicProperties(user)
}

View File

@ -251,7 +251,7 @@ async function setUpPassport(express, xo, { authentication: authCfg }) {
xo.registerPassportStrategy(
new LocalStrategy(async (username, password, done) => {
try {
const user = await xo.authenticateUser({ username, password })
const { user } = await xo.authenticateUser({ username, password })
done(null, user)
} catch (error) {
done(null, false, { message: error.message })
@ -518,6 +518,11 @@ const setUpApi = (webServer, xo, config) => {
// Connect the WebSocket to the JSON-RPC server.
socket.on('message', message => {
const expiration = connection.get('expiration', undefined)
if (expiration !== undefined && expiration < Date.now()) {
return void connection.close()
}
jsonRpc.write(message)
})
@ -565,7 +570,7 @@ const setUpConsoleProxy = (webServer, xo) => {
{
const { token } = parseCookies(req.headers.cookie)
const user = await xo.authenticateUser({ token })
const { user } = await xo.authenticateUser({ token })
if (!(await xo.hasPermissions(user.id, [[id, 'operate']]))) {
throw invalidCredentials()
}

View File

@ -37,7 +37,7 @@ export default class {
const user = await xo.getUserByName(username, true)
if (user && (await xo.checkUserPassword(user.id, password))) {
return user.id
return { userId: user.id }
}
})
@ -48,7 +48,8 @@ export default class {
}
try {
return (await xo.getAuthenticationToken(tokenId)).user_id
const token = await xo.getAuthenticationToken(tokenId)
return { expiration: token.expiration, userId: token.user_id }
} catch (error) {}
})
@ -88,6 +89,10 @@ export default class {
// A provider can return:
// - `undefined`/`null` if the user could not be authenticated
// - the identifier of the authenticated user
// - an object containing:
// - `userId`
// - optionally `expiration` to indicate when the session is no longer
// valid
// - an object with a property `username` containing the name
// of the authenticated user
const result = await provider(credentials)
@ -97,9 +102,20 @@ export default class {
continue
}
return result.username
? await this._xo.registerUser(undefined, result.username)
: await this._xo.getUser(result)
if (typeof result === 'string') {
return {
user: await this._getUser(result),
}
}
const { userId, username, expiration } = result
return {
user: await (userId !== undefined
? this._xo.getUser(userId)
: this._xo.registerUser(undefined, username)),
expiration,
}
} catch (error) {
// DEPRECATED: Authentication providers may just throw `null`
// to indicate they could not authenticate the user without
@ -109,7 +125,9 @@ export default class {
}
}
async authenticateUser(credentials) {
async authenticateUser(
credentials
): Promise<{| user: Object, expiration?: number |}> {
// don't even attempt to authenticate with empty password
const { password } = credentials
if (password === '') {