diff --git a/.changeset/stupid-rabbits-hide.md b/.changeset/stupid-rabbits-hide.md new file mode 100644 index 0000000000000..341fea6af5a5d --- /dev/null +++ b/.changeset/stupid-rabbits-hide.md @@ -0,0 +1,7 @@ +--- +'@rocket.chat/core-typings': minor +'@rocket.chat/i18n': minor +'@rocket.chat/meteor': minor +--- + +Adds a new setting to allow syncing federated users data through LDAP diff --git a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts index 03f853832ef51..0ff4f72a6f1c8 100644 --- a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts +++ b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts @@ -259,6 +259,10 @@ export class UserConverter extends RecordConverter[0]); + const localUsername = userData.federated ? undefined : userData.username; + if (userData.name || localUsername) { + await saveUserIdentity({ _id, name: userData.name, username: localUsername } as Parameters[0]); } if (userData.importIds.length) { @@ -347,6 +352,7 @@ export class UserConverter extends RecordConverter email.trim()); const name = this.getLdapName(ldapUser) || undefined; const voipExtension = this.getLdapExtension(ldapUser); @@ -182,6 +193,10 @@ export class LDAPManager { id, }, }, + ...(homeServer && { + username: `${username}:${homeServer}`, + federated: true, + }), }; this.onMapUserData(ldapUser, userData); @@ -500,6 +515,39 @@ export class LDAPManager { return this.getLdapDynamicValue(ldapUser, usernameField); } + protected static getFederationHomeServer(ldapUser: ILDAPEntry): string | undefined { + if (!settings.get('Federation_Matrix_enabled')) { + return; + } + + const homeServerField = settings.get('LDAP_FederationHomeServer_Field'); + const homeServer = this.getLdapDynamicValue(ldapUser, homeServerField); + + if (!homeServer) { + return; + } + + logger.debug({ msg: 'User has a federation home server', homeServer }); + + const localServer = settings.get('Federation_Matrix_homeserver_domain'); + if (localServer === homeServer) { + return; + } + + return homeServer; + } + + protected static getFederatedUsername(ldapUser: ILDAPEntry, requestUsername: string): string { + const username = this.slugifyUsername(ldapUser, requestUsername); + const homeServer = this.getFederationHomeServer(ldapUser); + + if (homeServer) { + return `${username}:${homeServer}`; + } + + return username; + } + // This method will find existing users by LDAP id or by username. private static async findExistingUser(ldapUser: ILDAPEntry, slugifiedUsername: string): Promise { const user = await this.findExistingLDAPUser(ldapUser); diff --git a/apps/meteor/server/settings/ldap.ts b/apps/meteor/server/settings/ldap.ts index d0d77d4ec3456..c492c94b69504 100644 --- a/apps/meteor/server/settings/ldap.ts +++ b/apps/meteor/server/settings/ldap.ts @@ -214,6 +214,11 @@ export const createLdapSettings = () => type: 'string', enableQuery, }); + + await this.add('LDAP_FederationHomeServer_Field', '', { + type: 'string', + enableQuery, + }); }); await this.section('LDAP_DataSync_Avatar', async function () { diff --git a/packages/core-typings/src/import/IImportUser.ts b/packages/core-typings/src/import/IImportUser.ts index de3b7806a300d..66841937cd90b 100644 --- a/packages/core-typings/src/import/IImportUser.ts +++ b/packages/core-typings/src/import/IImportUser.ts @@ -19,4 +19,5 @@ export interface IImportUser { password?: string; voipExtension?: string; + federated?: boolean; } diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index a524a44b339ca..6b62f7aef1025 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -3014,6 +3014,8 @@ "LDAP_Enable_Description": "Attempt to utilize LDAP for authentication.", "LDAP_Encryption": "Encryption", "LDAP_Encryption_Description": "The encryption method used to secure communications to the LDAP server. Examples include `plain` (no encryption), `SSL/LDAPS` (encrypted from the start), and `StartTLS` (upgrade to encrypted communication once connected).", + "LDAP_FederationHomeServer_Field": "Federation Home Server field", + "LDAP_FederationHomeServer_Field_Description": "The Home Server can only be assigned on user creation. Changing this will have no effect on users that were already synced.", "If_you_didnt_try_to_login_in_your_account_please_ignore_this_email": "If you didn't try to login in your account please ignore this email.", "LDAP_Find_User_After_Login": "Find user after login", "LDAP_Find_User_After_Login_Description": "Will perform a search of the user's DN after bind to ensure the bind was successful preventing login with empty passwords when allowed by the AD configuration.",