From bf7383d8189c251377f28c2b73c72163da01985c Mon Sep 17 00:00:00 2001 From: "Pierre H. Lehnen" Date: Mon, 31 Mar 2025 17:34:15 -0300 Subject: [PATCH 1/9] add support for syncing federated users through ldap --- .../classes/converters/UserConverter.ts | 2 + apps/meteor/server/lib/ldap/Manager.ts | 48 +++++++++++++++++++ apps/meteor/server/settings/ldap.ts | 5 ++ .../core-typings/src/import/IImportUser.ts | 1 + packages/i18n/src/locales/en.i18n.json | 1 + 5 files changed, 57 insertions(+) diff --git a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts index 03f853832ef51..f4099697c5f6f 100644 --- a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts +++ b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts @@ -276,6 +276,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 = 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 1a7ecd479baeb..dfc5d5e2b9c0f 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -3009,6 +3009,7 @@ "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", "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.", From 30fc46c84cc9c986ef21ae6d08f556a9134b435d Mon Sep 17 00:00:00 2001 From: Pierre Date: Mon, 31 Mar 2025 18:04:48 -0300 Subject: [PATCH 2/9] LDAP checks --- .../importer/server/classes/converters/UserConverter.ts | 7 +++++-- packages/i18n/src/locales/en.i18n.json | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts index f4099697c5f6f..61f070e9eba82 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]); } diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index dfc5d5e2b9c0f..d35938a669df1 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -3010,6 +3010,7 @@ "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.", From 45d69dbdb1e60a1b6146da9640ca38bacb5efa1c Mon Sep 17 00:00:00 2001 From: "Pierre H. Lehnen" Date: Mon, 31 Mar 2025 20:23:28 -0300 Subject: [PATCH 3/9] fixed conditional --- .../app/importer/server/classes/converters/UserConverter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts index 61f070e9eba82..dfecc9ac9f2ea 100644 --- a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts +++ b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts @@ -259,7 +259,7 @@ export class UserConverter extends RecordConverter Date: Mon, 7 Apr 2025 17:45:14 -0300 Subject: [PATCH 4/9] changeset --- .changeset/stupid-rabbits-hide.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/stupid-rabbits-hide.md diff --git a/.changeset/stupid-rabbits-hide.md b/.changeset/stupid-rabbits-hide.md new file mode 100644 index 0000000000000..28154095baa6e --- /dev/null +++ b/.changeset/stupid-rabbits-hide.md @@ -0,0 +1,7 @@ +--- +'@rocket.chat/core-typings': patch +'@rocket.chat/i18n': patch +'@rocket.chat/meteor': patch +--- + +adds a new setting to allow syncing federated users data through LDAP From 9d46d396315f6563a856e8860e6f6f6c263f917e Mon Sep 17 00:00:00 2001 From: Pierre Date: Tue, 8 Apr 2025 15:02:39 -0300 Subject: [PATCH 5/9] error from cherry pick conflict --- apps/meteor/server/lib/ldap/Manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/server/lib/ldap/Manager.ts b/apps/meteor/server/lib/ldap/Manager.ts index 161cf80fd167a..668b2f9242cf8 100644 --- a/apps/meteor/server/lib/ldap/Manager.ts +++ b/apps/meteor/server/lib/ldap/Manager.ts @@ -521,7 +521,7 @@ export class LDAPManager { } const homeServerField = settings.get('LDAP_FederationHomeServer_Field'); - const homeServer = getLdapDynamicValue(ldapUser, homeServerField); + const homeServer = this.getLdapDynamicValue(ldapUser, homeServerField); if (!homeServer) { return; From 264976f4b0cf71eab2e1b50e47b6881a89f39447 Mon Sep 17 00:00:00 2001 From: Pierre Date: Tue, 8 Apr 2025 15:29:25 -0300 Subject: [PATCH 6/9] do not save federated usernames when updating users, even if there's a name --- .../app/importer/server/classes/converters/UserConverter.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts index dfecc9ac9f2ea..2e8683a30f8f4 100644 --- a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts +++ b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts @@ -300,7 +300,8 @@ export class UserConverter extends RecordConverter[0]); + const { username } = userData.federated ? {} : userData; + await saveUserIdentity({ _id, name: userData.name, username } as Parameters[0]); } if (userData.importIds.length) { From 3273c8aebc88c54a5a3e3ee0cbb019d973746efa Mon Sep 17 00:00:00 2001 From: Pierre Date: Tue, 8 Apr 2025 15:31:07 -0300 Subject: [PATCH 7/9] simplify condition --- .../app/importer/server/classes/converters/UserConverter.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts index 2e8683a30f8f4..0ff4f72a6f1c8 100644 --- a/apps/meteor/app/importer/server/classes/converters/UserConverter.ts +++ b/apps/meteor/app/importer/server/classes/converters/UserConverter.ts @@ -299,9 +299,9 @@ 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) { From e0c66ad35bd0fe77a2e3df9ccca280fcda3e2c97 Mon Sep 17 00:00:00 2001 From: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> Date: Thu, 10 Apr 2025 10:39:32 -0300 Subject: [PATCH 8/9] Update .changeset/stupid-rabbits-hide.md Co-authored-by: Debdut Chakraborty --- .changeset/stupid-rabbits-hide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/stupid-rabbits-hide.md b/.changeset/stupid-rabbits-hide.md index 28154095baa6e..6e9f1847a2b63 100644 --- a/.changeset/stupid-rabbits-hide.md +++ b/.changeset/stupid-rabbits-hide.md @@ -4,4 +4,4 @@ '@rocket.chat/meteor': patch --- -adds a new setting to allow syncing federated users data through LDAP +Adds a new setting to allow syncing federated users data through LDAP From 9841ef07c62d98282b31b72b1d21f96c8190d66c Mon Sep 17 00:00:00 2001 From: Marcos Spessatto Defendi Date: Fri, 11 Apr 2025 09:53:34 -0300 Subject: [PATCH 9/9] Update .changeset/stupid-rabbits-hide.md --- .changeset/stupid-rabbits-hide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/stupid-rabbits-hide.md b/.changeset/stupid-rabbits-hide.md index 6e9f1847a2b63..341fea6af5a5d 100644 --- a/.changeset/stupid-rabbits-hide.md +++ b/.changeset/stupid-rabbits-hide.md @@ -1,7 +1,7 @@ --- -'@rocket.chat/core-typings': patch -'@rocket.chat/i18n': patch -'@rocket.chat/meteor': patch +'@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