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:: diff --git a/djangosaml2/views.py b/djangosaml2/views.py index 37be9dc3..bbb0b5d0 100644 --- a/djangosaml2/views.py +++ b/djangosaml2/views.py @@ -105,9 +105,16 @@ def login(request, came_from = settings.LOGIN_REDIRECT_URL # Ensure the user-originating redirection url is safe. - if not is_safe_url(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(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. @@ -348,7 +355,15 @@ 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(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(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)