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) 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/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) + 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 ea1108a..d440316 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'))