From acc12948d911ced60261505e36348d5533ec6c63 Mon Sep 17 00:00:00 2001 From: Paul Marillonnet Date: Mon, 4 Dec 2017 17:41:07 +0100 Subject: [PATCH] WIP ldap_backend: groups to A2 roles mapping (#16523) --- src/authentic2/backends/ldap_backend.py | 56 +++++++++++++++++---------------- tests/test_ldap.py | 46 +++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/authentic2/backends/ldap_backend.py b/src/authentic2/backends/ldap_backend.py index ba43f64d..e2c75c05 100644 --- a/src/authentic2/backends/ldap_backend.py +++ b/src/authentic2/backends/ldap_backend.py @@ -221,13 +221,15 @@ class LDAPBackend(object): 'sync_ldap_users_filter': None, 'user_basedn': None, 'group_dn_template': None, - 'member_of_attribute': None, + 'member_of_attribute': None, # DEPRECATED + 'group_member_of_attribute': None, 'group_filter': '(&(member={user_dn})(objectClass=groupOfNames))', 'group': None, 'groupsu': None, 'groupstaff': None, 'groupactive': None, - 'group_mapping': (), + 'group_mapping': (), # DEPRECATED + 'group_to_role_mapping': (), 'replicas': True, 'email_field': 'mail', 'fname_field': 'givenName', @@ -521,39 +523,39 @@ class LDAPBackend(object): setattr(user, attr, v) user._changed = True - def populate_groups_by_mapping(self, user, dn, conn, block, group_dns): - '''Assign group to user based on a mapping from group DNs''' - group_mapping = block['group_mapping'] - if not group_mapping: + def populate_roles_by_mapping(self, user, dn, conn, block, role_dns): + '''Assign role to user based on a mapping from group DNs''' + group_to_role_mapping = block.get('group_to_role_mapping') + if not group_to_role_mapping: return if not user.pk: user.save() user._changed = False - groups = user.groups.all() - for dn, group_names in group_mapping: - for group_name in group_names: - group = self.get_group_by_name(block, group_name) - if group is None: + roles = user.roles.all() + for dn, role_names in group_to_role_mapping: + for role_name in role_names: + role = self.get_role_by_name(block, role_name) + if role is None: continue - # Add missing groups - if dn in group_dns and group not in groups: - user.groups.add(group) - # Remove extra groups - elif dn not in group_dns and group in groups: - user.groups.remove(group) + # Add missing roles + if dn in role_dns and role not in roles: + user.roles.add(role) + # Remove extra roles + elif dn not in role_dns and role in roles: + user.roles.remove(role) def get_ldap_group_dns(self, user, dn, conn, block, attributes): '''Retrieve group DNs from the LDAP by attributes (memberOf) or by filter. ''' group_base_dn = block.get('group_basedn', block['basedn']) - member_of_attribute = block['member_of_attribute'] + group_member_of_attribute = block['group_member_of_attribute'] group_filter = block['group_filter'] group_dns = set() - if member_of_attribute: - member_of_attribute = str(member_of_attribute) - results = conn.search_s(dn, ldap.SCOPE_BASE, '', [member_of_attribute]) - group_dns.update(results[0][1].get(member_of_attribute, [])) + if group_member_of_attribute: + group_member_of_attribute = str(group_member_of_attribute) + results = conn.search_s(dn, ldap.SCOPE_BASE, '', [group_member_of_attribute]) + group_dns.update(results[0][1].get(group_member_of_attribute, [])) if group_filter: group_filter = str(group_filter) params = attributes.copy() @@ -568,11 +570,11 @@ class LDAPBackend(object): group_dns.update(dn for dn, attributes in results if dn) return group_dns - def populate_user_groups(self, user, dn, conn, block, attributes): + def populate_user_roles(self, user, dn, conn, block, attributes): group_dns = self.get_ldap_group_dns(user, dn, conn, block, attributes) - log.debug('groups for dn %r: %r', dn, group_dns) - self.populate_admin_flags_by_group(user, block, group_dns) - self.populate_groups_by_mapping(user, dn, conn, block, group_dns) + log.debug('roles for dn %r: %r', dn, group_dns) + # Admin flags by roles ? + self.populate_roles_by_mapping(user, dn, conn, block, group_dns) def get_group_by_name(self, block, group_name, create=None): '''Obtain a Django group''' @@ -648,7 +650,7 @@ class LDAPBackend(object): self.update_user_identifiers(user, username, block, attributes) self.populate_mandatory_groups(user, block) self.populate_mandatory_roles(user, block) - self.populate_user_groups(user, dn, conn, block, attributes) + self.populate_user_roles(user, dn, conn, block, attributes) def populate_user_ou(self, user, dn, conn, block, attributes): '''Assign LDAP user to an ou, the default one if ou_slug setting is diff --git a/tests/test_ldap.py b/tests/test_ldap.py index 1ab923bf..9248c236 100644 --- a/tests/test_ldap.py +++ b/tests/test_ldap.py @@ -272,6 +272,52 @@ def test_posix_group_mapping(slapd, settings, client): @pytest.mark.django_db +def test_group_to_role_mapping(slapd, settings, client): + from authentic2.a2_rbac.models import Role + + settings.LDAP_AUTH_SETTINGS = [{ + 'url': [slapd.ldap_url], + 'basedn': 'o=orga', + 'use_tls': False, + 'create_role': True, + 'group_to_role_mapping': [ + ('cn=group1,o=orga', ['Group1']), + ], + }] + assert Role.objects.filter(name='Group1').count() == 0 + response = client.post('/login/', {'login-password-submit': '1', + 'username': USERNAME, + 'password': PASS}, follow=True) + assert Role.objects.filter(name='Group1').count() == 1 + assert response.context['user'].username == u'%s@ldap' % USERNAME + assert response.context['user'].roles.count() == 1 + + +@pytest.mark.django_db +def test_posix_group_to_role_mapping(slapd, settings, client): + from authentic2.a2_rbac.models import Role + + settings.LDAP_AUTH_SETTINGS = [{ + 'url': [slapd.ldap_url], + 'basedn': 'o=orga', + 'use_tls': False, + 'create_role': True, + 'group_to_role_mapping': [ + ('cn=group2,o=orga', ['Group2']), + ], + 'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', + }] + assert Role.objects.filter(name='Group2').count() == 0 + response = client.post('/login/', {'login-password-submit': '1', + 'username': USERNAME, + 'password': PASS}, follow=True) + assert Role.objects.filter(name='Group2').count() == 1 + assert response.context['user'].username == u'%s@ldap' % USERNAME + assert response.context['user'].roles.count() == 1 + + + +@pytest.mark.django_db def test_group_su(slapd, settings, client): from django.contrib.auth.models import Group -- 2.11.0