Skip to content

Commit

Permalink
Added base logout view (#18)
Browse files Browse the repository at this point in the history
ECOM-4607
  • Loading branch information
clintonb committed Jun 7, 2016
1 parent 4c79d27 commit e5727ed
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 1 deletion.
2 changes: 1 addition & 1 deletion auth_backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
These package is designed to be used primarily with Open edX Django projects, but should be compatible with non-edX
projects as well.
"""
__version__ = '0.2.3' # pragma: no cover
__version__ = '0.3.0' # pragma: no cover
53 changes: 53 additions & 0 deletions auth_backends/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
""" Tests for the views module. """

from django.conf.urls import url
from django.contrib.auth import get_user_model, get_user
from django.core.urlresolvers import reverse
from django.test import TestCase, override_settings

from auth_backends.views import LogoutRedirectBaseView

LOGOUT_REDIRECT_URL = 'https://www.example.com/logout/'
User = get_user_model()

urlpatterns = [
url(r'^logout/$', LogoutRedirectBaseView.as_view(url=LOGOUT_REDIRECT_URL), name='logout'),
]


@override_settings(ROOT_URLCONF=__name__)
class LogoutRedirectBaseViewTests(TestCase):
""" Tests for LogoutRedirectBaseView. """

def assert_authentication_status(self, is_authenticated):
""" Verifies the authentication status of the user attached to the test client. """
user = get_user(self.client)
self.assertEqual(user.is_authenticated(), is_authenticated)

def test_redirect_url(self):
""" Verify the view redirects to the correct URL. """
response = self.client.get(reverse('logout'))
self.assertRedirects(response, LOGOUT_REDIRECT_URL, fetch_redirect_response=False)

def test_x_frame_options_header(self):
""" Verify no X-Frame-Options header is set in the resposne. """
response = self.client.get(reverse('logout'))
self.assertNotIn('X-Frame-Options', response)

def test_logout(self):
""" Verify the user is logged out of the current session. """
self.client.logout()
self.assert_authentication_status(False)

password = 'test'
user = User.objects.create_user('test', password=password)
self.client.login(username=user.username, password=password)
self.assert_authentication_status(True)

self.client.get(reverse('logout'))
self.assert_authentication_status(False)

def test_no_redirect(self):
""" Verify the view does not redirect if the no_redirect querystring parameter is set. """
response = self.client.get(reverse('logout') + '?no_redirect=1')
self.assertEqual(response.status_code, 200)
34 changes: 34 additions & 0 deletions auth_backends/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
""" Authentication views. """

from django.contrib.auth import logout
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import RedirectView


class LogoutRedirectBaseView(RedirectView):
""" Base logout view for projects with single sign out/logout.
This is a base view. You MUST override `url` attribute or `get_redirect_url` method to make this view useful. See
the documentation for `RedirectView` for more info:
https://docs.djangoproject.com/en/1.9/ref/class-based-views/base/#redirectview.
If the `no_redirect` querystring argument is set, the view will not redirect. An empty 200 response will be
returned instead.
This view is intended to be used with Django projects that need to implement single sign out/logout. After their
session is destroyed, the user will be redirected to the specified logout page on the authorization server/identity
provider. Additionally, no X-Frame-Options header is set, allowing this page to be loaded in an iframe on the
authorization server's logout page. This allows signout to be triggered by the authorization server.
"""
permanent = False

@method_decorator(xframe_options_exempt)
def dispatch(self, request, *args, **kwargs):
logout(request)

if request.GET.get('no_redirect'):
return HttpResponse()

return super(LogoutRedirectBaseView, self).dispatch(request, *args, **kwargs)
12 changes: 12 additions & 0 deletions test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django_nose',
'auth_backends',
)
Expand All @@ -25,6 +26,17 @@
}
}

MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

SOCIAL_AUTH_EDX_OIDC_URL_ROOT = 'http://example.com'
Expand Down

0 comments on commit e5727ed

Please sign in to comment.