|
12 | 12 | import ldap3
|
13 | 13 | from ldap3.core.exceptions import LDAPException
|
14 | 14 |
|
| 15 | +from collections import defaultdict |
| 16 | + |
15 | 17 | from satosa.exception import SATOSAError
|
16 | 18 | from satosa.logging_util import satosa_logging
|
17 | 19 | from satosa.micro_services.base import ResponseMicroService
|
@@ -46,6 +48,7 @@ class LdapAttributeStore(ResponseMicroService):
|
46 | 48 | "ldap_to_internal_map": None,
|
47 | 49 | "on_ldap_search_result_empty": None,
|
48 | 50 | "ordered_identifier_candidates": None,
|
| 51 | + "overwrite_existing_attributes": True, |
49 | 52 | "search_base": None,
|
50 | 53 | "query_return_attributes": None,
|
51 | 54 | "search_return_attributes": None,
|
@@ -333,20 +336,35 @@ def _populate_attributes(self, config, record):
|
333 | 336 | """
|
334 | 337 | Use a record found in LDAP to populate attributes.
|
335 | 338 | """
|
| 339 | + |
| 340 | + ldap_attributes = record.get("attributes", None) |
| 341 | + if not ldap_attributes: |
| 342 | + msg = "No attributes returned with LDAP record" |
| 343 | + satosa_logging(logger, logging.DEBUG, msg, None) |
| 344 | + return |
| 345 | + |
336 | 346 | ldap_to_internal_map = (
|
337 | 347 | config["ldap_to_internal_map"]
|
338 | 348 | if config["ldap_to_internal_map"]
|
339 | 349 | # Deprecated configuration. Will be removed in future.
|
340 | 350 | else config["search_return_attributes"]
|
341 | 351 | )
|
342 | 352 |
|
343 |
| - new_attr_values = { |
344 |
| - internal_attr: value |
345 |
| - for attr, internal_attr in ldap_to_internal_map.items() |
346 |
| - for value in [record["attributes"].get(attr)] |
347 |
| - if value |
348 |
| - } |
349 |
| - return new_attr_values |
| 353 | + attributes = defaultdict(list) |
| 354 | + |
| 355 | + for attr, values in ldap_attributes.items(): |
| 356 | + internal_attr = ldap_to_internal_map.get(attr, None) |
| 357 | + if not internal_attr and ';' in attr: |
| 358 | + internal_attr = ldap_to_internal_map.get(attr.split(';')[0], |
| 359 | + None) |
| 360 | + |
| 361 | + if internal_attr and values: |
| 362 | + attributes[internal_attr].extend(values) |
| 363 | + msg = "Recording internal attribute {} with values {}" |
| 364 | + msg = msg.format(internal_attr, attributes[internal_attr]) |
| 365 | + satosa_logging(logger, logging.DEBUG, msg, None) |
| 366 | + |
| 367 | + return attributes |
350 | 368 |
|
351 | 369 | def _populate_input_for_name_id(self, config, record, data):
|
352 | 370 | """
|
@@ -399,7 +417,7 @@ def process(self, context, data):
|
399 | 417 | data.subject_id,
|
400 | 418 | data.subject_type,
|
401 | 419 | issuer,
|
402 |
| - data.attriutes, |
| 420 | + data.attributes, |
403 | 421 | )
|
404 | 422 | ]
|
405 | 423 | # If we have constructed a non empty value then add it as the next
|
@@ -506,8 +524,12 @@ def process(self, context, data):
|
506 | 524 |
|
507 | 525 | # Populate attributes as configured.
|
508 | 526 | new_attrs = self._populate_attributes(config, record)
|
509 |
| - msg = "Updating internal attributes with new values {}".format(new_attrs) |
510 |
| - satosa_logging(logger, logging.DEBUG, msg, None) |
| 527 | + |
| 528 | + overwrite = config["overwrite_existing_attributes"] |
| 529 | + for attr, values in new_attrs.items(): |
| 530 | + if not overwrite: |
| 531 | + values = list(set(data.attributes.get(attr, []) + values)) |
| 532 | + data.attributes[attr] = values |
511 | 533 |
|
512 | 534 | # Populate input for NameID if configured. SATOSA core does the
|
513 | 535 | # hashing of input to create a persistent NameID.
|
|
0 commit comments