Merge pull request #2127 from rmoesbergen/master
Add support for nested group membership in ldap authenticator
This commit is contained in:
commit
c66c8f873e
|
@ -324,6 +324,7 @@ Here is an example LDAP configuration stanza you can add to your config. Adjust
|
||||||
LDAP_CACERT_FILE = '/opt/lemur/trusted.pem'
|
LDAP_CACERT_FILE = '/opt/lemur/trusted.pem'
|
||||||
LDAP_REQUIRED_GROUP = 'certificate-management-access'
|
LDAP_REQUIRED_GROUP = 'certificate-management-access'
|
||||||
LDAP_GROUPS_TO_ROLES = {'certificate-management-admin': 'admin', 'certificate-management-read-only': 'read-only'}
|
LDAP_GROUPS_TO_ROLES = {'certificate-management-admin': 'admin', 'certificate-management-read-only': 'read-only'}
|
||||||
|
LDAP_IS_ACTIVE_DIRECTORY = True
|
||||||
|
|
||||||
|
|
||||||
The lemur ldap module uses the `user principal name` (upn) of the authenticating user to bind. This is done once for each user at login time. The UPN is effectively the email address in AD/LDAP of the user. If the user doesn't provide the email address, it constructs one based on the username supplied (which should normally match the samAccountName) and the value provided by the config LDAP_EMAIL_DOMAIN.
|
The lemur ldap module uses the `user principal name` (upn) of the authenticating user to bind. This is done once for each user at login time. The UPN is effectively the email address in AD/LDAP of the user. If the user doesn't provide the email address, it constructs one based on the username supplied (which should normally match the samAccountName) and the value provided by the config LDAP_EMAIL_DOMAIN.
|
||||||
|
@ -406,6 +407,17 @@ The following LDAP options are not required, however TLS is always recommended.
|
||||||
LDAP_GROUPS_TO_ROLES = {'lemur_admins': 'admin', 'Lemur Team DL Group': 'team@example.com'}
|
LDAP_GROUPS_TO_ROLES = {'lemur_admins': 'admin', 'Lemur Team DL Group': 'team@example.com'}
|
||||||
|
|
||||||
|
|
||||||
|
.. data:: LDAP_IS_ACTIVE_DIRECTORY
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
When set to True, nested group memberships are supported, by searching for groups with the member:1.2.840.113556.1.4.1941 attribute set to the user DN.
|
||||||
|
When set to False, the list of groups will be determined by the 'memberof' attribute of the LDAP user logging in.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
LDAP_IS_ACTIVE_DIRECTORY = False
|
||||||
|
|
||||||
|
|
||||||
Authentication Providers
|
Authentication Providers
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ class LdapPrincipal():
|
||||||
self.ldap_default_role = current_app.config.get("LEMUR_DEFAULT_ROLE", None)
|
self.ldap_default_role = current_app.config.get("LEMUR_DEFAULT_ROLE", None)
|
||||||
self.ldap_required_group = current_app.config.get("LDAP_REQUIRED_GROUP", None)
|
self.ldap_required_group = current_app.config.get("LDAP_REQUIRED_GROUP", None)
|
||||||
self.ldap_groups_to_roles = current_app.config.get("LDAP_GROUPS_TO_ROLES", None)
|
self.ldap_groups_to_roles = current_app.config.get("LDAP_GROUPS_TO_ROLES", None)
|
||||||
|
self.ldap_is_active_directory = current_app.config.get("LDAP_IS_ACTIVE_DIRECTORY", False)
|
||||||
self.ldap_attrs = ['memberOf']
|
self.ldap_attrs = ['memberOf']
|
||||||
self.ldap_client = None
|
self.ldap_client = None
|
||||||
self.ldap_groups = None
|
self.ldap_groups = None
|
||||||
|
@ -168,11 +169,28 @@ class LdapPrincipal():
|
||||||
except ldap.LDAPError as e:
|
except ldap.LDAPError as e:
|
||||||
raise Exception("ldap error: {0}".format(e))
|
raise Exception("ldap error: {0}".format(e))
|
||||||
|
|
||||||
lgroups = self.ldap_client.search_s(self.ldap_base_dn,
|
if self.ldap_is_active_directory:
|
||||||
ldap.SCOPE_SUBTREE, ldap_filter, self.ldap_attrs)[0][1]['memberOf']
|
# Lookup user DN, needed to search for group membership
|
||||||
# lgroups is a list of utf-8 encoded strings
|
userdn = self.ldap_client.search_s(self.ldap_base_dn,
|
||||||
# convert to a single string of groups to allow matching
|
ldap.SCOPE_SUBTREE, ldap_filter,
|
||||||
self.ldap_groups = b''.join(lgroups).decode('ascii')
|
['distinguishedName'])[0][1]['distinguishedName'][0]
|
||||||
|
userdn = userdn.decode('utf-8')
|
||||||
|
# Search all groups that have the userDN as a member
|
||||||
|
groupfilter = '(&(objectclass=group)(member:1.2.840.113556.1.4.1941:={0}))'.format(userdn)
|
||||||
|
lgroups = self.ldap_client.search_s(self.ldap_base_dn, ldap.SCOPE_SUBTREE, groupfilter, ['cn'])
|
||||||
|
|
||||||
|
# Create a list of group CN's from the result
|
||||||
|
self.ldap_groups = []
|
||||||
|
for group in lgroups:
|
||||||
|
(dn, values) = group
|
||||||
|
self.ldap_groups.append(values['cn'][0].decode('ascii'))
|
||||||
|
else:
|
||||||
|
lgroups = self.ldap_client.search_s(self.ldap_base_dn,
|
||||||
|
ldap.SCOPE_SUBTREE, ldap_filter, self.ldap_attrs)[0][1]['memberOf']
|
||||||
|
# lgroups is a list of utf-8 encoded strings
|
||||||
|
# convert to a single string of groups to allow matching
|
||||||
|
self.ldap_groups = b''.join(lgroups).decode('ascii')
|
||||||
|
|
||||||
self.ldap_client.unbind()
|
self.ldap_client.unbind()
|
||||||
|
|
||||||
def _ldap_validate_conf(self):
|
def _ldap_validate_conf(self):
|
||||||
|
|
Loading…
Reference in New Issue