2017-07-25 18:31:42 +02:00
|
|
|
try:
|
|
|
|
from unittest.mock import patch
|
|
|
|
except ImportError:
|
2024-01-25 15:33:24 +01:00
|
|
|
from unittest.mock import patch
|
2017-07-25 18:31:42 +02:00
|
|
|
|
2017-07-28 15:31:37 +02:00
|
|
|
from django.test import RequestFactory, override_settings
|
2024-01-25 15:33:24 +01:00
|
|
|
from django.urls import reverse
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
from allauth_cas.exceptions import CASAuthenticationError
|
2017-07-28 15:31:37 +02:00
|
|
|
from allauth_cas.test.testcases import CASTestCase, CASViewTestCase
|
2017-07-25 18:31:42 +02:00
|
|
|
from allauth_cas.views import CASView
|
|
|
|
|
|
|
|
from .example.views import ExampleCASAdapter
|
|
|
|
|
|
|
|
|
2017-07-28 15:31:37 +02:00
|
|
|
class CASAdapterTests(CASTestCase):
|
2017-07-25 18:31:42 +02:00
|
|
|
def setUp(self):
|
|
|
|
factory = RequestFactory()
|
2024-01-25 15:33:24 +01:00
|
|
|
self.request = factory.get("/path/")
|
2017-07-28 15:31:37 +02:00
|
|
|
self.request.session = {}
|
2017-07-25 18:31:42 +02:00
|
|
|
self.adapter = ExampleCASAdapter(self.request)
|
|
|
|
|
|
|
|
def test_get_service_url(self):
|
|
|
|
"""
|
|
|
|
Service url (used by CAS client) is the callback url.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
expected = "http://testserver/accounts/theid/login/callback/"
|
2017-07-25 18:31:42 +02:00
|
|
|
service_url = self.adapter.get_service_url(self.request)
|
|
|
|
self.assertEqual(expected, service_url)
|
|
|
|
|
|
|
|
def test_get_service_url_keep_next(self):
|
|
|
|
"""
|
|
|
|
Current GET paramater next is appended on service url.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
expected = "http://testserver/accounts/theid/login/callback/?next=%2Fnext%2F"
|
2017-07-25 18:31:42 +02:00
|
|
|
factory = RequestFactory()
|
2024-01-25 15:33:24 +01:00
|
|
|
request = factory.get("/path/", {"next": "/next/"})
|
2017-07-25 18:31:42 +02:00
|
|
|
adapter = ExampleCASAdapter(request)
|
|
|
|
service_url = adapter.get_service_url(request)
|
|
|
|
self.assertEqual(expected, service_url)
|
|
|
|
|
2017-07-28 15:31:37 +02:00
|
|
|
def test_renew(self):
|
|
|
|
"""
|
|
|
|
From an anonymous request, renew is False to let using the single
|
|
|
|
sign-on.
|
|
|
|
"""
|
|
|
|
self.assertFalse(self.adapter.renew)
|
|
|
|
|
|
|
|
def test_renew_authenticated(self):
|
|
|
|
"""
|
|
|
|
If user has been authenticated to the application through CAS, and
|
|
|
|
tries to reauthenticate, renew is set to True to opt-out the single
|
|
|
|
sign-on.
|
|
|
|
"""
|
|
|
|
r = self.client_cas_login(self.client)
|
|
|
|
adapter = ExampleCASAdapter(r.wsgi_request)
|
|
|
|
self.assertTrue(adapter.renew)
|
|
|
|
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
class CASViewTests(CASViewTestCase):
|
|
|
|
class BasicCASView(CASView):
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
factory = RequestFactory()
|
2024-01-25 15:33:24 +01:00
|
|
|
self.request = factory.get("/path/")
|
2017-07-28 15:31:37 +02:00
|
|
|
self.request.session = {}
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
self.cas_view = self.BasicCASView.adapter_view(ExampleCASAdapter)
|
|
|
|
|
|
|
|
def test_adapter_view(self):
|
|
|
|
"""
|
|
|
|
adapter_view prepares the func view from a class view.
|
|
|
|
"""
|
|
|
|
view = self.cas_view(
|
|
|
|
self.request,
|
2024-01-25 15:33:24 +01:00
|
|
|
"arg1",
|
|
|
|
"arg2",
|
|
|
|
kwarg1="kwarg1",
|
|
|
|
kwarg2="kwarg2",
|
2017-07-25 18:31:42 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIsInstance(view, CASView)
|
|
|
|
|
2017-09-16 01:58:09 +02:00
|
|
|
self.assertEqual(view.request, self.request)
|
2024-01-25 15:33:24 +01:00
|
|
|
self.assertTupleEqual(view.args, ("arg1", "arg2"))
|
|
|
|
self.assertDictEqual(
|
|
|
|
view.kwargs,
|
|
|
|
{
|
|
|
|
"kwarg1": "kwarg1",
|
|
|
|
"kwarg2": "kwarg2",
|
|
|
|
},
|
|
|
|
)
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
self.assertIsInstance(view.adapter, ExampleCASAdapter)
|
|
|
|
|
2024-01-25 15:33:24 +01:00
|
|
|
@patch("allauth_cas.views.cas.CASClient")
|
|
|
|
@override_settings(
|
|
|
|
SOCIALACCOUNT_PROVIDERS={
|
|
|
|
"theid": {
|
|
|
|
"AUTH_PARAMS": {"key": "value"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
2017-07-25 18:31:42 +02:00
|
|
|
def test_get_client(self, mock_casclient_class):
|
|
|
|
"""
|
|
|
|
get_client returns a CAS client, configured from settings.
|
|
|
|
"""
|
|
|
|
view = self.cas_view(self.request)
|
|
|
|
view.get_client(self.request)
|
|
|
|
|
|
|
|
mock_casclient_class.assert_called_once_with(
|
2024-01-25 15:33:24 +01:00
|
|
|
service_url="http://testserver/accounts/theid/login/callback/",
|
|
|
|
server_url="https://server.cas",
|
2017-07-25 18:31:42 +02:00
|
|
|
version=2,
|
|
|
|
renew=False,
|
2024-01-25 15:33:24 +01:00
|
|
|
extra_login_params={"key": "value"},
|
2017-07-25 18:31:42 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_render_error_on_failure(self):
|
|
|
|
"""
|
|
|
|
A common login failure page is rendered if CASAuthenticationError is
|
|
|
|
raised by dispatch.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
|
2017-07-25 18:31:42 +02:00
|
|
|
def dispatch_raise(self, request):
|
|
|
|
raise CASAuthenticationError("failure")
|
|
|
|
|
2024-01-25 15:33:24 +01:00
|
|
|
with patch.object(self.BasicCASView, "dispatch", dispatch_raise):
|
2017-07-25 18:31:42 +02:00
|
|
|
resp = self.cas_view(self.request)
|
|
|
|
self.assertLoginFailure(resp)
|
|
|
|
|
|
|
|
|
|
|
|
class CASLoginViewTests(CASViewTestCase):
|
|
|
|
def test_reverse(self):
|
|
|
|
"""
|
|
|
|
Login view name is "{provider_id}_login".
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
url = reverse("theid_login")
|
|
|
|
self.assertEqual("/accounts/theid/login/", url)
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
def test_execute(self):
|
|
|
|
"""
|
|
|
|
Login view redirects to the CAS server login url.
|
|
|
|
Service is the callback url, as absolute uri.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
r = self.client.get("/accounts/theid/login/")
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
expected = (
|
2024-01-25 15:33:24 +01:00
|
|
|
"https://server.cas/login?service=http%3A%2F%2Ftestserver%2F"
|
|
|
|
"accounts%2Ftheid%2Flogin%2Fcallback%2F"
|
2017-07-25 18:31:42 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
self.assertRedirects(r, expected, fetch_redirect_response=False)
|
|
|
|
|
|
|
|
def test_execute_keep_next(self):
|
|
|
|
"""
|
|
|
|
Current GET parameter 'next' is kept on service url.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
r = self.client.get("/accounts/theid/login/?next=/path/")
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
expected = (
|
2024-01-25 15:33:24 +01:00
|
|
|
"https://server.cas/login?service=http%3A%2F%2Ftestserver%2F"
|
|
|
|
"accounts%2Ftheid%2Flogin%2Fcallback%2F%3Fnext%3D%252Fpath%252F"
|
2017-07-25 18:31:42 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
self.assertRedirects(r, expected, fetch_redirect_response=False)
|
|
|
|
|
|
|
|
|
|
|
|
class CASCallbackViewTests(CASViewTestCase):
|
2017-09-16 01:58:09 +02:00
|
|
|
def setUp(self):
|
2024-01-25 15:33:24 +01:00
|
|
|
self.client.get("/accounts/theid/login/")
|
2017-09-16 01:58:09 +02:00
|
|
|
|
2017-07-25 18:31:42 +02:00
|
|
|
def test_reverse(self):
|
|
|
|
"""
|
|
|
|
Callback view name is "{provider_id}_callback".
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
url = reverse("theid_callback")
|
|
|
|
self.assertEqual("/accounts/theid/login/callback/", url)
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
def test_ticket_valid(self):
|
2018-10-21 15:20:23 +02:00
|
|
|
"""
|
2017-07-25 18:31:42 +02:00
|
|
|
If ticket is valid, the user is logged in.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
self.patch_cas_response(username="username", valid_ticket="123456")
|
|
|
|
r = self.client.get(
|
|
|
|
"/accounts/theid/login/callback/",
|
|
|
|
{
|
|
|
|
"ticket": "123456",
|
|
|
|
},
|
|
|
|
)
|
2017-07-25 18:31:42 +02:00
|
|
|
self.assertLoginSuccess(r)
|
|
|
|
|
|
|
|
def test_ticket_invalid(self):
|
|
|
|
"""
|
|
|
|
Login failure page is returned if the ticket is invalid.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
self.patch_cas_response(username="username", valid_ticket="123456")
|
|
|
|
r = self.client.get(
|
|
|
|
"/accounts/theid/login/callback/",
|
|
|
|
{
|
|
|
|
"ticket": "000000",
|
|
|
|
},
|
|
|
|
)
|
2017-07-25 18:31:42 +02:00
|
|
|
self.assertLoginFailure(r)
|
|
|
|
|
|
|
|
def test_ticket_missing(self):
|
|
|
|
"""
|
|
|
|
Login failure page is returned if request lacks a ticket.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
self.patch_cas_response(username="username", valid_ticket="123456")
|
|
|
|
r = self.client.get("/accounts/theid/login/callback/")
|
2017-07-25 18:31:42 +02:00
|
|
|
self.assertLoginFailure(r)
|
|
|
|
|
2018-10-21 15:20:23 +02:00
|
|
|
def test_attributes_is_none(self):
|
|
|
|
"""
|
|
|
|
Without extra attributes, CASClientV2 of python-cas returns None.
|
|
|
|
"""
|
|
|
|
self.patch_cas_response(
|
2024-01-25 15:33:24 +01:00
|
|
|
username="username", valid_ticket="123456", attributes=None
|
|
|
|
)
|
|
|
|
r = self.client.get(
|
|
|
|
"/accounts/theid/login/callback/",
|
|
|
|
{
|
|
|
|
"ticket": "123456",
|
|
|
|
},
|
2018-10-21 15:20:23 +02:00
|
|
|
)
|
|
|
|
self.assertLoginSuccess(r)
|
|
|
|
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
class CASLogoutViewTests(CASViewTestCase):
|
|
|
|
def test_reverse(self):
|
|
|
|
"""
|
|
|
|
Callback view name is "{provider_id}_logout".
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
url = reverse("theid_logout")
|
|
|
|
self.assertEqual("/accounts/theid/logout/", url)
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
def test_execute(self):
|
|
|
|
"""
|
|
|
|
Logout view redirects to the CAS server logout url.
|
|
|
|
Service is a url to here, as absolute uri.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
r = self.client.get("/accounts/theid/logout/")
|
2017-07-25 18:31:42 +02:00
|
|
|
|
2024-01-25 15:33:24 +01:00
|
|
|
expected = "https://server.cas/logout?url=http%3A%2F%2Ftestserver%2F"
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
self.assertRedirects(r, expected, fetch_redirect_response=False)
|
|
|
|
|
|
|
|
def test_execute_with_next(self):
|
|
|
|
"""
|
|
|
|
GET parameter 'next' is set as service url.
|
|
|
|
"""
|
2024-01-25 15:33:24 +01:00
|
|
|
r = self.client.get("/accounts/theid/logout/?next=/path/")
|
2017-07-25 18:31:42 +02:00
|
|
|
|
2024-01-25 15:33:24 +01:00
|
|
|
expected = "https://server.cas/logout?url=http%3A%2F%2Ftestserver%2Fpath%2F"
|
2017-07-25 18:31:42 +02:00
|
|
|
|
|
|
|
self.assertRedirects(r, expected, fetch_redirect_response=False)
|