Skip to content

Commit 12d9f25

Browse files
Merge pull request #320 from skoranda/ldap_attribute_store_generalize_sp_override
Let the Ldap attribute store look up any entity rather than just services
2 parents 8daddcb + d244ffe commit 12d9f25

File tree

2 files changed

+52
-28
lines changed

2 files changed

+52
-28
lines changed

example/plugins/microservices/ldap_attribute_store.yaml.example

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ module: LdapAttributeStore
22
name: LdapAttributeStore
33
config:
44

5-
# The microservice may be configured per SP.
6-
# The configuration key is the entityID of the SP.
7-
# The empty key ("") specifies the default configuration
8-
"":
5+
# The microservice may be configured per entityID.
6+
# The configuration key is the entityID of the requesting SP,
7+
# the authenticating IdP, or the entityID of the CO virtual IdP.
8+
# The key "default" specifies the default configuration
9+
default:
910
ldap_url: ldaps://ldap.example.org
1011
bind_dn: cn=admin,dc=example,dc=org
1112
# Obtain bind password from environment variable LDAP_BIND_PASSWORD.
@@ -96,9 +97,13 @@ config:
9697
# from LDAP. The default is not to redirect.
9798
on_ldap_search_result_empty: https://my.vo.org/please/go/enroll
9899

99-
# The microservice may be configured per SP.
100-
# The configuration key is the entityID of the SP.
101-
# Αny missing parameters are looked up from the default configuration.
100+
# The microservice may be configured per entityID.
101+
# The configuration key is the entityID of the requesting SP,
102+
# the authenticating IdP, or the entityID of the CO virtual IdP.
103+
# When more than one configured entityID matches during a flow
104+
# the priority ordering is requesting SP, then authenticating IdP, then
105+
# CO virtual IdP. Αny missing parameters are taken from the
106+
# default configuration.
102107
https://sp.myserver.edu/shibboleth-sp:
103108
search_base: ou=People,o=MyVO,dc=example,dc=org
104109
search_return_attributes:
@@ -109,6 +114,9 @@ config:
109114
user_id_from_attrs:
110115
- uid
111116

112-
# The microservice may be configured to ignore a particular SP.
117+
https://federation-proxy.my.edu/satosa/idp/proxy/some_co
118+
search_base: ou=People,o=some_co,dc=example,dc=org
119+
120+
# The microservice may be configured to ignore a particular entityID.
113121
https://another.sp.myserver.edu:
114122
ignore: true

src/satosa/micro_services/ldap_attribute_store.py

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from satosa.exception import SATOSAError
1919
from satosa.micro_services.base import ResponseMicroService
2020
from satosa.response import Redirect
21+
from satosa.frontends.saml2 import SAMLVirtualCoFrontend
22+
from satosa.routing import STATE_KEY as ROUTING_STATE_KEY
2123

2224

2325
logger = logging.getLogger(__name__)
@@ -399,22 +401,36 @@ def process(self, context, data):
399401
Default interface for microservices. Process the input data for
400402
the input context.
401403
"""
402-
issuer = data.auth_info.issuer
404+
state = context.state
405+
session_id = lu.get_session_id(state)
406+
403407
requester = data.requester
404-
config = self.config.get(requester) or self.config["default"]
408+
issuer = data.auth_info.issuer
409+
410+
frontend_name = state.get(ROUTING_STATE_KEY)
411+
co_entity_id_key = SAMLVirtualCoFrontend.KEY_CO_ENTITY_ID
412+
co_entity_id = state.get(frontend_name, {}).get(co_entity_id_key)
413+
414+
entity_ids = [requester, issuer, co_entity_id, "default"]
415+
416+
config, entity_id = next((self.config.get(e), e)
417+
for e in entity_ids if self.config.get(e))
418+
405419
msg = {
406420
"message": "entityID for the involved entities",
407421
"requester": requester,
408422
"issuer": issuer,
409423
"config": self._filter_config(config),
410424
}
411-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
425+
if co_entity_id:
426+
msg["co_entity_id"] = co_entity_id
427+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
412428
logger.debug(logline)
413429

414-
# Ignore this SP entirely if so configured.
430+
# Ignore this entityID entirely if so configured.
415431
if config["ignore"]:
416-
msg = "Ignoring SP {}".format(requester)
417-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
432+
msg = "Ignoring entityID {}".format(entity_id)
433+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
418434
logger.info(logline)
419435
return super().process(context, data)
420436

@@ -439,7 +455,7 @@ def process(self, context, data):
439455
if filter_value
440456
]
441457
msg = {"message": "Search filters", "filter_values": filter_values}
442-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
458+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
443459
logger.debug(logline)
444460

445461
# Initialize an empty LDAP record. The first LDAP record found using
@@ -453,7 +469,7 @@ def process(self, context, data):
453469
"message": "LDAP server host",
454470
"server host": connection.server.host,
455471
}
456-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
472+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
457473
logger.debug(logline)
458474

459475
for filter_val in filter_values:
@@ -463,7 +479,7 @@ def process(self, context, data):
463479
"message": "LDAP query with constructed search filter",
464480
"search filter": search_filter,
465481
}
466-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
482+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
467483
logger.debug(logline)
468484

469485
attributes = (
@@ -485,14 +501,14 @@ def process(self, context, data):
485501
exp_msg = "Caught unhandled exception: {}".format(err)
486502

487503
if exp_msg:
488-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=exp_msg)
504+
logline = lu.LOG_FMT.format(id=session_id, message=exp_msg)
489505
logger.error(logline)
490506
return super().process(context, data)
491507

492508
if not results:
493509
msg = "Querying LDAP server: No results for {}."
494510
msg = msg.format(filter_val)
495-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
511+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
496512
logger.debug(logline)
497513
continue
498514

@@ -502,10 +518,10 @@ def process(self, context, data):
502518
responses = connection.get_response(results)[0]
503519

504520
msg = "Done querying LDAP server"
505-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
521+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
506522
logger.debug(logline)
507523
msg = "LDAP server returned {} records".format(len(responses))
508-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
524+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
509525
logger.info(logline)
510526

511527
# For now consider only the first record found (if any).
@@ -514,7 +530,7 @@ def process(self, context, data):
514530
msg = "LDAP server returned {} records using search filter"
515531
msg = msg + " value {}"
516532
msg = msg.format(len(responses), filter_val)
517-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
533+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
518534
logger.warning(logline)
519535
record = responses[0]
520536
break
@@ -524,7 +540,7 @@ def process(self, context, data):
524540
if config["clear_input_attributes"]:
525541
msg = "Clearing values for these input attributes: {}"
526542
msg = msg.format(data.attributes)
527-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
543+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
528544
logger.debug(logline)
529545
data.attributes = {}
530546

@@ -549,7 +565,7 @@ def process(self, context, data):
549565
"DN": record["dn"],
550566
"attributes": record["attributes"],
551567
}
552-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
568+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
553569
logger.debug(logline)
554570

555571
# Populate attributes as configured.
@@ -573,11 +589,11 @@ def process(self, context, data):
573589
# may use it if required.
574590
context.decorate(KEY_FOUND_LDAP_RECORD, record)
575591
msg = "Added record {} to context".format(record)
576-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
592+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
577593
logger.debug(logline)
578594
else:
579595
msg = "No record found in LDAP so no attributes will be added"
580-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
596+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
581597
logger.warning(logline)
582598
on_ldap_search_result_empty = config["on_ldap_search_result_empty"]
583599
if on_ldap_search_result_empty:
@@ -592,11 +608,11 @@ def process(self, context, data):
592608
encoded_idp_entity_id,
593609
)
594610
msg = "Redirecting to {}".format(url)
595-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
611+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
596612
logger.info(logline)
597613
return Redirect(url)
598614

599615
msg = "Returning data.attributes {}".format(data.attributes)
600-
logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
616+
logline = lu.LOG_FMT.format(id=session_id, message=msg)
601617
logger.debug(logline)
602618
return super().process(context, data)

0 commit comments

Comments
 (0)