From 85eb13b1f96a76439e44c3cfcb01c17f62fca47a Mon Sep 17 00:00:00 2001 From: Maarten van Schaik Date: Thu, 23 Jul 2015 15:03:01 +0200 Subject: [PATCH 1/3] Don't filter all falsy claims Sometimes you do want the value False, or 0, or any datetime value at midnight. (http://lwn.net/Articles/590299/) --- oidc_provider/lib/claims.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oidc_provider/lib/claims.py b/oidc_provider/lib/claims.py index 6863d6b..b01082c 100644 --- a/oidc_provider/lib/claims.py +++ b/oidc_provider/lib/claims.py @@ -53,7 +53,7 @@ class AbstractScopeClaims(object): aux_dic = dic.copy() for key, value in iter(dic.items()): - if not value: + if value is None or value == '': del aux_dic[key] elif type(value) is dict: aux_dic[key] = self._clean_dic(value) From 76efb6fc68885e97552d6627da99da08bf7ae9ee Mon Sep 17 00:00:00 2001 From: Maarten van Schaik Date: Fri, 24 Jul 2015 11:36:45 +0200 Subject: [PATCH 2/3] Add logout view to enable minimal session mgmt This implements a very small part of the OIDC session management as described in http://openid.net/specs/openid-connect-session-1_0-17.html#rfc.section.5. It does not implement the full session management (using iframes) and does not implement the registration and verification of logout redirect uri's. --- oidc_provider/lib/endpoints/discovery.py | 4 +++- oidc_provider/urls.py | 3 ++- oidc_provider/views.py | 8 +++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/oidc_provider/lib/endpoints/discovery.py b/oidc_provider/lib/endpoints/discovery.py index 130f598..5d892aa 100644 --- a/oidc_provider/lib/endpoints/discovery.py +++ b/oidc_provider/lib/endpoints/discovery.py @@ -1,4 +1,5 @@ from django.core.urlresolvers import reverse +from django.conf import settings as django_settings from oidc_provider import settings from oidc_provider.lib.utils.common import get_issuer @@ -17,6 +18,7 @@ class ProviderInfoEndpoint(object): dic['authorization_endpoint'] = SITE_URL + reverse('oidc_provider:authorize') dic['token_endpoint'] = SITE_URL + reverse('oidc_provider:token') dic['userinfo_endpoint'] = SITE_URL + reverse('oidc_provider:userinfo') + dic['end_session_endpoint'] = SITE_URL + reverse('oidc_provider:logout') from oidc_provider.models import Client types_supported = [x[0] for x in Client.RESPONSE_TYPE_CHOICES] @@ -29,4 +31,4 @@ class ProviderInfoEndpoint(object): # See: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes dic['subject_types_supported'] = ['public'] - return dic \ No newline at end of file + return dic diff --git a/oidc_provider/urls.py b/oidc_provider/urls.py index 8a9654e..8fd0756 100644 --- a/oidc_provider/urls.py +++ b/oidc_provider/urls.py @@ -8,8 +8,9 @@ urlpatterns = patterns('', url(r'^authorize/$', AuthorizeView.as_view(), name='authorize'), url(r'^token/$', csrf_exempt(TokenView.as_view()), name='token'), url(r'^userinfo/$', csrf_exempt(userinfo), name='userinfo'), + url(r'^logout/$', LogoutView.as_view(), name='logout'), url(r'^\.well-known/openid-configuration/$', ProviderInfoView.as_view(), name='provider_info'), url(r'^jwks/$', JwksView.as_view(), name='jwks'), -) \ No newline at end of file +) diff --git a/oidc_provider/views.py b/oidc_provider/views.py index c9bed77..4a0939b 100644 --- a/oidc_provider/views.py +++ b/oidc_provider/views.py @@ -1,7 +1,7 @@ import logging from Crypto.PublicKey import RSA -from django.contrib.auth.views import redirect_to_login +from django.contrib.auth.views import redirect_to_login, logout from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.shortcuts import render from django.template.loader import render_to_string @@ -172,3 +172,9 @@ class JwksView(View): }) return JsonResponse(dic) + + +class LogoutView(View): + def get(self, request, *args, **kwargs): + # We should actually verify if the requested redirect URI is safe + return logout(request, next_page=request.GET.get('post_logout_redirect_uri')) From 6e513cfb73857b8a15efadcaa66492599f749853 Mon Sep 17 00:00:00 2001 From: Maarten van Schaik Date: Fri, 24 Jul 2015 12:13:31 +0200 Subject: [PATCH 3/3] Add tests for logout view --- oidc_provider/tests/test_logout_endpoint.py | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 oidc_provider/tests/test_logout_endpoint.py diff --git a/oidc_provider/tests/test_logout_endpoint.py b/oidc_provider/tests/test_logout_endpoint.py new file mode 100644 index 0000000..2462699 --- /dev/null +++ b/oidc_provider/tests/test_logout_endpoint.py @@ -0,0 +1,30 @@ +from django.core.urlresolvers import reverse +from django.test import TestCase + +from oidc_provider.views import * +from oidc_provider.tests.app.utils import * + + +class UserInfoTestCase(TestCase): + def setUp(self): + self.user = create_fake_user() + self.url = reverse('oidc_provider:logout') + + def test_shows_logged_out_page(self): + response = self.client.get(self.url) + + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'registration/logged_out.html') + + def test_redirects(self): + response = self.client.get(self.url, data={'post_logout_redirect_uri': 'http://example.com/logged_out.html'}) + + self.assertRedirects(response, 'http://example.com/logged_out.html', + fetch_redirect_response=False) + + def test_user_is_logged_out(self): + self.assertTrue(self.client.login(username=self.user.username, password='1234')) + self.assertGreater(len(self.client.session.keys()), 0) + self.client.get(self.url) + self.assertEqual(len(self.client.session.keys()), 0) +