refactor(core): Decouple LDAP from internal hooks (no-changelog) (#10157)

Co-authored-by: Ricardo Espinoza <ricardo@n8n.io>
This commit is contained in:
Iván Ovejero 2024-07-24 09:49:06 +02:00 committed by GitHub
parent 30784fb76c
commit dea212659a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 105 additions and 49 deletions

View file

@ -618,40 +618,6 @@ export class InternalHooks {
}); });
} }
async onLdapSyncFinished(data: {
type: string;
succeeded: boolean;
users_synced: number;
error: string;
}): Promise<void> {
return await this.telemetry.track('Ldap general sync finished', data);
}
async onUserUpdatedLdapSettings(data: {
user_id: string;
loginIdAttribute: string;
firstNameAttribute: string;
lastNameAttribute: string;
emailAttribute: string;
ldapIdAttribute: string;
searchPageSize: number;
searchTimeout: number;
synchronizationEnabled: boolean;
synchronizationInterval: number;
loginLabel: string;
loginEnabled: boolean;
}): Promise<void> {
return await this.telemetry.track('Ldap general sync finished', data);
}
async onLdapLoginSyncFailed(data: { error: string }): Promise<void> {
return await this.telemetry.track('Ldap login sync failed', data);
}
async userLoginFailedDueToLdapDisabled(data: { user_id: string }): Promise<void> {
return await this.telemetry.track('User login failed since ldap disabled', data);
}
/* /*
* Execution Statistics * Execution Statistics
*/ */

View file

@ -1,18 +1,18 @@
import pick from 'lodash/pick'; import pick from 'lodash/pick';
import { Get, Post, Put, RestController, GlobalScope } from '@/decorators'; import { Get, Post, Put, RestController, GlobalScope } from '@/decorators';
import { InternalHooks } from '@/InternalHooks';
import { BadRequestError } from '@/errors/response-errors/bad-request.error'; import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { NON_SENSIBLE_LDAP_CONFIG_PROPERTIES } from './constants'; import { NON_SENSIBLE_LDAP_CONFIG_PROPERTIES } from './constants';
import { getLdapSynchronizations } from './helpers.ee'; import { getLdapSynchronizations } from './helpers.ee';
import { LdapConfiguration } from './types'; import { LdapConfiguration } from './types';
import { LdapService } from './ldap.service.ee'; import { LdapService } from './ldap.service.ee';
import { EventService } from '@/eventbus/event.service';
@RestController('/ldap') @RestController('/ldap')
export class LdapController { export class LdapController {
constructor( constructor(
private readonly internalHooks: InternalHooks,
private readonly ldapService: LdapService, private readonly ldapService: LdapService,
private readonly eventService: EventService,
) {} ) {}
@Get('/config') @Get('/config')
@ -42,8 +42,8 @@ export class LdapController {
const data = await this.ldapService.loadConfig(); const data = await this.ldapService.loadConfig();
void this.internalHooks.onUserUpdatedLdapSettings({ this.eventService.emit('ldap-settings-updated', {
user_id: req.user.id, userId: req.user.id,
...pick(data, NON_SENSIBLE_LDAP_CONFIG_PROPERTIES), ...pick(data, NON_SENSIBLE_LDAP_CONFIG_PROPERTIES),
}); });

View file

@ -11,7 +11,6 @@ import config from '@/config';
import type { User } from '@db/entities/User'; import type { User } from '@db/entities/User';
import type { RunningMode, SyncStatus } from '@db/entities/AuthProviderSyncHistory'; import type { RunningMode, SyncStatus } from '@db/entities/AuthProviderSyncHistory';
import { SettingsRepository } from '@db/repositories/settings.repository'; import { SettingsRepository } from '@db/repositories/settings.repository';
import { InternalHooks } from '@/InternalHooks';
import { Logger } from '@/Logger'; import { Logger } from '@/Logger';
import { BadRequestError } from '@/errors/response-errors/bad-request.error'; import { BadRequestError } from '@/errors/response-errors/bad-request.error';
@ -45,6 +44,7 @@ import {
LDAP_LOGIN_ENABLED, LDAP_LOGIN_ENABLED,
LDAP_LOGIN_LABEL, LDAP_LOGIN_LABEL,
} from './constants'; } from './constants';
import { EventService } from '@/eventbus/event.service';
@Service() @Service()
export class LdapService { export class LdapService {
@ -56,9 +56,9 @@ export class LdapService {
constructor( constructor(
private readonly logger: Logger, private readonly logger: Logger,
private readonly internalHooks: InternalHooks,
private readonly settingsRepository: SettingsRepository, private readonly settingsRepository: SettingsRepository,
private readonly cipher: Cipher, private readonly cipher: Cipher,
private readonly eventService: EventService,
) {} ) {}
async init() { async init() {
@ -257,9 +257,7 @@ export class LdapService {
); );
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
void this.internalHooks.onLdapLoginSyncFailed({ this.eventService.emit('ldap-login-sync-failed', { error: e.message });
error: e.message,
});
this.logger.error('LDAP - Error during search', { message: e.message }); this.logger.error('LDAP - Error during search', { message: e.message });
} }
return undefined; return undefined;
@ -383,10 +381,10 @@ export class LdapService {
error: errorMessage, error: errorMessage,
}); });
void this.internalHooks.onLdapSyncFinished({ this.eventService.emit('ldap-general-sync-finished', {
type: !this.syncTimer ? 'scheduled' : `manual_${mode}`, type: !this.syncTimer ? 'scheduled' : `manual_${mode}`,
succeeded: true, succeeded: true,
users_synced: usersToCreate.length + usersToUpdate.length + usersToDisable.length, usersSynced: usersToCreate.length + usersToUpdate.length + usersToDisable.length,
error: errorMessage, error: errorMessage,
}); });

View file

@ -1,10 +1,10 @@
import type { User } from '@db/entities/User'; import type { User } from '@db/entities/User';
import { PasswordUtility } from '@/services/password.utility'; import { PasswordUtility } from '@/services/password.utility';
import { Container } from 'typedi'; import { Container } from 'typedi';
import { InternalHooks } from '@/InternalHooks';
import { isLdapLoginEnabled } from '@/Ldap/helpers.ee'; import { isLdapLoginEnabled } from '@/Ldap/helpers.ee';
import { UserRepository } from '@db/repositories/user.repository'; import { UserRepository } from '@db/repositories/user.repository';
import { AuthError } from '@/errors/response-errors/auth.error'; import { AuthError } from '@/errors/response-errors/auth.error';
import { EventService } from '@/eventbus/event.service';
export const handleEmailLogin = async ( export const handleEmailLogin = async (
email: string, email: string,
@ -23,9 +23,7 @@ export const handleEmailLogin = async (
// so suggest to reset the password to gain access to the instance. // so suggest to reset the password to gain access to the instance.
const ldapIdentity = user?.authIdentities?.find((i) => i.providerType === 'ldap'); const ldapIdentity = user?.authIdentities?.find((i) => i.providerType === 'ldap');
if (user && ldapIdentity && !isLdapLoginEnabled()) { if (user && ldapIdentity && !isLdapLoginEnabled()) {
void Container.get(InternalHooks).userLoginFailedDueToLdapDisabled({ Container.get(EventService).emit('login-failed-due-to-ldap-disabled', { userId: user.id });
user_id: user.id,
});
throw new AuthError('Reset your password to gain access to the instance.'); throw new AuthError('Reset your password to gain access to the instance.');
} }

View file

@ -266,6 +266,36 @@ export type Event = {
errorMessage?: string; errorMessage?: string;
}; };
'ldap-general-sync-finished': {
type: string;
succeeded: boolean;
usersSynced: number;
error: string;
};
'ldap-settings-updated': {
userId: string;
loginIdAttribute: string;
firstNameAttribute: string;
lastNameAttribute: string;
emailAttribute: string;
ldapIdAttribute: string;
searchPageSize: number;
searchTimeout: number;
synchronizationEnabled: boolean;
synchronizationInterval: number;
loginLabel: string;
loginEnabled: boolean;
};
'ldap-login-sync-failed': {
error: string;
};
'login-failed-due-to-ldap-disabled': {
userId: string;
};
/** /**
* Events listened to by more than one relay * Events listened to by more than one relay
*/ */

View file

@ -66,6 +66,18 @@ export class TelemetryEventRelay {
this.eventService.on('community-package-deleted', (event) => { this.eventService.on('community-package-deleted', (event) => {
this.communityPackageDeleted(event); this.communityPackageDeleted(event);
}); });
this.eventService.on('ldap-general-sync-finished', (event) => {
this.ldapGeneralSyncFinished(event);
});
this.eventService.on('ldap-settings-updated', (event) => {
this.ldapSettingsUpdated(event);
});
this.eventService.on('ldap-login-sync-failed', (event) => {
this.ldapLoginSyncFailed(event);
});
this.eventService.on('login-failed-due-to-ldap-disabled', (event) => {
this.loginFailedDueToLdapDisabled(event);
});
} }
private teamProjectUpdated({ userId, role, members, projectId }: Event['team-project-updated']) { private teamProjectUpdated({ userId, role, members, projectId }: Event['team-project-updated']) {
@ -293,4 +305,56 @@ export class TelemetryEventRelay {
package_author_email: packageAuthorEmail, package_author_email: packageAuthorEmail,
}); });
} }
private ldapGeneralSyncFinished({
type,
succeeded,
usersSynced,
error,
}: Event['ldap-general-sync-finished']) {
void this.telemetry.track('Ldap general sync finished', {
type,
succeeded,
users_synced: usersSynced,
error,
});
}
private ldapSettingsUpdated({
userId,
loginIdAttribute,
firstNameAttribute,
lastNameAttribute,
emailAttribute,
ldapIdAttribute,
searchPageSize,
searchTimeout,
synchronizationEnabled,
synchronizationInterval,
loginLabel,
loginEnabled,
}: Event['ldap-settings-updated']) {
void this.telemetry.track('User updated Ldap settings', {
user_id: userId,
loginIdAttribute,
firstNameAttribute,
lastNameAttribute,
emailAttribute,
ldapIdAttribute,
searchPageSize,
searchTimeout,
synchronizationEnabled,
synchronizationInterval,
loginLabel,
loginEnabled,
});
}
private ldapLoginSyncFailed({ error }: Event['ldap-login-sync-failed']) {
void this.telemetry.track('Ldap login sync failed', { error });
}
private loginFailedDueToLdapDisabled({ userId }: Event['login-failed-due-to-ldap-disabled']) {
void this.telemetry.track('User login failed since ldap disabled', { user_ud: userId });
}
} }