From e16d4e294a094facaf8a1ba5286fbf867d4664f4 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 14 Mar 2014 15:18:17 +0100 Subject: [PATCH] add middleware for automatic authentication, add slo support --- authentic2_idp_ltpa/__init__.py | 14 +++++++++++ authentic2_idp_ltpa/adapter.py | 6 +++++ authentic2_idp_ltpa/app_settings.py | 1 + authentic2_idp_ltpa/middleware.py | 7 ++++++ authentic2_idp_ltpa/urls.py | 3 ++- authentic2_idp_ltpa/views.py | 36 +++++++++++++++++++++-------- 6 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 authentic2_idp_ltpa/middleware.py diff --git a/authentic2_idp_ltpa/__init__.py b/authentic2_idp_ltpa/__init__.py index 0a77178..835f775 100644 --- a/authentic2_idp_ltpa/__init__.py +++ b/authentic2_idp_ltpa/__init__.py @@ -8,6 +8,20 @@ class Plugin(object): def get_apps(self): return [__name__] + def logout_list(self, request): + if request.session.get('ltpa', False): + url = resolve('ltpa-logout') + ctx = { + 'needs_iframe': False, + 'name': 'Domino', + 'url': url, + 'iframe_timeout': 0, + } + content = render_to_string('idp/saml/logout_fragment.html', ctx) + return [content] + return [] + + from django.utils.six.moves import http_cookies import Cookie diff --git a/authentic2_idp_ltpa/adapter.py b/authentic2_idp_ltpa/adapter.py index f6419e1..b2ba32c 100644 --- a/authentic2_idp_ltpa/adapter.py +++ b/authentic2_idp_ltpa/adapter.py @@ -15,4 +15,10 @@ def get_adapter(): class UserAdapter(object): def get_username(self, request): + '''What username do we put in the token ?''' return request.user.username + + def can_add_token(self, request): + '''Can we generate a token ?''' + return request.user.is_authenticated() \ + and app_settings.USE_MIDDLEWARE diff --git a/authentic2_idp_ltpa/app_settings.py b/authentic2_idp_ltpa/app_settings.py index 31db3a1..df7fbc6 100644 --- a/authentic2_idp_ltpa/app_settings.py +++ b/authentic2_idp_ltpa/app_settings.py @@ -1,5 +1,6 @@ class AppSettings(object): __DEFAULTS = { + 'USE_MIDDLEWARE': True, 'TOKEN_DURATION': 8*3600, 'TOKEN_SECRET': None, 'COOKIE_NAME': 'LtpaToken', diff --git a/authentic2_idp_ltpa/middleware.py b/authentic2_idp_ltpa/middleware.py new file mode 100644 index 0000000..af499c1 --- /dev/null +++ b/authentic2_idp_ltpa/middleware.py @@ -0,0 +1,7 @@ +from . import views + +class LTPAMiddleware(object): + def process_response(self, request, response): + views.add_ltpa_token_to_response(request, response) + return response + diff --git a/authentic2_idp_ltpa/urls.py b/authentic2_idp_ltpa/urls.py index 4225ea8..bdfcc18 100644 --- a/authentic2_idp_ltpa/urls.py +++ b/authentic2_idp_ltpa/urls.py @@ -1,5 +1,6 @@ from django.conf.urls import patterns, url urlpatterns = patterns('authentic2_idp_ltpa.views', - url('^idp/ltpa/$', 'ltpa'), + url('^idp/ltpa/$', 'ltpa', name='ltpa-login'), + url('^idp/ltpa/logout/$', 'logout', name='ltpa-logout'), ) diff --git a/authentic2_idp_ltpa/views.py b/authentic2_idp_ltpa/views.py index 908059a..5c0e91b 100644 --- a/authentic2_idp_ltpa/views.py +++ b/authentic2_idp_ltpa/views.py @@ -1,22 +1,40 @@ +import urlparse + from django.core.exceptions import ImproperlyConfigured from django.http import HttpResponseRedirect from django.contrib.auth.decorators import login_required from django.contrib.auth import REDIRECT_FIELD_NAME -from . import app_settings, utils, adapter +from . import app_settings, utils, adapter as _adapter + +def add_ltpa_token_to_response(request, response): + adapter = _adapter.get_adapter() + if not adapter.can_add_token(): + return + if app_settings.TOKEN_SECRET is None: + raise ImproperlyConfigured('missing TOKEN_SECRET') + secret = utils.decode_secret(app_settings.TOKEN_SECRET) + user = adapter.get_username(request) + token = utils.generate_domino_ltpa_token(user, secret, + duration=app_settings.TOKEN_DURATION) + domain = app_settings.COOKIE_DOMAIN or \ + request.META['HTTP_HOST'].split(':')[0] + response.set_cookie(app_settings.COOKIE_NAME, token, domain=domain, + httponly=app_settings.COOKIE_HTTP_ONLY) + request.session['ltpa'] = True @login_required def ltpa(request): '''Ask for authentication then generate a cookie''' next_url = request.REQUEST[REDIRECT_FIELD_NAME] response = HttpResponseRedirect(next_url) - if app_settings.TOKEN_SECRET is None: - raise ImproperlyConfigured('missing TOKEN_SECRET') - secret = utils.decode_secret(app_settings.TOKEN_SECRET) - user = adapter.get_adapter().get_username(request) - token = utils.generate_domino_ltpa_token(user, secret, duration=app_settings.TOKEN_DURATION) - domain = app_settings.COOKIE_DOMAIN or request.META['HTTP_HOST'].split(':')[0] - response.set_cookie(app_settings.COOKIE_NAME, token, domain=domain, - httponly=app_settings.COOKIE_HTTP_ONLY) + add_ltpa_token_to_response(request, response) + return response + +def logout(request): + next_url = urlparse.urljoin(settings.STATIC_URL, 'authentic2/images/ok.png') + response = HttpResponseRedirect(next_url) + domain = app_settings.COOKIE_DOMAIN or request.META['HTTP_HOST'].split(':')[0] + response.delete_cookie(app_settings.COOKIE_NAME, domain=domain) return response