Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ Common configuration parameters:
| `attribute_profile` | string | `saml` | attribute profile to use for mapping attributes from/to response
| `entityid_endpoint` | bool | `true` | whether `entityid` should be used as a URL that serves the metadata xml document
| `acr_mapping` | dict | `None` | custom Authentication Context Class Reference
| `metadata_endpoint` | string | `my/metadata/endpoint.xml` | metadata endpoint, used for serving the metadata xml at a path of your choice. This config option acts independently from `entityid_endpoint`. |

The metadata could be loaded in multiple ways in the table above it's loaded from a static
file by using the key "local". It's also possible to load read the metadata from a remote URL.
Expand Down
6 changes: 1 addition & 5 deletions src/satosa/backends/saml2.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,11 +452,7 @@ def register_endpoints(self):
url_map.append(
("^%s$" % parsed_endp.path[1:], self.disco_response))

if self.expose_entityid_endpoint():
parsed_entity_id = urlparse(self.sp.config.entityid)
url_map.append(("^{0}".format(parsed_entity_id.path[1:]),
self._metadata_endpoint))

self.populate_entityid_urls(url_map, self.sp.config.entityid, self._metadata_endpoint)
return url_map

def get_metadata_desc(self):
Expand Down
22 changes: 22 additions & 0 deletions src/satosa/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import json
import logging
import uuid
from urllib.parse import urlparse
import warnings as _warnings

from saml2.s_utils import UnknownSystemEntity
Expand Down Expand Up @@ -306,6 +307,7 @@ def run(self, context):

class SAMLBaseModule(object):
KEY_ENTITYID_ENDPOINT = 'entityid_endpoint'
KEY_METADATA_ENDPOINT = 'metadata_endpoint'
KEY_ATTRIBUTE_PROFILE = 'attribute_profile'
KEY_ACR_MAPPING = 'acr_mapping'
VALUE_ATTRIBUTE_PROFILE_DEFAULT = 'saml'
Expand All @@ -321,6 +323,26 @@ def expose_entityid_endpoint(self):
value = self.config.get(self.KEY_ENTITYID_ENDPOINT, False)
return bool(value)

def metadata_endpoint(self):
value = self.config.get(self.KEY_METADATA_ENDPOINT, '')
return str(value)

def populate_entityid_urls(self, url_map, entity_id, metadata_endpoint_fct):
"""
Populate the endpoints that return the metadata

:param url_map: A list of tuples from endpoint to a metadata endpoint function
:param entity_id: The entity id defined in the config
:param metadata_endpoint_fct: The function that handles the metadata endpoint
"""
if self.expose_entityid_endpoint():
parsed_entity_id = urlparse(entity_id)
url_map.append(("^{0}".format(parsed_entity_id.path[1:]),
metadata_endpoint_fct))
metadata_endpoint = self.metadata_endpoint()
if metadata_endpoint:
url_map.append(("^{0}".format(metadata_endpoint),
metadata_endpoint_fct))

class SAMLEIDASBaseModule(SAMLBaseModule):
VALUE_ATTRIBUTE_PROFILE_DEFAULT = 'eidas'
Expand Down
7 changes: 1 addition & 6 deletions src/satosa/frontends/saml2.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,7 @@ def _register_endpoints(self, providers):
parsed_endp = urlparse(endp)
url_map.append(("(%s)/%s$" % (valid_providers, parsed_endp.path),
functools.partial(self.handle_authn_request, binding_in=binding)))

if self.expose_entityid_endpoint():
parsed_entity_id = urlparse(self.idp.config.entityid)
url_map.append(("^{0}".format(parsed_entity_id.path[1:]),
self._metadata_endpoint))

self.populate_entityid_urls(url_map, self.idp.config.entityid, self._metadata_endpoint)
return url_map

def _set_common_domain_cookie(self, internal_response, http_args, context):
Expand Down
8 changes: 6 additions & 2 deletions src/satosa/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import logging
import re
import pprint

from satosa.context import SATOSABadContextError
from satosa.exception import SATOSAError
Expand Down Expand Up @@ -38,6 +39,9 @@ class UnknownEndpoint(ValueError):
and handles the internal routing between frontends and backends.
"""

def __format_endpoint_urls(self, endpoints):
return pprint.pformat([{i : v['endpoints']} for i, v in endpoints.items()])

def __init__(self, frontends, backends, micro_services):
"""
:type frontends: dict[str, satosa.frontends.base.FrontendModule]
Expand Down Expand Up @@ -68,8 +72,8 @@ def __init__(self, frontends, backends, micro_services):
else:
self.micro_services = {}

logger.debug("Loaded backends with endpoints: {}".format(backends))
logger.debug("Loaded frontends with endpoints: {}".format(frontends))
logger.debug("Loaded backends with endpoints: {}".format(self.__format_endpoint_urls(self.backends)))
logger.debug("Loaded frontends with endpoints: {}".format(self.__format_endpoint_urls(self.frontends)))
logger.debug("Loaded micro services with endpoints: {}".format(micro_services))

def backend_routing(self, context):
Expand Down
20 changes: 20 additions & 0 deletions tests/satosa/frontends/test_saml2.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,26 @@ def get_path_from_url(url):
for endp in all_idp_endpoints:
assert any(p.match(endp) for p in compiled_regex)

def test_register_endpoints_metadata_endpoint_mapping(self, idp_conf):
"""
Tests the method register_endpoints when a metadata_endpoint is defined
"""
metadata_endpoint = "potato/test"
def get_path_from_url(url):
return urlparse(url).path.lstrip("/")

config = {"idp_config": idp_conf, "endpoints": ENDPOINTS,
"metadata_endpoint": metadata_endpoint, "entityid_endpoint": True }

base_url = self.construct_base_url_from_entity_id(idp_conf["entityid"])
samlfrontend = SAMLFrontend(lambda context, internal_req: (context, internal_req),
INTERNAL_ATTRIBUTES, config, base_url, "saml_frontend")

providers = ["foo", "bar"]
url_map = samlfrontend.register_endpoints(providers)
compiled_regex = [re.compile(regex) for regex, _ in url_map]
assert any(p.match(metadata_endpoint) for p in compiled_regex)

def test_handle_authn_request(self, context, idp_conf, sp_conf, internal_response):
samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf)
_, internal_req = samlfrontend.handle_authn_request(context, BINDING_HTTP_REDIRECT)
Expand Down