From 8fa771c4ce6b667d5c2b1de6b343977af4351644 Mon Sep 17 00:00:00 2001 From: Charlotte County Public Schools <119430841+icsinfo@users.noreply.github.com> Date: Sun, 29 Jan 2023 22:52:21 -0500 Subject: [PATCH] feat: set groups based on LDAP groups (#5903) * Add mapping ldap groups to wiki groups --------- Co-authored-by: Nicolas Giard --- .../authentication/ldap/authentication.js | 24 ++++++++++++- .../authentication/ldap/definition.yml | 36 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/server/modules/authentication/ldap/authentication.js b/server/modules/authentication/ldap/authentication.js index 8f5a9817..29d21482 100644 --- a/server/modules/authentication/ldap/authentication.js +++ b/server/modules/authentication/ldap/authentication.js @@ -19,6 +19,13 @@ module.exports = { searchBase: conf.searchBase, searchFilter: conf.searchFilter, tlsOptions: getTlsOptions(conf), + ...conf.mapGroups && { + groupSearchBase: conf.groupSearchBase, + groupSearchFilter: conf.groupSearchFilter, + groupSearchScope: conf.groupSearchScope, + groupDnProperty: conf.groupDnProperty, + groupSearchAttributes: [conf.groupNameField] + }, includeRaw: true }, usernameField: 'email', @@ -40,6 +47,21 @@ module.exports = { picture: _.get(profile, `_raw.${conf.mappingPicture}`, '') } }) + // map users LDAP groups to wiki groups with the same name, and remove any groups that don't match LDAP + if (conf.mapGroups) { + const ldapGroups = _.get(profile, '_groups') + if (ldapGroups && _.isArray(ldapGroups)) { + const groups = ldapGroups.map(g => g[conf.groupNameField]) + const currentGroups = (await user.$relatedQuery('groups').select('groups.id')).map(g => g.id) + const expectedGroups = Object.values(WIKI.auth.groups).filter(g => groups.includes(g.name)).map(g => g.id) + for (const groupId of _.difference(expectedGroups, currentGroups)) { + await user.$relatedQuery('groups').relate(groupId) + } + for (const groupId of _.difference(currentGroups, expectedGroups)) { + await user.$relatedQuery('groups').unrelate().where('groupId', groupId) + } + } + } cb(null, user) } catch (err) { if (WIKI.config.flags.ldapdebug) { @@ -59,7 +81,7 @@ function getTlsOptions(conf) { if (!conf.tlsCertPath) { return { - rejectUnauthorized: conf.verifyTLSCertificate, + rejectUnauthorized: conf.verifyTLSCertificate } } diff --git a/server/modules/authentication/ldap/definition.yml b/server/modules/authentication/ldap/definition.yml index 8b0b1b2d..193a9fc0 100644 --- a/server/modules/authentication/ldap/definition.yml +++ b/server/modules/authentication/ldap/definition.yml @@ -83,3 +83,39 @@ props: hint: The field storing the user avatar picture. Usually "jpegPhoto" or "thumbnailPhoto". maxWidth: 500 order: 23 + mapGroups: + type: Boolean + title: Map Groups + hint: Map groups matching names from the users LDAP/Active Directory groups. Group Search Base must also be defined for this to work. Note this will remove any groups the user has that doesn't match an LDAP/Active Directory group. + default: false + order: 24 + groupSearchBase: + type: String + title: Group Search Base + hint: The base DN from which to search for groups. + default: OU=groups,dc=example,dc=com + order: 25 + groupSearchFilter: + type: String + title: Group Search Filter + hint: LDAP search filter for groups. (member={{dn}}) will use the distinguished name of the user and will work in most cases. + default: (member={{dn}}) + order: 26 + groupSearchScope: + type: String + title: Group Search Scope + hint: How far from the Group Search Base to search for groups. sub (default) will search the entire subtree. base, will only search the Group Search Base dn. one, will search the Group Search Base dn and one additional level. + default: sub + order: 27 + groupDnProperty: + type: String + title: Group DN Property + hint: The property of user object to use in {{dn}} interpolation of Group Search Filter. + default: dn + order: 28 + groupNameField: + type: String + title: Group Name Field + hint: The field that contains the name of the LDAP group to match on, usually "name" or "cn". + default: name + order: 29