Fixed channel sync and role sync (#23311)

pull/23322/head
pierre-lehnen-rc 4 years ago committed by GitHub
parent f0aa26757b
commit 4bae47ddc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      ee/server/configuration/ldap.ts
  2. 55
      ee/server/lib/ldap/Manager.ts
  3. 24
      server/lib/ldap/Manager.ts

@ -4,6 +4,7 @@ import _ from 'underscore';
import { LDAPEE } from '../sdk';
import { settings } from '../../../app/settings/server';
import { LDAPConnection } from '../../../server/lib/ldap/Connection';
import { logger } from '../../../server/lib/ldap/Logger';
import { cronJobs } from '../../../app/utils/server/lib/cron/Cronjobs';
import { LDAPEEManager } from '../lib/ldap/Manager';
@ -11,6 +12,7 @@ import { callbacks } from '../../../app/callbacks/server';
import type { IImportUser } from '../../../definition/IImportUser';
import type { ILDAPEntry } from '../../../definition/ldap/ILDAPEntry';
import type { SettingValue } from '../../../definition/ISetting';
import type { IUser } from '../../../definition/IUser';
import type { SettingCallback } from '../../../app/settings/lib/settings';
import { onLicense } from '../../app/license/server';
import { addSettings } from '../settings/ldap';
@ -75,4 +77,8 @@ Meteor.startup(() => onLicense('ldap-enterprise', () => {
LDAPEEManager.copyCustomFields(ldapUser, userData);
LDAPEEManager.copyActiveState(ldapUser, userData);
}, callbacks.priority.MEDIUM, 'mapLDAPCustomFields');
callbacks.add('onLDAPLogin', ({ user, ldapUser, isNewUser }: { user: IUser; ldapUser: ILDAPEntry; isNewUser: boolean }, ldap: LDAPConnection) => {
Promise.await(LDAPEEManager.advancedSyncForUser(ldap, user, isNewUser, ldapUser.dn));
}, callbacks.priority.MEDIUM, 'advancedLDAPSync');
}));

@ -113,6 +113,12 @@ export class LDAPEEManager extends LDAPManager {
}
}
public static async advancedSyncForUser(ldap: LDAPConnection, user: IUser, isNewRecord: boolean, dn: string): Promise<void> {
await this.syncUserRoles(ldap, user, dn);
await this.syncUserChannels(ldap, user, dn);
await this.syncUserTeams(ldap, user, isNewRecord);
}
private static async advancedSync(ldap: LDAPConnection, importUser: IImportUser, converter: LDAPDataConverter, isNewRecord: boolean): Promise<void> {
const user = converter.findExistingUser(importUser);
if (!user || user.username) {
@ -120,9 +126,7 @@ export class LDAPEEManager extends LDAPManager {
}
const dn = importUser.importIds[0];
await this.syncUserRoles(ldap, user, dn);
await this.syncUserChannels(ldap, user, dn);
await this.syncUserTeams(ldap, user, isNewRecord);
return this.advancedSyncForUser(ldap, user, isNewRecord, dn);
}
private static async isUserInGroup(ldap: LDAPConnection, baseDN: string, filter: string, { dn, username }: { dn: string; username: string }, groupName: string): Promise<boolean> {
@ -200,20 +204,22 @@ export class LDAPEEManager extends LDAPManager {
const fieldMap = this.parseJson(syncUserRolesFieldMap);
if (!fieldMap) {
logger.debug('missing group role mapping');
return;
}
Object.keys(fieldMap).forEach(async (ldapField) => {
if (!fieldMap.hasOwnProperty(ldapField)) {
return;
const ldapFields = Object.keys(fieldMap);
for await (const ldapField of ldapFields) {
if (!fieldMap[ldapField]) {
continue;
}
const userField = fieldMap[ldapField];
const [roleName] = userField.split(/\.(.+)/);
if (!_.find<IRole>(roles, (el) => el._id === roleName)) {
if (!_.find<IRole>(roles, (el) => el.name === roleName)) {
logger.debug(`User Role doesn't exist: ${ roleName }`);
return;
continue;
}
logger.debug(`User role exists for mapping ${ ldapField } -> ${ roleName }`);
@ -223,17 +229,17 @@ export class LDAPEEManager extends LDAPManager {
this.broadcastRoleChange('added', roleName, user._id, username);
}
logger.debug(`Synced user group ${ roleName } from LDAP for ${ user.username }`);
return;
continue;
}
if (!syncUserRolesAutoRemove) {
return;
continue;
}
if (Roles.removeUserRoles(user._id, roleName)) {
this.broadcastRoleChange('removed', roleName, user._id, username);
}
});
}
}
private static createRoomForSync(channel: string): IRoom | undefined {
@ -265,22 +271,33 @@ export class LDAPEEManager extends LDAPManager {
const fieldMap = this.parseJson(syncUserChannelsFieldMap);
if (!fieldMap) {
logger.debug('missing group channel mapping');
return;
}
const { username } = user;
if (!username) {
return;
}
const username = user.username as string;
_.map(fieldMap, (channels, ldapField) => {
if (!Array.isArray(channels)) {
channels = [channels];
logger.debug('syncing user channels');
const ldapFields = Object.keys(fieldMap);
for await (const ldapField of ldapFields) {
if (!fieldMap[ldapField]) {
continue;
}
channels.forEach(async (channel: string) => {
const isUserInGroup = await this.isUserInGroup(ldap, syncUserChannelsBaseDN, syncUserChannelsFilter, { dn, username }, ldapField);
const channels: Array<string> = [].concat(fieldMap[ldapField]);
for await (const channel of channels) {
const room: IRoom | undefined = Rooms.findOneByNonValidatedName(channel) || this.createRoomForSync(channel);
if (!room) {
return;
}
if (await this.isUserInGroup(ldap, syncUserChannelsBaseDN, syncUserChannelsFilter, { dn, username }, ldapField)) {
if (isUserInGroup) {
if (room.teamMain) {
logger.error(`Can't add user to channel ${ channel } because it is a team.`);
} else {
@ -293,8 +310,8 @@ export class LDAPEEManager extends LDAPManager {
removeUserFromRoom(room._id, user);
}
}
});
});
}
}
}
private static async syncUserTeams(ldap: LDAPConnection, user: IUser, isNewRecord: boolean): Promise<void> {

@ -9,7 +9,7 @@ import _ from 'underscore';
import { ILDAPEntry } from '../../../definition/ldap/ILDAPEntry';
import { LDAPLoginResult } from '../../../definition/ldap/ILDAPLoginResult';
import { ILDAPUniqueIdentifierField } from '../../../definition/ldap/ILDAPUniqueIdentifierField';
import { IUser, /* IUserEmail,*/ LoginUsername } from '../../../definition/IUser';
import { IUser, LoginUsername } from '../../../definition/IUser';
import { IImportUser } from '../../../definition/IImportUser';
import { settings } from '../../../app/settings/server';
import { Users as UsersRaw } from '../../../app/models/server/raw';
@ -205,7 +205,7 @@ export class LDAPManager {
private static async addLdapUser(ldapUser: ILDAPEntry, username: string | undefined, password: string | undefined, ldap: LDAPConnection): Promise<LDAPLoginResult> {
const user = await this.syncUserForLogin(ldapUser, undefined, username);
this.onLogin(ldapUser, user, password, ldap);
this.onLogin(ldapUser, user, password, ldap, true);
if (user) {
return {
userId: user._id,
@ -213,18 +213,18 @@ export class LDAPManager {
}
}
private static onLogin(ldapUser: ILDAPEntry, user: IUser | undefined, password: string | undefined, ldap: LDAPConnection): void {
logger.debug('running onLDAPLogin');
if (user) {
if (settings.get<boolean>('LDAP_Login_Fallback') && typeof password === 'string' && password.trim() !== '') {
Accounts.setPassword(user._id, password, { logout: false });
}
private static onLogin(ldapUser: ILDAPEntry, user: IUser | undefined, password: string | undefined, ldap: LDAPConnection, isNewUser: boolean): void {
if (!user) {
return;
}
this.syncUserAvatar(user, ldapUser);
logger.debug('running onLDAPLogin');
if (settings.get<boolean>('LDAP_Login_Fallback') && typeof password === 'string' && password.trim() !== '') {
Accounts.setPassword(user._id, password, { logout: false });
}
callbacks.run('onLDAPLogin', { user, ldapUser }, ldap);
this.syncUserAvatar(user, ldapUser);
callbacks.run('onLDAPLogin', { user, ldapUser, isNewUser }, ldap);
}
private static async loginExistingUser(ldap: LDAPConnection, user: IUser, ldapUser: ILDAPEntry, password: string): Promise<LDAPLoginResult> {
@ -237,7 +237,7 @@ export class LDAPManager {
logger.debug({ msg: 'Logging user in', syncData });
const updatedUser = (syncData && await this.syncUserForLogin(ldapUser, user)) || user;
this.onLogin(ldapUser, updatedUser, password, ldap);
this.onLogin(ldapUser, updatedUser, password, ldap, false);
return {
userId: user._id,
};

Loading…
Cancel
Save