import pytest
from django.core.exceptions import ImproperlyConfigured
from django.test import RequestFactory
from django_cas_ng import backends
[docs]@pytest.mark.django_db
def test_backend_authentication_creating_a_user(monkeypatch, django_user_model):
"""
Test the case where CAS authentication is creating a new user.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'ticket': ticket, 'service': service}, None
# we mock out the verify method so that we can bypass the external http
# calls needed for real authentication since we are testing the logic
# around authentication.
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
# sanity check
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
backend = backends.CASBackend()
user = backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is not None
assert user.username == 'test@example.com'
assert django_user_model.objects.filter(
username='test@example.com',
).exists()
[docs]def test_backend_authentication_do_not_create_user(monkeypatch, django_user_model, settings):
"""
Test the case where CAS authentication is not creating a new user.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'ticket': ticket, 'service': service}, None
# we mock out the verify method so that we can bypass the external http
# calls needed for real authentication since we are testing the logic
# around authentication.
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
# sanity check
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
settings.CAS_CREATE_USER = False
backend = backends.CASBackend()
user = backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is None
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
[docs]@pytest.mark.django_db
def test_backend_for_existing_user(monkeypatch, django_user_model):
"""
Test the case where CAS authenticates an existing user.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'ticket': ticket, 'service': service}, None
# we mock out the verify method so that we can bypass the external http
# calls needed for real authentication since we are testing the logic
# around authentication.
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
existing_user = django_user_model.objects.create_user('test@example.com', '')
backend = backends.CASBackend()
user = backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is not None
assert user.username == 'test@example.com'
assert user == existing_user
[docs]@pytest.mark.django_db
def test_backend_for_existing_user_no_request(monkeypatch, django_user_model):
"""
Test the case where CAS authenticates an existing user, but request argument is None.
"""
def mock_verify(ticket, service):
return 'test@example.com', {'ticket': ticket, 'service': service}, None
# we mock out the verify method so that we can bypass the external http
# calls needed for real authentication since we are testing the logic
# around authentication.
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
existing_user = django_user_model.objects.create_user('test@example.com', '')
backend = backends.CASBackend()
user = backend.authenticate(
None, ticket='fake-ticket', service='fake-service',
)
assert user is not None
assert user.username == 'test@example.com'
assert user == existing_user
[docs]@pytest.mark.django_db
def test_backend_for_failed_auth(monkeypatch, django_user_model):
"""
Test CAS authentication failure.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return None, {}, None
# we mock out the verify method so that we can bypass the external http
# calls needed for real authentication since we are testing the logic
# around authentication.
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
backend = backends.CASBackend()
user = backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is None
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
[docs]@pytest.mark.django_db
def test_backend_user_can_authenticate(monkeypatch, django_user_model):
"""
Test CAS authentication failure.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'ticket': ticket, 'service': service}, None
# we mock out the verify method so that we can bypass the external http
# calls needed for real authentication since we are testing the logic
# around authentication.
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
user = backends.CASBackend().authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is not None
class AllowNoneBackend(backends.CASBackend):
def user_can_authenticate(self, user):
return False
user = AllowNoneBackend().authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is None
[docs]@pytest.mark.django_db
def test_backend_does_not_apply_attributes_by_default(monkeypatch):
"""
Test to make sure attributes returned from the provider are not assigned to
the User model by default.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'is_staff': 'True', 'is_superuser': 'False'}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
backend = backends.CASBackend()
user = backend.authenticate(request, ticket='fake-ticket',
service='fake-service')
assert user is not None
assert not user.is_staff
[docs]@pytest.mark.django_db
def test_backend_applies_attributes_when_set(monkeypatch, settings):
"""
If CAS_APPLY_ATTRIBUTES_TO_USER is set, make sure the attributes returned
with the ticket are added to the User model.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'is_staff': 'True', 'is_superuser': 'False'}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
settings.CAS_APPLY_ATTRIBUTES_TO_USER = True
backend = backends.CASBackend()
user = backend.authenticate(request, ticket='fake-ticket',
service='fake-service')
assert user is not None
assert user.is_staff
[docs]@pytest.mark.django_db
def test_cas_attributes_renaming_working(monkeypatch, settings):
"""
Test to make sure attributes are renamed according to the setting file
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', \
{'ln': 'MyLastName', 'fn': 'MyFirstName', 'unkownAttr': 'knownAttr'}, \
None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
settings.CAS_RENAME_ATTRIBUTES = {'ln': 'last_name'}
settings.CAS_APPLY_ATTRIBUTES_TO_USER = True
backend = backends.CASBackend()
user = backend.authenticate(request, ticket='fake-ticket',
service='fake-service')
# Checking user data
assert user is not None
assert user.last_name == 'MyLastName'
assert user.first_name == ''
# checking session data
session_attr = request.session['attributes']
assert session_attr['fn'] == 'MyFirstName'
assert session_attr['last_name'] == 'MyLastName'
with pytest.raises(KeyError):
session_attr['ln']
[docs]@pytest.mark.django_db
def test_boolean_attributes_applied_as_booleans(monkeypatch, settings):
"""
If CAS_CREATE_USER_WITH_ID is True and 'id' is in the attributes, use this
field to get_or_create a User.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'is_staff': 'True', 'is_superuser': 'False'}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
settings.CAS_APPLY_ATTRIBUTES_TO_USER = True
backend = backends.CASBackend()
user = backend.authenticate(request, ticket='fake-ticket',
service='fake-service')
assert user is not None
assert user.is_superuser is False
assert user.is_staff is True
[docs]@pytest.mark.django_db
def test_backend_authentication_creates_a_user_with_id_attribute(monkeypatch, django_user_model, settings):
"""
If CAS_CREATE_USER_WITH_ID is True and 'id' is in the attributes, use this
field to get_or_create a User.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'id': 999, 'is_staff': True, 'is_superuser': False}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
# sanity check
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
settings.CAS_CREATE_USER_WITH_ID = True
backend = backends.CASBackend()
user = backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is not None
assert user.username == 'test@example.com'
assert django_user_model.objects.filter(id=999).exists()
[docs]@pytest.mark.django_db
def test_backend_authentication_create_user_with_id_and_user_exists(monkeypatch, django_user_model, settings):
"""
If CAS_CREATE_USER_WITH_ID is True and and the User already exists, don't create another user.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'id': 999, 'is_staff': True, 'is_superuser': False}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
existing_user = django_user_model.objects.create_user('test@example.com', '', id=999)
settings.CAS_CREATE_USER_WITH_ID = True
backend = backends.CASBackend()
user = backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert django_user_model.objects.all().count() == 1
assert user is not None
assert user.username == 'test@example.com'
assert user.id == 999
assert user == existing_user
[docs]@pytest.mark.django_db
def test_backend_authentication_create_user_with_id_and_no_id_provided(monkeypatch, django_user_model, settings):
"""
CAS_CREATE_USER_WITH_ID is True and the 'id' field is not in the attributes.
Should raise ImproperlyConfigured exception
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', {'is_staff': True, 'is_superuser': False}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
# sanity check
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
settings.CAS_CREATE_USER_WITH_ID = True
backend = backends.CASBackend()
with pytest.raises(ImproperlyConfigured) as excinfo:
backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert "CAS_CREATE_USER_WITH_ID is True, but `'id'` is not part of attributes." in str(excinfo.value)
[docs]@pytest.mark.django_db
def test_backend_authentication_create_user_with_id_and_attributes(monkeypatch, django_user_model, settings):
"""
CAS_CREATE_USER_WITH_ID is True and the attributes are not provided.
Should raise ImproperlyConfigured exception
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', None, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
# sanity check
assert not django_user_model.objects.filter(
username='test@example.com',
).exists()
settings.CAS_CREATE_USER_WITH_ID = True
backend = backends.CASBackend()
with pytest.raises(ImproperlyConfigured) as excinfo:
backend.authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert "CAS_CREATE_USER_WITH_ID is True, but no attributes were provided" in str(excinfo.value)
[docs]@pytest.mark.django_db
def test_backend_user_can_authenticate_with_cas_username_attribute(monkeypatch, settings):
"""
Test CAS_USERNAME_ATTRIBUTE setting.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
settings.CAS_USERNAME_ATTRIBUTE = 'username'
settings.CAS_FORCE_CHANGE_USERNAME_CASE = 'upper'
# Testing to make sure the custom username attribute is handled correctly.
def mock_verify(ticket, service):
return 'bad@example.com', {'ticket': ticket, 'service': service, 'username': 'good@example.com'}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
user = backends.CASBackend().authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user.username == 'GOOD@EXAMPLE.COM'
# Testing to make sure None is returned if username attribute is missing.
def mock_verify1(ticket, service):
return 'bad@example.com', {'ticket': ticket, 'service': service}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify1)
user = backends.CASBackend().authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is None
# Testing to make sure None is returned if attributes are None.
def mock_verify2(ticket, service):
return 'bad@example.com', None, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify2)
user = backends.CASBackend().authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user is None
[docs]@pytest.mark.django_db
def test_backend_user_can_authenticate_with_cas_username_attribute2(monkeypatch, settings):
"""
Test CAS_USERNAME_ATTRIBUTE setting.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
settings.CAS_USERNAME_ATTRIBUTE = 'cas:user'
# Test to make user we return the cas:user value and not an attibute named cas:user
def mock_verify(ticket, service):
return 'good', {'ticket': ticket, 'service': service, 'cas:user': 'bad'}, None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
user = backends.CASBackend().authenticate(
request, ticket='fake-ticket', service='fake-service',
)
assert user.username == 'good'
[docs]@pytest.mark.django_db
def test_backend_user_can_map_cas_affils(monkeypatch, settings):
"""
Test CAS_MAP_AFFILIATIONS setting.
"""
factory = RequestFactory()
request = factory.get('/login/')
request.session = {}
def mock_verify(ticket, service):
return 'test@example.com', \
{'affiliation': ['affil_group1', 'affil_group2']}, \
None
monkeypatch.setattr('cas.CASClientV2.verify_ticket', mock_verify)
settings.CAS_MAP_AFFILIATIONS = True
user = backends.CASBackend().authenticate(
request, ticket='fake-ticket', service='fake-service',
)
# Checking user data
assert user is not None
assert user.groups.count() == 2
group_names = [g.name for g in user.groups.all()]
assert 'affil_group1' in group_names
assert 'affil_group2' in group_names