diff --git a/server/modules/authentication/ldap/authentication.js b/server/modules/authentication/ldap/authentication.js index 8f5a9817ab..29d2148220 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 8b0b1b2d05..193a9fc00f 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