add logout support

This commit is contained in:
Benjamin Dauvergne 2014-05-02 11:48:05 +02:00
parent 957657972a
commit 565d7a07f2
3 changed files with 89 additions and 2 deletions

1
README
View File

@ -33,6 +33,7 @@ Add mellon urls to your urls::
If SAML 2.0 should be your only authentication method you can define `mellon_login` as you main `LOGIN_URL`::
LOGIN_URL = 'mellon_login'
LOGOUT_URL = 'mellon_logout'
Yout metadata will be downloadable through HTTP on

View File

@ -111,3 +111,22 @@ def get_values(saml_attributes, name):
def get_parameter(idp, name):
return idp.get(name) or getattr(app_settings, name)
def create_logout(request):
server = create_server(request)
mellon_session = request.session.get('mellon_session', {})
entity_id = mellon_session.get('issuer')
session_index = mellon_session.get('session_index')
name_id_format = mellon_session.get('name_id_format')
name_id_content = mellon_session.get('name_id_content')
session_dump = render_to_string('mellon/session_dump.xml', {
'entity_id': entity_id,
'session_index': session_index,
'name_id_format': name_id_format,
'name_id_content': name_id_content,
})
logout = lasso.Logout(server)
if not app_settings.PRIVATE_KEY:
logout.setSignatureHint(lasso.PROFILE_SIGNATURE_HINT_FORBID)
logout.setSessionFromDump(session_dump)
return logout

View File

@ -5,7 +5,8 @@ from django.http import HttpResponseBadRequest, HttpResponseRedirect, HttpRespon
from django.contrib import auth
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
from django.shortcuts import render, redirect
from django.utils.http import same_origin
import lasso
@ -120,10 +121,76 @@ class LoginView(View):
login = csrf_exempt(LoginView.as_view())
class LogoutView(View):
pass
def get(self, request):
if 'SAMLRequest' in request.GET:
return self.idp_logout(request)
elif 'SAMLResponse' in request.GET:
return self.sp_logout_response(request)
else:
return self.sp_logout_request(request)
def idp_logout(self, request):
'''Handle logout request emitted by the IdP'''
logout = utils.create_logout(request)
try:
logout.processRequestMsg(request.META['QUERY_STRING'])
except lasso.Error, e:
return HttpResponseBadRequest('error processing logout request: %r' % e)
try:
logout.validateRequest()
except lasso.Error, e:
log.warning('error validating logout request: %r' % e)
issuer = request.session.get('mellon_session', {}).get('issuer')
if issuer == logout.remoteProviderId:
auth.logout(request)
try:
logout.buildResponseMsg()
except lasso.Error, e:
return HttpResponseBadRequest('error processing logout request: %r' % e)
return HttpResponseRedirect(logout.msgUrl)
def sp_logout_request(self, request):
'''Launch a logout request to the identity provider'''
next_url = request.GET.get('next') or settings.LOGIN_REDIRECT_URL
referer = request.META.get('HTTP_REFERER')
if not referer or same_origin(referer, request.build_absolute_uri()):
if request.user.is_authenticated():
issuer = request.session.get('mellon_session', {}).get('issuer')
if issuer:
logout = utils.create_logout(request)
try:
logout.initRequest(issuer, lasso.HTTP_METHOD_REDIRECT)
logout.msgRelayState = next_url
logout.buildRequestMsg()
except lasso.Error, e:
log.error('unable to initiate a logout request %r', e)
else:
return HttpResponseRedirect(logout.msgUrl)
auth.logout(request)
else:
log.warning('logout refused referer %r is not of the '
'same origin', referer)
return HttpResponseRedirect(next_url)
def sp_logout_response(self, request):
'''Launch a logout request to the identity provider'''
if 'SAMLResponse' not in request.GET:
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
logout = utils.create_logout(request)
try:
logout.processResponseMsg(request.GET['SAMLResponse'])
except lasso.Error, e:
log.error('unable to process a logout response %r', e)
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
next_url = logout.msgRelayState
if next_url and same_origin(next_url, request.build_absolute_uri()):
return redirect(next_url)
return redirect(settings.LOGIN_REDIRECT_URL)
logout = LogoutView.as_view()
def metadata(request):
metadata = utils.create_metadata(request)
return HttpResponse(metadata, content_type='text/xml')