From 8733ef9205092d38e857ccbe98c8986aadb81404 Mon Sep 17 00:00:00 2001 From: Armin Felder Date: Fri, 3 Jul 2020 19:40:30 +0200 Subject: [PATCH 1/4] add OAuth groups channels mapper --- .../server/custom_oauth_server.js | 23 ++++++++++++- app/custom-oauth/server/oauth_helpers.js | 33 ++++++++++++++++++- app/lib/server/methods/addOAuthService.js | 4 +++ app/lib/server/startup/oAuthServicesUpdate.js | 8 +++++ packages/rocketchat-i18n/i18n/en.i18n.json | 3 ++ 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/app/custom-oauth/server/custom_oauth_server.js b/app/custom-oauth/server/custom_oauth_server.js index c37e43b620470..ad0f6b92c1be5 100644 --- a/app/custom-oauth/server/custom_oauth_server.js +++ b/app/custom-oauth/server/custom_oauth_server.js @@ -7,7 +7,7 @@ import { ServiceConfiguration } from 'meteor/service-configuration'; import _ from 'underscore'; import { normalizers, fromTemplate, renameInvalidProperties } from './transform_helpers'; -import { mapRolesFromSSO, updateRolesFromSSO } from './oauth_helpers'; +import { mapRolesFromSSO, mapSSOGroupsToChannels, updateRolesFromSSO } from './oauth_helpers'; import { Logger } from '../../logger'; import { Users } from '../../models'; import { isURL } from '../../utils/lib/isURL'; @@ -79,8 +79,21 @@ export class CustomOAuth { this.avatarField = (options.avatarField || '').trim(); this.mergeUsers = options.mergeUsers; this.mergeRoles = options.mergeRoles || false; + this.mapChannels = options.mapChannels || false; this.rolesClaim = options.rolesClaim || 'roles'; + this.groupsClaim = options.groupsClaim || 'groups'; this.accessTokenParam = options.accessTokenParam; + this.channelsAdmin = options.channelsAdmin || 'rocket.cat'; + + if (this.mapChannels) { + const channelsMap = (options.channelsMap || '{}').trim(); + try { + this.channelsMap = JSON.parse(channelsMap); + } catch (err) { + logger.error(`Unexpected error : ${ err.message }`); + } + } + if (this.identityTokenSentVia == null || this.identityTokenSentVia === 'default') { this.identityTokenSentVia = this.tokenSentVia; @@ -330,6 +343,10 @@ export class CustomOAuth { updateRolesFromSSO(user, serviceData, this.rolesClaim); } + if (this.mapChannels) { + mapSSOGroupsToChannels(user, serviceData, this.groupsClaim, this.channelsMap, this.channelsAdmin); + } + // User already created or merged and has identical name as before if (user.services && user.services[serviceName] && user.services[serviceName].id === serviceData.id && user.name === serviceData.name) { return; @@ -372,6 +389,10 @@ export class CustomOAuth { user.roles = mapRolesFromSSO(user.services[this.name], this.rolesClaim); } + if (this.mapChannels) { + mapSSOGroupsToChannels(user, user.services[this.name], this.groupsClaim, this.channelsMap, this.channelsAdmin); + } + return true; }); } diff --git a/app/custom-oauth/server/oauth_helpers.js b/app/custom-oauth/server/oauth_helpers.js index 7b7a4abf9b08c..37aa85e360496 100644 --- a/app/custom-oauth/server/oauth_helpers.js +++ b/app/custom-oauth/server/oauth_helpers.js @@ -1,6 +1,9 @@ import { addUserRoles, removeUserFromRoles } from '../../authorization'; -import { Roles } from '../../models'; +import { Roles, Rooms } from '../../models'; +import { addUserToRoom, createRoom } from '../../lib/server/functions'; +import { Logger } from '../../logger'; +export const logger = new Logger('OAuth', {}); // Returns list of roles from SSO identity export function mapRolesFromSSO(identity, roleClaimName) { @@ -40,3 +43,31 @@ export function updateRolesFromSSO(user, identity, roleClaimName) { }); } } + +export function mapSSOGroupsToChannels(user, identity, groupClaimName, channelsMap, channelsAdmin) { + if (user && identity && groupClaimName) { + const groupsFromSSO = identity[groupClaimName] || []; + + for (const ssoGroup in channelsMap) { + if (typeof ssoGroup === 'string') { + let channels = channelsMap[ssoGroup]; + if (!Array.isArray(channels)) { + channels = [channels]; + } + for (const channel of channels) { + let room = Rooms.findOneByNonValidatedName(channel); + if (!room) { + room = createRoom('c', channel, channelsAdmin, [], false); + if (!room || !room.rid) { + logger.error(`could not create channel ${ channel }`); + return; + } + } + if (groupsFromSSO.includes(ssoGroup)) { + addUserToRoom(room._id, user); + } + } + } + } + } +} diff --git a/app/lib/server/methods/addOAuthService.js b/app/lib/server/methods/addOAuthService.js index 4852e5af1e7ff..5986b7e343e86 100644 --- a/app/lib/server/methods/addOAuthService.js +++ b/app/lib/server/methods/addOAuthService.js @@ -41,6 +41,10 @@ Meteor.methods({ settings.add(`Accounts_OAuth_Custom-${ name }-name_field` , '' , { type: 'string' , group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Name_Field', persistent: true }); settings.add(`Accounts_OAuth_Custom-${ name }-avatar_field` , '' , { type: 'string' , group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Avatar_Field', persistent: true }); settings.add(`Accounts_OAuth_Custom-${ name }-roles_claim` , 'roles' , { type: 'string' , group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Roles_Claim', persistent: true }); + settings.add(`Accounts_OAuth_Custom-${ name }-groups_claim` , 'groups' , { type: 'string' , group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Groups_Claim', persistent: true }); + settings.add(`Accounts_OAuth_Custom-${ name }-channels_admin` , 'rocket.cat' , { type: 'string' , group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Channel_Admin', persistent: true }); + settings.add(`Accounts_OAuth_Custom-${ name }-groups_channel_map` , '{\n\t"rocket-admin": "admin",\n\t"tech-support": "support"\n}' , { type: 'code' , multiline: true, code: 'application/json', group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Channel_Map', persistent: true }); + settings.add(`Accounts_OAuth_Custom-${ name }-map_channels` , false , { type: 'boolean', group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Map_Channels', persistent: true }); settings.add(`Accounts_OAuth_Custom-${ name }-merge_roles` , false , { type: 'boolean', group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Merge_Roles', persistent: true }); settings.add(`Accounts_OAuth_Custom-${ name }-merge_users` , false , { type: 'boolean', group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Merge_Users', persistent: true }); settings.add(`Accounts_OAuth_Custom-${ name }-show_button` , true , { type: 'boolean', group: 'OAuth', section: `Custom OAuth: ${ name }`, i18nLabel: 'Accounts_OAuth_Custom_Show_Button_On_Login_Page', persistent: true }); diff --git a/app/lib/server/startup/oAuthServicesUpdate.js b/app/lib/server/startup/oAuthServicesUpdate.js index 0374ad30c56f7..0e44c288fd0a6 100644 --- a/app/lib/server/startup/oAuthServicesUpdate.js +++ b/app/lib/server/startup/oAuthServicesUpdate.js @@ -51,7 +51,11 @@ function _OAuthServicesUpdate() { data.nameField = settings.get(`${ service.key }-name_field`); data.avatarField = settings.get(`${ service.key }-avatar_field`); data.rolesClaim = settings.get(`${ service.key }-roles_claim`); + data.groupsClaim = settings.get(`${ service.key }-groups_claim`); + data.channelsMap = settings.get(`${ service.key }-groups_channel_map`); + data.channelsAdmin = settings.get(`${ service.key }--channels_admin`); data.mergeUsers = settings.get(`${ service.key }-merge_users`); + data.mapChannels = settings.get(`${ service.key }-map_channels`); data.mergeRoles = settings.get(`${ service.key }-merge_roles`); data.showButton = settings.get(`${ service.key }-show_button`); new CustomOAuth(serviceName.toLowerCase(), { @@ -68,6 +72,10 @@ function _OAuthServicesUpdate() { nameField: data.nameField, avatarField: data.avatarField, rolesClaim: data.rolesClaim, + groupsClaim: data.groupsClaim, + mapChannels: data.mapChannels, + channelsMap: data.channelsMap, + channelsAdmin: data.channelsAdmin, mergeUsers: data.mergeUsers, mergeRoles: data.mergeRoles, accessTokenParam: data.accessTokenParam, diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index f7f93ee7cca61..0ef0195518b47 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -123,7 +123,10 @@ "Accounts_OAuth_Custom_Email_Field": "Email field", "Accounts_OAuth_Custom_Name_Field": "Name field", "Accounts_OAuth_Custom_Roles_Claim": "Roles/Groups field name", + "Accounts_OAuth_Custom_Groups_Claim": "Roles/Groups field for channel mapping", + "Accounts_OAuth_Custom_Channel_Map": "OAuth Group Channel Map", "Accounts_OAuth_Custom_Merge_Roles": "Merge Roles from SSO", + "Accounts_OAuth_Custom_Map_Channels": "Map Roles/Groups to channels", "Accounts_OAuth_Drupal": "Drupal Login Enabled", "Accounts_OAuth_Drupal_callback_url": "Drupal oAuth2 Redirect URI", "Accounts_OAuth_Drupal_id": "Drupal oAuth2 Client ID", From f3cf42b10da8433fe748fe24f086e7ae79c8c78d Mon Sep 17 00:00:00 2001 From: Armin Felder Date: Sat, 4 Jul 2020 14:15:52 +0200 Subject: [PATCH 2/4] mend --- packages/rocketchat-i18n/i18n/en.i18n.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 0ef0195518b47..4737017e56274 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -124,6 +124,7 @@ "Accounts_OAuth_Custom_Name_Field": "Name field", "Accounts_OAuth_Custom_Roles_Claim": "Roles/Groups field name", "Accounts_OAuth_Custom_Groups_Claim": "Roles/Groups field for channel mapping", + "Accounts_OAuth_Custom_Channel_Admin": "User Data Group Map", "Accounts_OAuth_Custom_Channel_Map": "OAuth Group Channel Map", "Accounts_OAuth_Custom_Merge_Roles": "Merge Roles from SSO", "Accounts_OAuth_Custom_Map_Channels": "Map Roles/Groups to channels", From 8fd0b5af9255bd0bc16e2a11a6513892c35c878d Mon Sep 17 00:00:00 2001 From: arminfelder Date: Wed, 21 Oct 2020 16:25:18 +0200 Subject: [PATCH 3/4] Update app/lib/server/startup/oAuthServicesUpdate.js Co-authored-by: pierre-lehnen-rc <55164754+pierre-lehnen-rc@users.noreply.github.com> --- app/lib/server/startup/oAuthServicesUpdate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/server/startup/oAuthServicesUpdate.js b/app/lib/server/startup/oAuthServicesUpdate.js index 554bb59aff89f..ccf826991deda 100644 --- a/app/lib/server/startup/oAuthServicesUpdate.js +++ b/app/lib/server/startup/oAuthServicesUpdate.js @@ -53,7 +53,7 @@ function _OAuthServicesUpdate() { data.rolesClaim = settings.get(`${ service.key }-roles_claim`); data.groupsClaim = settings.get(`${ service.key }-groups_claim`); data.channelsMap = settings.get(`${ service.key }-groups_channel_map`); - data.channelsAdmin = settings.get(`${ service.key }--channels_admin`); + data.channelsAdmin = settings.get(`${ service.key }-channels_admin`); data.mergeUsers = settings.get(`${ service.key }-merge_users`); data.mapChannels = settings.get(`${ service.key }-map_channels`); data.mergeRoles = settings.get(`${ service.key }-merge_roles`); From 5ee12908734e37d3db403a8f4ef5c817e5c647cb Mon Sep 17 00:00:00 2001 From: arminfelder Date: Wed, 21 Oct 2020 16:25:25 +0200 Subject: [PATCH 4/4] Update app/custom-oauth/server/oauth_helpers.js Co-authored-by: pierre-lehnen-rc <55164754+pierre-lehnen-rc@users.noreply.github.com> --- app/custom-oauth/server/oauth_helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/custom-oauth/server/oauth_helpers.js b/app/custom-oauth/server/oauth_helpers.js index 37aa85e360496..f00eea03b6b75 100644 --- a/app/custom-oauth/server/oauth_helpers.js +++ b/app/custom-oauth/server/oauth_helpers.js @@ -63,7 +63,7 @@ export function mapSSOGroupsToChannels(user, identity, groupClaimName, channelsM return; } } - if (groupsFromSSO.includes(ssoGroup)) { + if (Array.isArray(groupsFromSSO) && groupsFromSSO.includes(ssoGroup)) { addUserToRoom(room._id, user); } }