From 046ebf4e1a2eee7f349ab3db47a9ae0972f4f66c Mon Sep 17 00:00:00 2001 From: Chander Ganesan Date: Mon, 15 Apr 2019 17:19:52 -0400 Subject: [PATCH 1/3] User specified hostnames for redirect Post-login redirect URL's may often be generated from a client that is accessing an API, however the current implementation only allows redirect urls to point to the same server. This results in the need for confusing redirect-to-another-route-so-we-can-redirect elsewhere type cases. This fixes that by allowing the user to list a set of domains that may be redirected to. The default is to work as it has in the past - so no end user work is needed on upgrading. However, by specifying a SAML_ALLOWED_HOSTS parameter they can open up the allowable redirect hostnames. --- djangosaml2/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/djangosaml2/views.py b/djangosaml2/views.py index b328fff7..d9dbd99a 100644 --- a/djangosaml2/views.py +++ b/djangosaml2/views.py @@ -110,9 +110,15 @@ def login(request, came_from = settings.LOGIN_REDIRECT_URL # Ensure the user-originating redirection url is safe. - if not is_safe_url_compat(url=came_from, allowed_hosts={request.get_host()}): + # By setting SAML_ALLOWED_HOSTS in settings.py the user may provide a list of "allowed" + # hostnames for post-login redirects, much like one would specify ALLOWED_HOSTS . + # If this setting is absent, the default is to use the hostname that was used for the current + # request. + saml_allowed_hosts = set(getattr(settings, 'SAML_ALLOWED_HOSTS', [request.get_host()])) + if not is_safe_url_compat(url=came_from, allowed_hosts=saml_allowed_hosts): came_from = settings.LOGIN_REDIRECT_URL + # if the user is already authenticated that maybe because of two reasons: # A) He has this URL in two browser windows and in the other one he # has already initiated the authenticated session. From 9853690f435ce4143768a7a4c94fe19d6507a0a9 Mon Sep 17 00:00:00 2001 From: Chander Ganesan Date: Wed, 17 Apr 2019 14:49:06 +0000 Subject: [PATCH 2/3] Update to also address the other case where we check for safe redirect URLS --- djangosaml2/views.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/djangosaml2/views.py b/djangosaml2/views.py index d9dbd99a..6c309947 100644 --- a/djangosaml2/views.py +++ b/djangosaml2/views.py @@ -338,7 +338,14 @@ def assertion_consumer_service(request, if not relay_state: logger.warning('The RelayState parameter exists but is empty') relay_state = default_relay_state - if not is_safe_url_compat(url=relay_state, allowed_hosts={request.get_host()}): + + # Ensure the user-originating redirection url is safe. + # By setting SAML_ALLOWED_HOSTS in settings.py the user may provide a list of "allowed" + # hostnames for post-login redirects, much like one would specify ALLOWED_HOSTS . + # If this setting is absent, the default is to use the hostname that was used for the current + # request. + saml_allowed_hosts = set(getattr(settings, 'SAML_ALLOWED_HOSTS', [request.get_host()])) + if not is_safe_url_compat(url=relay_state, allowed_hosts=saml_allowed_hosts): relay_state = settings.LOGIN_REDIRECT_URL logger.debug('Redirecting to the RelayState: %s', relay_state) return HttpResponseRedirect(relay_state) From 1016cddb332375d02681c63e39f3e05e1391b3ca Mon Sep 17 00:00:00 2001 From: Chander Ganesan Date: Thu, 30 Apr 2020 13:43:26 -0400 Subject: [PATCH 3/3] Updates for SAML_ALLOWED_HOSTS changes Update the readme to include documentation regarding how SAML_ALLOWED_HOSTS works and is used. --- README.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.rst b/README.rst index 49b5557f..caefe97a 100644 --- a/README.rst +++ b/README.rst @@ -113,6 +113,24 @@ If you want to allow several authentication mechanisms in your project you should set the LOGIN_URL option to another view and put a link in such view to the ``/saml2/login/`` view. +Handling Post-Login Redirects +----------------------------- +It is often desireable for the client to maintain the URL state (or at least manage it) so that +the URL once authentication has completed is consistent with the desired application state (such +as retaining query parameters, etc.) By default, the HttpRequest objects get_host() method is used +to determine the hostname of the server, and redirect URL's are allowed so long as the destination +host matches the output of get_host(). However, in some cases it becomes desireable for additional +hostnames to be used for the post-login redirect. In such cases, the setting:: + + SAML_ALLOWED_HOSTS = [] + +May be set to a list of allowed post-login redirect hostnames (note, the URL components beyond the hostname +may be specified by the client - typically with the ?next= parameter.) + +In the absence of a ?next= parameter, the LOGIN_REDIRECT_URL setting will be used (assuming the destination hostname +either matches the output of get_host() or is included in the SAML_ALLOWED_HOSTS setting) + + Preferred Logout binding ------------------------ Use the following setting to choose your preferred binding for SP initiated logout requests::