Skip to content

Commit 4135429

Browse files
Merge pull request #578 from bajwa-adobe/v2
Fix for 'invalid attribute type memberOf' at user-level LDAP request
2 parents ea6a758 + 37e01bb commit 4135429

File tree

4 files changed

+34
-5
lines changed

4 files changed

+34
-5
lines changed

docs/en/user-manual/advanced_configuration.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,17 @@ targeted Adobe groups.
742742
**Note:** Additional group mapping will fail if a multiple source groups
743743
map to the same target group.
744744

745+
### Configure 'dynamic_group_member_attribute'
746+
747+
From User Sync tool 2.5 onward, you are required to mention the `memberOf`
748+
LDAP attribute in `connector-ldap.yml`. There is no default value and if
749+
`addtional_groups` is defined but `dynamic_group_member_attribute` not defined,
750+
you would see an warning. Here is example:
751+
752+
```yaml
753+
dynamic_group_member_attribute: 'memberOf'
754+
```
755+
745756
### Additional Group Example
746757

747758
Suppose an Adobe Experience Manager customer would like

examples/config files - basic/connector-ldap.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ group_filter_format: "(&(|(objectCategory=group)(objectClass=groupOfNames)(objec
9292
# group_member_filter_format: "(memberOf:1.2.840.113556.1.4.1941:={group_dn})"
9393
group_member_filter_format: "(memberOf={group_dn})"
9494

95+
# (optional) configure dynamic_group_member_attribute with dynamic group mappings
96+
# From User Sync tool 2.5.0 onward, if additional_groups defined in user-sync-config.yml
97+
# then dynamic_group_member_attribute is required. Here you specify the LDAP attribute
98+
# used to filter groups mentioned in dynamic group mappings.
99+
#dynamic_group_member_attribute: "memberOf"
100+
95101
# (optional) two_steps_lookup (no default)
96102
#two_steps_lookup:
97103
# (required) group_member_attribute_name (no default)

user_sync/app.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,10 @@ def begin_work(config_loader):
337337
additional_group_filters = [r['source'] for r in additional_groups]
338338
if directory_connector is not None:
339339
directory_connector.state.additional_group_filters = additional_group_filters
340-
340+
# show error dynamic mappings enabled but 'dynamic_group_member_attribute' is not defined
341+
if additional_group_filters and directory_connector.state.options['dynamic_group_member_attribute'] is None:
342+
raise AssertionException(
343+
"Failed to enable dynamic group mappings. 'dynamic_group_member_attribute' is not defined in config")
341344
primary_name = '.primary' if secondary_umapi_configs else ''
342345
umapi_primary_connector = user_sync.connector.umapi.UmapiConnector(primary_name, primary_umapi_config)
343346
umapi_other_connectors = {}

user_sync/connector/directory_ldap.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ def get_options(caller_config):
137137
builder.set_string_value('user_given_name_format', six.text_type('{givenName}'))
138138
builder.set_string_value('user_surname_format', six.text_type('{sn}'))
139139
builder.set_string_value('user_country_code_format', six.text_type('{c}'))
140+
builder.set_string_value('dynamic_group_member_attribute', None)
140141
builder.set_string_value('user_identity_type', None)
141142
builder.set_int_value('search_page_size', 200)
142143
builder.set_string_value('logger_name', LDAPDirectoryConnector.name)
@@ -302,6 +303,9 @@ def iter_group_member_dns(self, group_dn, member_attribute, searched_dns=None):
302303
pass
303304

304305
def iter_users(self, base_dn, users_filter, extended_attributes):
306+
options = self.options
307+
dynamic_group_member_attribute = options['dynamic_group_member_attribute']
308+
305309
user_attribute_names = []
306310
user_attribute_names.extend(self.user_given_name_formatter.get_attribute_names())
307311
user_attribute_names.extend(self.user_surname_formatter.get_attribute_names())
@@ -310,7 +314,8 @@ def iter_users(self, base_dn, users_filter, extended_attributes):
310314
user_attribute_names.extend(self.user_email_formatter.get_attribute_names())
311315
user_attribute_names.extend(self.user_username_formatter.get_attribute_names())
312316
user_attribute_names.extend(self.user_domain_formatter.get_attribute_names())
313-
user_attribute_names.append(six.text_type('memberOf'))
317+
if dynamic_group_member_attribute is not None:
318+
user_attribute_names.append(six.text_type(dynamic_group_member_attribute))
314319

315320
extended_attributes = [six.text_type(attr) for attr in extended_attributes]
316321
extended_attributes = list(set(extended_attributes) - set(user_attribute_names))
@@ -389,7 +394,7 @@ def iter_users(self, base_dn, users_filter, extended_attributes):
389394
if c_value is not None:
390395
user['country'] = c_value.upper()
391396

392-
user['member_groups'] = self.get_member_groups(record) if self.additional_group_filters else []
397+
user['member_groups'] = self.get_member_groups(record, dynamic_group_member_attribute) if self.additional_group_filters else []
393398

394399
if extended_attributes is not None:
395400
for extended_attribute in extended_attributes:
@@ -403,15 +408,15 @@ def iter_users(self, base_dn, users_filter, extended_attributes):
403408

404409
yield (dn, user)
405410

406-
def get_member_groups(self, user):
411+
def get_member_groups(self, user, dynamic_group_member_attribute):
407412
"""
408413
Get a list of member group common names for user
409414
Assumes groups are contained in attribute memberOf
410415
:param user:
411416
:return:
412417
"""
413418
group_names = []
414-
groups = LDAPValueFormatter.get_attribute_value(user, 'memberOf')
419+
groups = LDAPValueFormatter.get_attribute_value(user, dynamic_group_member_attribute)
415420

416421
if not groups:
417422
return group_names
@@ -512,6 +517,10 @@ def is_dn_within_base_dn_scope(base_dn, dn):
512517
:param dn: str
513518
:return: bool
514519
"""
520+
# return true if base_dn is empty string such as global scope and no need to check user_dn is part of base_dn
521+
if (not (base_dn and base_dn.strip())):
522+
return True
523+
515524
split_base_dn = ldap3.utils.dn.parse_dn(base_dn.lower())
516525
split_dn = ldap3.utils.dn.parse_dn(dn.lower())
517526
if split_base_dn == split_dn[-len(split_base_dn):]:

0 commit comments

Comments
 (0)