authentic2-auth-fedict/tests/test_all.py

339 lines
12 KiB
Python

import datetime
import lasso
import pytest
from authentic2.a2_rbac.utils import get_default_ou
from authentic2.models import Attribute
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.db import connection
from django.db.migrations.executor import MigrationExecutor
from django.test.client import RequestFactory
from mellon.models import Issuer, UserSAMLIdentifier
from utils import login
from authentic2_auth_fedict.adapters import AuthenticAdapter
from authentic2_auth_fedict.backends import FedictBackend
from authentic2_auth_fedict.models import FedictAuthenticator
User = get_user_model()
pytestmark = pytest.mark.django_db
factory = RequestFactory()
@pytest.fixture
def authenticator():
return FedictAuthenticator.objects.create(slug='fedict', enabled=True)
@pytest.fixture
def adapter():
return AuthenticAdapter()
@pytest.fixture
def idp_conf():
return {
'A2_ATTRIBUTE_MAPPING': [
{
'attribute': 'email',
'saml_attribute': 'mail',
},
{
'attribute': 'last_name',
'saml_attribute': 'surname',
},
{
'attribute': 'first_name',
'saml_attribute': 'givenName',
},
{
'attribute': 'uuid',
'saml_attribute': 'urn:be:fedict:iam:attr:fedid',
},
]
}
@pytest.fixture
def issuer():
return Issuer.objects.create(entity_id='https://idp.com/', slug='idp')
@pytest.fixture
def fedict_attributes():
return {
'issuer': 'https://idp.com/',
'name_id_content': 'c54db0a8ddc24a02a2d057f857d3b102',
'name_id_format': lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED,
'surname': ['Doe'],
'givenName': ['John'],
'mail': ['john.doe@example.org'],
'urn:be:fedict:iam:attr:fedid': ['c54db0a8ddc24a02a2d057f857d3b102'],
}
def test_custom_lookup_user(adapter, idp_conf, issuer, fedict_attributes):
assert User.objects.count() == 0
user = adapter.lookup_user(idp_conf, fedict_attributes)
user.refresh_from_db()
assert user.email == '' # email purposely deleted
assert user.first_name == '' # not provisionned yet
assert user.last_name == '' # not provisionned yet
assert user.username == 'c54db0a8ddc24a02a2d057f857d3b102@saml' # <NameID>@<source>
assert user.ou == get_default_ou()
def test_login_fedict_authenticator_displayed(app, settings, issuer, authenticator):
response = app.get('/login/')
assert 'Belgian eID' in response
assert 'csam-login' in response
def test_authenticate_eid_provision(app, settings, issuer):
backend = FedictBackend()
request = factory.get(path='/accounts/')
request.user = AnonymousUser()
saml_attributes = {
'city': [],
'zipcode': [],
'givenName': ['Doe'],
'surname': ['John'],
'verified_attributes': [],
'address': [],
'last_name': ['Doe'],
'first_name': ['John'],
'title': [],
'username': ['john.doe'],
'urn:be:fedict:iam:attr:fedid': ['xyz'], # new fedict id
'is_superuser': ['false'],
'phone': [],
'mobile': [],
'issuer': 'https://idp.com/',
'nonce': None,
'force_authn': False,
'name_id_content': 'xyz', # new fedict id
'name_id_format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
'name_id_name_qualifier': 'https://idp.com/idp/saml2/metadata',
'authn_instant': datetime.datetime(2022, 1, 27, 11, 26, 7, 301054),
'session_not_on_or_after': datetime.datetime(2022, 1, 27, 16, 26, 7),
'session_index': '_401EEEE3C700B6D203B83AA1826E3B80',
'authn_context_class_ref': 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
'name_id_content_orig': 'c54db0a8ddc24a02a2d057f857d3b102',
}
credentials = {'saml_attributes': saml_attributes}
assert len(User.objects.all()) == 0
SessionMiddleware().process_request(request)
MessageMiddleware().process_request(request)
backend_user = backend.authenticate(request, **credentials)
assert backend_user.is_authenticated
assert backend_user.username == 'xyz@saml' # <NameID>@<source>
def test_authenticate_eid_link_to_existing_user(app, settings, issuer, user):
backend = FedictBackend()
request = factory.get(path='/accounts/')
request.user = user
UserSAMLIdentifier.objects.create(
user=user,
name_id='c54db0a8ddc24a02a2d057f857d3b102',
issuer=Issuer.objects.first(),
)
saml_attributes = {
'city': [],
'zipcode': [],
'givenName': ['Doe'],
'surname': ['John'],
'verified_attributes': [],
'address': [],
'last_name': ['Doe'],
'first_name': ['John'],
'title': [],
'username': ['john.doe'],
'urn:be:fedict:iam:attr:fedid': ['c54db0a8ddc24a02a2d057f857d3b102'],
'is_superuser': ['false'],
'phone': [],
'mobile': [],
'issuer': 'https://idp.com/',
'nonce': None,
'force_authn': False,
'name_id_content': 'c54db0a8ddc24a02a2d057f857d3b102',
'name_id_format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
'name_id_name_qualifier': 'https://idp.com/idp/saml2/metadata',
'authn_instant': datetime.datetime(2022, 1, 27, 11, 26, 7, 301054),
'session_not_on_or_after': datetime.datetime(2022, 1, 27, 16, 26, 7),
'session_index': '_401EEEE3C700B6D203B83AA1826E3B80',
'authn_context_class_ref': 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
'name_id_content_orig': 'c54db0a8ddc24a02a2d057f857d3b102',
}
credentials = {'saml_attributes': saml_attributes}
SessionMiddleware().process_request(request)
MessageMiddleware().process_request(request)
backend_user = backend.authenticate(request, **credentials)
assert backend_user == user
def test_eid_unlink(app, settings, issuer, user, authenticator):
assert len(UserSAMLIdentifier.objects.all()) == 0
# create link
UserSAMLIdentifier.objects.create(
user=user,
name_id='abc',
issuer=Issuer.objects.first(),
)
response = login(app, user, path='/accounts/', password=user.username)
assert "Unlink my account" in response.text
app.get('/accounts/fedict/unlink/').follow()
response = app.get('/accounts/')
assert "Link my account to my eID card" in response.text
def test_provision_new_attributes_verified(app, settings, issuer, user):
Attribute.objects.create(name='title', kind='title', label='Titre')
# email & title verified
user.email = 'john.doe@verified.publik.love'
user.email_verified = True
user.verified_attributes.title = 'Mr'
user.first_name = 'Johnny'
user.last_name = 'Smith'
user.save()
UserSAMLIdentifier.objects.create(
user=user,
name_id='c54db0a8ddc24a02a2d057f857d3b102',
issuer=Issuer.objects.first(),
)
backend = FedictBackend()
request = factory.get(path='/accounts/')
request_user = User.objects.create(
first_name='Foo',
last_name='Bar',
email='foo.bar@nowhere.null',
)
request.user = request_user
saml_attributes = {
'givenName': ['Doe'],
'surname': ['John'],
'last_name': ['Doe'],
'first_name': ['John'],
'username': ['john.doe'],
'urn:be:fedict:iam:attr:fedid': ['c54db0a8ddc24a02a2d057f857d3b102'],
'is_superuser': ['false'],
'issuer': 'https://idp.com/',
'name_id_content': 'c54db0a8ddc24a02a2d057f857d3b102',
'name_id_format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
'name_id_name_qualifier': 'https://idp.com/idp/saml2/metadata',
'name_id_content_orig': 'c54db0a8ddc24a02a2d057f857d3b102',
}
credentials = {'saml_attributes': saml_attributes}
SessionMiddleware().process_request(request)
MessageMiddleware().process_request(request)
backend_user = backend.authenticate(request, **credentials)
assert backend_user == request_user
assert backend_user.email == 'john.doe@verified.publik.love'
assert backend_user.email_verified == True
assert backend_user.verified_attributes.title == 'Mr'
assert backend_user.first_name == 'Foo'
assert backend_user.last_name == 'Bar'
def test_provision_old_account_deleted(app, settings, issuer, user):
backend = FedictBackend()
request = factory.get(path='/accounts/')
request_user = User.objects.create(
first_name='foo',
last_name='bar',
email='foo.bar@nowhere.null',
)
request.user = request_user
count = User.objects.count()
user_uuid = user.uuid
UserSAMLIdentifier.objects.create(
user=user,
name_id='c54db0a8ddc24a02a2d057f857d3b102',
issuer=Issuer.objects.first(),
)
saml_attributes = {
'givenName': ['Doe'],
'surname': ['John'],
'last_name': ['Doe'],
'first_name': ['John'],
'username': ['john.doe'],
'urn:be:fedict:iam:attr:fedid': ['c54db0a8ddc24a02a2d057f857d3b102'],
'is_superuser': ['false'],
'issuer': 'https://idp.com/',
'name_id_content': 'c54db0a8ddc24a02a2d057f857d3b102',
'name_id_format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
'name_id_name_qualifier': 'https://idp.com/idp/saml2/metadata',
'name_id_content_orig': 'c54db0a8ddc24a02a2d057f857d3b102',
}
credentials = {'saml_attributes': saml_attributes}
SessionMiddleware().process_request(request)
MessageMiddleware().process_request(request)
backend_user = backend.authenticate(request, **credentials)
# link has been created on currently logged-in user
assert backend_user == request_user
# previous user as been deactivated
assert User.objects.count() == count - 1
assert not User.objects.filter(uuid=user_uuid)
def test_fedict_authenticator_data_migration(settings):
app = 'authentic2_auth_fedict'
migrate_from = [(app, '0001_initial')]
migrate_to = [(app, '0002_auto_20220706_1712')]
executor = MigrationExecutor(connection)
old_apps = executor.loader.project_state(migrate_from).apps
executor.migrate(migrate_from)
FedictAuthenticator = old_apps.get_model(app, 'FedictAuthenticator')
settings.AUTH_FRONTENDS_KWARGS = {
"fedict": {"priority": 3, "show_condition": "'backoffice' not in login_hint"}
}
settings.A2_AUTH_FEDICT_ENABLE = True
executor = MigrationExecutor(connection)
executor.migrate(migrate_to)
executor.loader.build_graph()
new_apps = executor.loader.project_state(migrate_to).apps
FedictAuthenticator = new_apps.get_model(app, 'FedictAuthenticator')
authenticator = FedictAuthenticator.objects.get()
assert authenticator.slug == 'fedict-authenticator'
assert authenticator.order == 3
assert authenticator.show_condition == "'backoffice' not in login_hint"
assert authenticator.enabled is True
def test_manager(app, admin):
resp = login(app, admin, path='/manage/authenticators/', index=0)
resp = resp.click('Add new authenticator')
resp.form['authenticator'] = 'fedict'
resp = resp.form.submit().follow()
authenticator = FedictAuthenticator.objects.get()
assert not authenticator.enabled
# on edit page, submit
resp = resp.form.submit().follow()
resp = resp.click('Enable')
authenticator.refresh_from_db()
assert authenticator.enabled