From daf11a8c3ae99d28a5c63eb801dc3be4b0acafeb Mon Sep 17 00:00:00 2001
From: Art Lukyanchyk <artiom.lukyanchyk@hs-hannover.de>
Date: Mon, 21 Aug 2017 14:55:24 +0200
Subject: [PATCH] Implement proper redirects after log in and log out.

---
 ssoauth/templates/ssoauth/dev.html |  4 ++--
 ssoauth/urls.py                    |  2 +-
 ssoauth/views.py                   | 32 +++++++++++++++++++++---------
 3 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/ssoauth/templates/ssoauth/dev.html b/ssoauth/templates/ssoauth/dev.html
index 67d678d..bbf8937 100644
--- a/ssoauth/templates/ssoauth/dev.html
+++ b/ssoauth/templates/ssoauth/dev.html
@@ -34,8 +34,8 @@
                     </div>
                     <div class="column">
                         <h4 class="title">Production Actions</h4>
-                        <a class="button button-outline button-black" href="{% url "sso-login" %}">SSO Log in</a>
-                        <a class="button button-outline button-black" href="{% url "sso-logout" %}">Log out</a>
+                        <a class="button button-outline button-black" href="{% url "sso-login" %}?next={% url "sso-dev" %}">SSO Log in</a>
+                        <a class="button button-outline button-black" href="{% url "sso-logout" %}?next={% url "sso-dev" %}">Log out</a>
                         <p><i>These actions are used in production</i></p>
                     </div>
                 </div>
diff --git a/ssoauth/urls.py b/ssoauth/urls.py
index a291deb..f63ebf5 100644
--- a/ssoauth/urls.py
+++ b/ssoauth/urls.py
@@ -6,6 +6,6 @@ urlpatterns = (
     url(r"^logout/?$", views.LogOutView.as_view(), name="sso-logout"),
     url(r"^saml2/acs/?$", views.ACSAuthNView.as_view(), name="sso-saml2-acs"),
     url(r"^saml2/meta/?$", views.MetadataView.as_view(), name="sso-saml2-meta"),
-    url(r"^d(?:ev)?/?$", views.DevView.as_view(), name="sso-dev"),
+    url(r"^dev/?$", views.DevView.as_view(), name="sso-dev"),
 )
 
diff --git a/ssoauth/views.py b/ssoauth/views.py
index 2637756..d8785f4 100644
--- a/ssoauth/views.py
+++ b/ssoauth/views.py
@@ -5,13 +5,14 @@ from django.utils.decorators import method_decorator
 from django.views.decorators.csrf import csrf_exempt
 from django.contrib import auth as contrib_auth
 from django.contrib.auth import models as contrib_auth_models
+from django.contrib.auth import REDIRECT_FIELD_NAME
 from django import conf
 from django.core import exceptions
 from django import forms
+from django.views.decorators.cache import never_cache
 from . import logger
 from . import app_settings
 from . import auth_utils
-from onelogin.saml2.utils import OneLogin_Saml2_Utils
 from onelogin.saml2.auth import OneLogin_Saml2_Auth
 from collections import OrderedDict
 
@@ -50,26 +51,30 @@ class SAMLMixin:
         )
 
 
+@method_decorator(never_cache, "dispatch")
 class LogInView(SAMLMixin, View):
 
     def get(self, request, *args, **kwargs):
-        next_url = "{host}{relative}".format(
-            host=OneLogin_Saml2_Utils.get_self_url(self.get_onelogin_request_data(request)),
-            relative=urls.reverse("sso-saml2-meta"),
-        )
         auth = self.get_onelogin_auth(request)
-        login = auth.login(return_to=next_url)
+        login = auth.login(return_to=self.get_next_url(request))
         return http.HttpResponseRedirect(login)
 
+    @staticmethod
+    def get_next_url(request):
+        next_url = request.GET.get(REDIRECT_FIELD_NAME, None) or conf.settings.LOGIN_REDIRECT_URL or "/"
+        logger.debug("Will ask IDP to redirect after login to: {}".format(next_url))
+        return next_url
+
 
 class LogOutView(View):
 
     def get(self, request, *args, **kwargs):
         contrib_auth.logout(request)
-        logger.warning("Don't know what to do after logging out in Django.")
-        return http.HttpResponseRedirect(urls.reverse("sso-dev"))
+        next_url = request.GET.get(REDIRECT_FIELD_NAME, None) or conf.settings.LOGOUT_REDIRECT_URL or "/"
+        return http.HttpResponseRedirect(next_url)
 
 
+@method_decorator(never_cache, "dispatch")
 @method_decorator(csrf_exempt, "dispatch")
 class ACSAuthNView(SAMLMixin, View):
     """
@@ -84,11 +89,20 @@ class ACSAuthNView(SAMLMixin, View):
             self.log_in_user(request, auth)
             if conf.settings.DEBUG:
                 request.session["DEBUG_SAML2_ATTRS"] = auth.get_attributes()
-            return http.HttpResponseRedirect(urls.reverse("sso-dev"))
+            return http.HttpResponseRedirect(self.get_next_url(request))
         else:
             logger.error("Not authenticated. Errors: {0}".format(auth.get_errors()))
             raise exceptions.PermissionDenied()
 
+    @staticmethod
+    def get_next_url(request):
+        next_url = request.POST.get("RelayState", None)
+        if not next_url:
+            logger.warning("Did not receive RelayState (redirect target) from the IDP.")
+            next_url = conf.settings.LOGOUT_REDIRECT_URL or "/"
+        logger.debug("From ACS redirecting to {}".format(next_url))
+        return next_url
+
     def log_in_user(self, request, auth):
 
         def get_attr(attribute_name, nullable=False, multivalued=False):
-- 
GitLab