Skip to content

Commit

Permalink
feat: Add custom OAuth setting to allow merging users to others from …
Browse files Browse the repository at this point in the history
…distinct services (RocketChat#28783)

* Merge OAuth users with existing users from distinct services when setting is enabled

* Add changesets

* Fix changesets

* Apply requested changes

---------

Co-authored-by: Diego Sampaio <[email protected]>
Co-authored-by: Rafael Tapia <[email protected]>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Gabriel Casals <[email protected]>
  • Loading branch information
5 people authored Jul 3, 2023
1 parent eecd9fc commit 74aa677
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changeset/dirty-singers-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/rest-typings": minor
---

feat: Add custom OAuth setting to allow merging users to others from distinct services
9 changes: 7 additions & 2 deletions apps/meteor/app/custom-oauth/server/custom_oauth_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class CustomOAuth {
this.nameField = (options.nameField || '').trim();
this.avatarField = (options.avatarField || '').trim();
this.mergeUsers = options.mergeUsers;
this.mergeUsersDistinctServices = options.mergeUsersDistinctServices;
this.rolesClaim = options.rolesClaim || 'roles';
this.accessTokenParam = options.accessTokenParam;
this.channelsAdmin = options.channelsAdmin || 'rocket.cat';
Expand Down Expand Up @@ -333,9 +334,13 @@ export class CustomOAuth {
let user = undefined;

if (this.keyField === 'username') {
user = await Users.findOneByUsernameAndServiceNameIgnoringCase(serviceData.username, serviceData._id, serviceName);
user = this.mergeUsersDistinctServices
? await Users.findOneByUsernameIgnoringCase(serviceData.username)
: await Users.findOneByUsernameAndServiceNameIgnoringCase(serviceData.username, serviceData.id, serviceName);
} else if (this.keyField === 'email') {
user = await Users.findOneByEmailAddressAndServiceNameIgnoringCase(serviceData.email, serviceData._id, serviceName);
user = this.mergeUsersDistinctServices
? await Users.findOneByEmailAddress(serviceData.email)
: await Users.findOneByEmailAddressAndServiceNameIgnoringCase(serviceData.email, serviceData.id, serviceName);
}

if (!user) {
Expand Down
12 changes: 12 additions & 0 deletions apps/meteor/app/lib/server/functions/addOAuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,18 @@ export async function addOAuthService(name: string, values: { [k: string]: strin
i18nLabel: 'Accounts_OAuth_Custom_Merge_Users',
persistent: true,
});
await settingsRegistry.add(`Accounts_OAuth_Custom-${name}-merge_users_distinct_services`, values.mergeUsersDistinctServices || false, {
type: 'boolean',
group: 'OAuth',
section: `Custom OAuth: ${name}`,
i18nLabel: 'Accounts_OAuth_Custom_Merge_Users_Distinct_Services',
i18nDescription: 'Accounts_OAuth_Custom_Merge_Users_Distinct_Services_Description',
enableQuery: {
_id: `Accounts_OAuth_Custom-${name}-merge_users`,
value: true,
},
persistent: true,
});
await settingsRegistry.add(`Accounts_OAuth_Custom-${name}-show_button`, values.showButton || true, {
type: 'boolean',
group: 'OAuth',
Expand Down
3 changes: 3 additions & 0 deletions apps/meteor/app/lib/server/startup/oAuthServicesUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ async function _OAuthServicesUpdate() {
data.channelsMap = settings.get(`${key}-groups_channel_map`);
data.channelsAdmin = settings.get(`${key}-channels_admin`);
data.mergeUsers = settings.get(`${key}-merge_users`);
data.mergeUsersDistinctServices = settings.get(`${key}-merge_users_distinct_services`);
data.mapChannels = settings.get(`${key}-map_channels`);
data.mergeRoles = settings.get(`${key}-merge_roles`);
data.rolesToSync = settings.get(`${key}-roles_to_sync`);
Expand All @@ -78,6 +79,7 @@ async function _OAuthServicesUpdate() {
channelsMap: data.channelsMap,
channelsAdmin: data.channelsAdmin,
mergeUsers: data.mergeUsers,
mergeUsersDistinctServices: data.mergeUsersDistinctServices,
mergeRoles: data.mergeRoles,
rolesToSync: data.rolesToSync,
accessTokenParam: data.accessTokenParam,
Expand Down Expand Up @@ -187,6 +189,7 @@ async function customOAuthServicesInit() {
channelsMap: process.env[`${serviceKey}_groups_channel_map`],
channelsAdmin: process.env[`${serviceKey}_channels_admin`],
mergeUsers: process.env[`${serviceKey}_merge_users`] === 'true',
mergeUsersDistinctServices: process.env[`${serviceKey}_merge_users_distinct_services`] === 'true',
mapChannels: process.env[`${serviceKey}_map_channels`],
mergeRoles: process.env[`${serviceKey}_merge_roles`] === 'true',
rolesToSync: process.env[`${serviceKey}_roles_to_sync`],
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@
"Accounts_OAuth_Custom_Map_Channels": "Map Roles/Groups to channels",
"Accounts_OAuth_Custom_Merge_Roles": "Merge Roles from SSO",
"Accounts_OAuth_Custom_Merge_Users": "Merge users",
"Accounts_OAuth_Custom_Merge_Users_Distinct_Services": "Merge users from distinct services",
"Accounts_OAuth_Custom_Merge_Users_Distinct_Services_Description": "When the given key field matches the one of an existing user, allow users from this OAuth service to be merged to existing users regardless of their origin service.",
"Accounts_OAuth_Custom_Name_Field": "Name field",
"Accounts_OAuth_Custom_Roles_Claim": "Roles/Groups field name",
"Accounts_OAuth_Custom_Roles_To_Sync": "Roles to Sync",
Expand Down
27 changes: 27 additions & 0 deletions apps/meteor/server/startup/migrations/v300.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Settings } from '@rocket.chat/models';

import { settingsRegistry } from '../../../app/settings/server';
import { addMigration } from '../../lib/migrations';

addMigration({
version: 300,
async up() {
const customOauthServices = await Settings.find({ _id: /Accounts_OAuth_Custom-[^-]+$/ }, { projection: { _id: 1 } }).toArray();
const serviceNames = customOauthServices.map(({ _id }) => _id.replace('Accounts_OAuth_Custom-', ''));

for await (const serviceName of serviceNames) {
await settingsRegistry.add(`Accounts_OAuth_Custom-${serviceName}-merge_users_distinct_services`, false, {
type: 'boolean',
group: 'OAuth',
section: `Custom OAuth: ${serviceName}`,
i18nLabel: 'Accounts_OAuth_Custom_Merge_Users_Distinct_Services',
i18nDescription: 'Accounts_OAuth_Custom_Merge_Users_Distinct_Services_Description',
enableQuery: {
_id: `Accounts_OAuth_Custom-${serviceName}-merge_users`,
value: true,
},
persistent: true,
});
}
},
});
1 change: 1 addition & 0 deletions packages/rest-typings/src/v1/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type OauthCustomConfiguration = {
channelsMap: string;
channelsAdmin: string;
mergeUsers: boolean;
mergeUsersDistinctServices: boolean;
mergeRoles: boolean;
accessTokenParam: string;
showButton: boolean;
Expand Down

0 comments on commit 74aa677

Please sign in to comment.