Skip to content

Implement IdP Scoping parameter for SPs suggesting an entityID to a proxy #272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 13, 2021
Merged
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
13 changes: 10 additions & 3 deletions djangosaml2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
UnsolicitedResponse)
from saml2.s_utils import UnsupportedBinding
from saml2.saml import SCM_BEARER
from saml2.samlp import AuthnRequest
from saml2.samlp import AuthnRequest, IDPEntry, IDPList, Scoping
from saml2.sigver import MissingKey
from saml2.validate import ResponseLifetimeExceed, ToEarly
from saml2.xmldsig import ( # support for SHA1 is required by spec
Expand Down Expand Up @@ -192,6 +192,13 @@ def get(self, request, *args, **kwargs):
if selected_idp is None:
selected_idp = list(configured_idps.keys())[0]

# perform IdP Scoping if scoping param is present
idp_scoping = Scoping()
idp_scoping_param = request.GET.get('scoping', None)
if idp_scoping_param:
idp_scoping.idp_list = IDPList()
idp_scoping.idp_list.idp_entry.append(IDPEntry(provider_id = idp_scoping_param))

# choose a binding to try first
binding = getattr(settings, 'SAML_DEFAULT_BINDING', saml2.BINDING_HTTP_POST)
logger.debug(f'Trying binding {binding} for IDP {selected_idp}')
Expand Down Expand Up @@ -253,7 +260,7 @@ def get(self, request, *args, **kwargs):
try:
session_id, result = client.prepare_for_authenticate(
entityid=selected_idp, relay_state=next_path,
binding=binding, sign=sign_requests,
binding=binding, sign=sign_requests, scoping=idp_scoping,
**sso_kwargs)
except TypeError as e:
logger.error(f'{_msg}: {e}')
Expand Down Expand Up @@ -294,7 +301,7 @@ def get(self, request, *args, **kwargs):
try:
session_id, result = client.prepare_for_authenticate(
entityid=selected_idp, relay_state=next_path,
binding=binding)
binding=binding, scoping=idp_scoping)
except TypeError as e:
_msg = f"Can't prepare the authentication for {selected_idp}"
logger.error(f'{_msg}: {e}')
Expand Down
14 changes: 14 additions & 0 deletions docs/source/contents/setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,20 @@ For example::

see AARC Blueprint specs `here <https://zenodo.org/record/4596667/files/AARC-G061-A_specification_for_IdP_hinting.pdf>`_.


IdP scoping
===========
The SP can suggest an IdP to a proxy by using the Scoping and IDPList elements in a SAML AuthnRequest. This is done using the `scoping` parameter to the login URL.

``https://sp.example.org/saml2/login/?scoping=https://idp.example.org``

This parameter can be combined with the IdP parameter if multiple IdPs are present in the metadata, otherwise the first is used.

``https://sp.example.org/saml2/login/?scoping=https://idp.example.org&idp=https://proxy.example.com/metadata``

Currently there is support for a single IDPEntry in the IDPList.


Custom and dynamic configuration loading
========================================

Expand Down