Skip to content

Commit 86c5eae

Browse files
Merge pull request #103 from skoranda/user_id_from_attrs
NameID input from attributes for LDAP attribute store
2 parents 2daaaa0 + e9ba69d commit 86c5eae

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

doc/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ correct functionality.
527527
An identifier such as eduPersonPrincipalName asserted by an IdP can be used to look up a person record
528528
in an LDAP directory to find attributes to assert about the authenticated user to the SP. The identifier
529529
to consume from the IdP, the LDAP directory details, and the mapping of attributes found in the
530-
directory may all be confingured on a per-SP basis. To use the
530+
directory may all be confingured on a per-SP basis. The input to use when hashing to create a
531+
persistent NameID may also be obtained from attributes returned from the LDAP directory. To use the
531532
LDAP microservice install the extra necessary dependencies with `pip install satosa[ldap]` and then see the
532533
[example config](../example/plugins/microservices/ldap_attribute_store.yaml.example).
533534

example/plugins/microservices/ldap_attribute_store.yaml.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ config:
1818
# Whether to clear values for attributes incoming
1919
# to this microservice. Default is no or false.
2020
clear_input_attributes: no
21+
# List of LDAP attributes to use as input to hashing to create
22+
# NameID.
23+
user_id_from_attrs:
24+
- employeeNumber
2125
# Configuration may also be done per-SP with any
2226
# missing parameters taken from the default if any.
2327
# The configuration key is the entityID of the SP.
@@ -26,3 +30,5 @@ config:
2630
https://sp.myserver.edu/shibboleth-sp
2731
search_base: ou=People,o=MyVO,dc=example,dc=org
2832
eduPersonPrincipalName: employeenumber
33+
user_id_from_attrs:
34+
- uid

src/satosa/micro_services/ldap_attribute_store.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ def process(self, context, data):
9191
clear_input_attributes = self.config['clear_input_attributes']
9292
else:
9393
clear_input_attributes = False
94+
if 'user_id_from_attrs' in config:
95+
user_id_from_attrs = config['user_id_from_attrs']
96+
elif 'user_id_from_attrs' in self.config:
97+
user_id_from_attrs = self.config['user_id_from_attrs']
98+
else:
99+
user_id_from_attrs = []
94100

95101
except KeyError as err:
96102
satosa_logging(logger, logging.ERROR, "{} Configuration '{}' is missing".format(logprefix, err), context.state)
@@ -153,15 +159,41 @@ def process(self, context, data):
153159
satosa_logging(logger, logging.DEBUG, "{} Clearing values for these input attributes: {}".format(logprefix, data.attributes), context.state)
154160
data.attributes = {}
155161

156-
# Use a found record, if any, to populate attributes
162+
# Use a found record, if any, to populate attributes and input for NameID
157163
if record:
158164
satosa_logging(logger, logging.DEBUG, "{} Using record with DN {}".format(logprefix, record["dn"]), context.state)
159165
satosa_logging(logger, logging.DEBUG, "{} Record with DN {} has attributes {}".format(logprefix, record["dn"], record["attributes"]), context.state)
166+
167+
# Populate attributes as configured.
160168
for attr in search_return_attributes.keys():
161169
if attr in record["attributes"]:
162170
data.attributes[search_return_attributes[attr]] = record["attributes"][attr]
163171
satosa_logging(logger, logging.DEBUG, "{} Setting internal attribute {} with values {}".format(logprefix, search_return_attributes[attr], record["attributes"][attr]), context.state)
164172

173+
# Populate input for NameID if configured. SATOSA core does the hashing of input
174+
# to create a persistent NameID.
175+
if user_id_from_attrs:
176+
userId = ""
177+
for attr in user_id_from_attrs:
178+
if attr in record["attributes"]:
179+
value = record["attributes"][attr]
180+
if isinstance(value, list):
181+
# Use a default sort to ensure some predictability since the
182+
# LDAP directory server may return multi-valued attributes
183+
# in any order.
184+
value.sort()
185+
for v in value:
186+
userId += v
187+
satosa_logging(logger, logging.DEBUG, "{} Added attribute {} with value {} to input for NameID".format(logprefix, attr, v), context.state)
188+
else:
189+
userId += value
190+
satosa_logging(logger, logging.DEBUG, "{} Added attribute {} with value {} to input for NameID".format(logprefix, attr, value), context.state)
191+
if not userId:
192+
satosa_logging(logger, logging.WARNING, "{} Input for NameID is empty so not overriding default".format(logprefix), context.state)
193+
else:
194+
data.user_id = userId
195+
satosa_logging(logger, logging.DEBUG, "{} Input for NameID is {}".format(logprefix, data.user_id), context.state)
196+
165197
else:
166198
satosa_logging(logger, logging.WARN, "{} No record found in LDAP so no attributes will be added".format(logprefix), context.state)
167199

0 commit comments

Comments
 (0)