@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user