feat(audit): record failed users' connection attempt (#4900)

See #4844
This commit is contained in:
badrAZ
2020-05-25 12:48:05 +02:00
committed by GitHub
parent b9a18807ae
commit 3d5fd47748
5 changed files with 42 additions and 21 deletions

View File

@@ -14,6 +14,7 @@
- [Modal] Don't close pop-up forms when you click outside or press escape (PR [#5002](https://github.com/vatesfr/xen-orchestra/pull/5002))
- [Plugin/auth-ldap] Support `StartTLS` [#4999](https://github.com/vatesfr/xen-orchestra/issues/4999)
- [OVA import] Add support for OVA 2.0 file format (PR [#4921](https://github.com/vatesfr/xen-orchestra/pull/4921))
- [Audit] Record failed connection attempts [#4844](https://github.com/vatesfr/xen-orchestra/issues/4844) (PR [#4900](https://github.com/vatesfr/xen-orchestra/pull/4900))
### Bug fixes
@@ -44,6 +45,7 @@
>
> In case of conflict, the highest (lowest in previous list) `$version` wins.
- xo-server-audit minor
- xo-vmdk-to-vhd minor
- xo-server-backup-reports patch
- xo-server-perf-alert patch
@@ -52,5 +54,5 @@
- xo-server-sdn-controller patch
- xo-server-usage-report minor
- @xen-orchestra/fs patch
- xo-server patch
- xo-server minor
- xo-web minor

View File

@@ -40,6 +40,7 @@ const DEFAULT_BLOCKED_LIST = {
'schedule.getAll': true,
'server.getAll': true,
'session.getUser': true,
'session.signIn': true,
'sr.getUnhealthyVdiChainsLength': true,
'sr.stats': true,
'system.getMethodsInfo': true,

View File

@@ -7,7 +7,10 @@ import { getUserPublicProperties } from '../utils'
export async function signIn(credentials) {
const { session } = this
const { user, expiration } = await this.authenticateUser(credentials)
const { user, expiration } = await this.authenticateUser(credentials, {
ip: session.get('user_ip', undefined),
})
session.set('user_id', user.id)
if (expiration === undefined) {

View File

@@ -278,14 +278,20 @@ async function setUpPassport(express, xo, { authentication: authCfg }) {
// Install the local strategy.
xo.registerPassportStrategy(
new LocalStrategy(async (username, password, done) => {
try {
const { user } = await xo.authenticateUser({ username, password })
done(null, user)
} catch (error) {
done(null, false, { message: error.message })
new LocalStrategy(
{ passReqToCallback: true },
async (req, username, password, done) => {
try {
const { user } = await xo.authenticateUser(
{ username, password },
{ ip: req.ip }
)
done(null, user)
} catch (error) {
done(null, false, { message: error.message })
}
}
})
)
)
}

View File

@@ -31,16 +31,24 @@ export default class {
}))
// Password authentication provider.
this.registerAuthenticationProvider(async ({ username, password }) => {
if (username === undefined || password === undefined) {
return
}
this.registerAuthenticationProvider(
async ({ username, password }, { ip } = {}) => {
if (username === undefined || password === undefined) {
return
}
const user = await xo.getUserByName(username, true)
if (user && (await xo.checkUserPassword(user.id, password))) {
return { userId: user.id }
const user = await xo.getUserByName(username, true)
if (user && (await xo.checkUserPassword(user.id, password))) {
return { userId: user.id }
}
xo.emit('xo:audit', 'signInFailed', {
userId: user?.id,
userName: username,
userIp: ip,
})
}
})
)
// Token authentication provider.
this.registerAuthenticationProvider(async ({ token: tokenId }) => {
@@ -84,7 +92,7 @@ export default class {
return this._providers.delete(provider)
}
async _authenticateUser(credentials) {
async _authenticateUser(credentials, userData) {
for (const provider of this._providers) {
try {
// A provider can return:
@@ -96,7 +104,7 @@ export default class {
// valid
// - an object with a property `username` containing the name
// of the authenticated user
const result = await provider(credentials)
const result = await provider(credentials, userData)
// No match.
if (result == null) {
@@ -127,7 +135,8 @@ export default class {
}
async authenticateUser(
credentials
credentials,
userData
): Promise<{| user: Object, expiration?: number |}> {
// don't even attempt to authenticate with empty password
const { password } = credentials
@@ -155,7 +164,7 @@ export default class {
throw new Error('too fast authentication tries')
}
const result = await this._authenticateUser(credentials)
const result = await this._authenticateUser(credentials, userData)
if (result === undefined) {
failures[username] = now
throw invalidCredentials()