fix(xo-server-auth-ldap): create logger inside plugin (#5864)

The plugin was wrongly expecting a logger instance to be passed on instantiation
This commit is contained in:
Pierre Donias 2021-08-11 11:21:22 +02:00 committed by GitHub
parent 656dc8fefc
commit d5f5cdd27a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 26 deletions

View File

@ -31,6 +31,7 @@
"node": ">=10"
},
"dependencies": {
"@xen-orchestra/log": "^0.2.1",
"exec-promise": "^0.7.0",
"inquirer": "^8.0.0",
"ldapts": "^2.2.1",

View File

@ -3,9 +3,12 @@
import ensureArray from 'ensure-array'
import fromCallback from 'promise-toolbox/fromCallback'
import { Client } from 'ldapts'
import { createLogger } from '@xen-orchestra/log'
import { Filter } from 'ldapts/filters/Filter'
import { readFile } from 'fs'
const logger = createLogger('xo:xo-server-auth-ldap')
// ===================================================================
const DEFAULTS = {
@ -27,8 +30,6 @@ const evalFilter = (filter, vars) =>
return escape(value)
})
const noop = Function.prototype
export const configurationSchema = {
type: 'object',
properties: {
@ -184,8 +185,7 @@ export const testSchema = {
// ===================================================================
class AuthLdap {
constructor({ logger = noop, xo }) {
this._logger = logger
constructor({ xo } = {}) {
this._xo = xo
this._authenticate = this._authenticate.bind(this)
@ -257,10 +257,8 @@ class AuthLdap {
}
async _authenticate({ username, password }) {
const logger = this._logger
if (username === undefined || password === undefined) {
logger('require `username` and `password` to authenticate!')
logger.debug('require `username` and `password` to authenticate!')
return null
}
@ -276,29 +274,34 @@ class AuthLdap {
{
const { _credentials: credentials } = this
if (credentials) {
logger(`attempting to bind with as ${credentials.dn}...`)
logger.debug(`attempting to bind with as ${credentials.dn}...`)
await client.bind(credentials.dn, credentials.password)
logger(`successfully bound as ${credentials.dn}`)
logger.debug(`successfully bound as ${credentials.dn}`)
}
}
// Search for the user.
logger('searching for entries...')
logger.debug('searching for entries...')
const { searchEntries: entries } = await client.search(this._searchBase, {
scope: 'sub',
filter: evalFilter(this._searchFilter, {
name: username,
}),
})
logger(`${entries.length} entries found`)
logger.debug(`${entries.length} entries found`)
// Try to find an entry which can be bind with the given password.
for (const entry of entries) {
try {
logger(`attempting to bind as ${entry.dn}`)
logger.debug(`attempting to bind as ${entry.dn}`)
await client.bind(entry.dn, password)
logger(`successfully bound as ${entry.dn} => ${username} authenticated`)
logger(JSON.stringify(entry, null, 2))
logger.info(`successfully bound as ${entry.dn} => ${username} authenticated`)
logger.debug(JSON.stringify(entry, null, 2))
// CLI test: don't register user/sync groups
if (this._xo === undefined) {
return
}
let user
if (this._userIdAttribute === undefined) {
@ -315,18 +318,18 @@ class AuthLdap {
try {
await this._synchronizeGroups(user, entry[groupsConfig.membersMapping.userAttribute])
} catch (error) {
logger(`failed to synchronize groups: ${error.message}`)
logger.error(`failed to synchronize groups: ${error.message}`)
}
}
}
return { userId: user.id }
} catch (error) {
logger(`failed to bind as ${entry.dn}: ${error.message}`)
logger.debug(`failed to bind as ${entry.dn}: ${error.message}`)
}
}
logger(`could not authenticate ${username}`)
logger.debug(`could not authenticate ${username}`)
return null
} finally {
await client.unbind()
@ -335,7 +338,6 @@ class AuthLdap {
// Synchronize user's groups OR all groups if no user is passed
async _synchronizeGroups(user, memberId) {
const logger = this._logger
const client = new Client(this._clientOpts)
try {
@ -347,12 +349,12 @@ class AuthLdap {
{
const { _credentials: credentials } = this
if (credentials) {
logger(`attempting to bind with as ${credentials.dn}...`)
logger.debug(`attempting to bind with as ${credentials.dn}...`)
await client.bind(credentials.dn, credentials.password)
logger(`successfully bound as ${credentials.dn}`)
logger.debug(`successfully bound as ${credentials.dn}`)
}
}
logger('syncing groups...')
logger.info('syncing groups...')
const { base, displayNameAttribute, filter, idAttribute, membersMapping } = this._groupsConfig
const { searchEntries: ldapGroups } = await client.search(base, {
scope: 'sub',
@ -374,7 +376,7 @@ class AuthLdap {
// Empty or undefined names/IDs are invalid
if (!groupLdapId || !groupLdapName) {
logger(`Invalid group ID (${groupLdapId}) or name (${groupLdapName})`)
logger.error(`Invalid group ID (${groupLdapId}) or name (${groupLdapName})`)
continue
}
@ -393,7 +395,7 @@ class AuthLdap {
if (xoGroupIndex === -1) {
if (xoGroups.find(group => group.name === groupLdapName) !== undefined) {
// TODO: check against LDAP groups that are being created as well
logger(`A group called ${groupLdapName} already exists`)
logger.error(`A group called ${groupLdapName} already exists`)
continue
}
xoGroup = await this._xo.createGroup({
@ -459,6 +461,8 @@ class AuthLdap {
xoGroups.filter(group => group.provider === 'ldap').map(group => this._xo.deleteGroup(group.id))
)
}
logger.info('done syncing groups')
} finally {
await client.unbind()
}

View File

@ -1,6 +1,8 @@
#!/usr/bin/env node
import execPromise from 'exec-promise'
import transportConsole from '@xen-orchestra/log/transports/console'
import { configure } from '@xen-orchestra/log/configure.js'
import { fromCallback } from 'promise-toolbox'
import { readFile, writeFile } from 'fs'
@ -28,9 +30,14 @@ execPromise(async args => {
}
)
const plugin = createPlugin({
logger: console.log.bind(console),
})
configure([
{
filter: process.env.DEBUG ?? 'xo:xo-server-auth-ldap',
transport: transportConsole(),
},
])
const plugin = createPlugin()
await plugin.configure(config)
await plugin._authenticate({