auth_saml: reorganize and fix tests (#48117)
This commit is contained in:
parent
7b002f861f
commit
8d6b4653e3
|
@ -23,7 +23,9 @@ import lasso
|
|||
|
||||
from django.contrib.auth import get_user_model
|
||||
from authentic2.models import Attribute
|
||||
from authentic2_auth_saml.adapters import MappingError
|
||||
from authentic2_auth_saml.adapters import AuthenticAdapter, MappingError
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
def test_providers_on_login_page(db, app, settings):
|
||||
|
@ -52,15 +54,15 @@ def test_providers_on_login_page(db, app, settings):
|
|||
assert response.pyquery('button[name="login-saml-1"]')
|
||||
|
||||
|
||||
def test_provision_attributes(db, caplog):
|
||||
from authentic2_auth_saml.adapters import AuthenticAdapter
|
||||
@pytest.fixture
|
||||
def adapter():
|
||||
return AuthenticAdapter()
|
||||
|
||||
adapter = AuthenticAdapter()
|
||||
User = get_user_model()
|
||||
Attribute.objects.create(kind='title', name='title', label='title')
|
||||
|
||||
user = User.objects.create()
|
||||
idp = {
|
||||
@pytest.fixture
|
||||
def idp():
|
||||
|
||||
return {
|
||||
'A2_ATTRIBUTE_MAPPING': [
|
||||
{
|
||||
'attribute': 'email',
|
||||
|
@ -83,113 +85,126 @@ def test_provision_attributes(db, caplog):
|
|||
]
|
||||
}
|
||||
|
||||
saml_attributes = {
|
||||
u'issuer': 'https://idp.com/',
|
||||
u'name_id_content': 'xxx',
|
||||
u'name_id_format': lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
|
||||
u'mail': [u'john.doe@example.com'],
|
||||
u'title': [u'Mr.'],
|
||||
u'http://fucking/attribute/givenName': ['John'],
|
||||
|
||||
@pytest.fixture
|
||||
def title_attribute(db):
|
||||
return Attribute.objects.create(kind='title', name='title', label='title')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def saml_attributes():
|
||||
return {
|
||||
'issuer': 'https://idp.com/',
|
||||
'name_id_content': 'xxx',
|
||||
'name_id_format': lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
|
||||
'mail': ['john.doe@example.com'],
|
||||
'title': ['Mr.'],
|
||||
'http://fucking/attribute/givenName': ['John'],
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user(db):
|
||||
return User.objects.create()
|
||||
|
||||
|
||||
def test_lookup_user_ok(adapter, idp, saml_attributes, title_attribute):
|
||||
assert User.objects.count() == 0
|
||||
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
user.refresh_from_db()
|
||||
assert user.email == 'john.doe@example.com'
|
||||
assert user.attributes.title == 'Mr.'
|
||||
assert user.first_name == 'John'
|
||||
user.delete()
|
||||
assert user.attributes.title == 'Mr.'
|
||||
assert user.ou.default is True
|
||||
|
||||
# on missing mandatory attribute, no user is created
|
||||
|
||||
def test_lookup_user_missing_mandatory_attribute(adapter, idp, saml_attributes, title_attribute):
|
||||
del saml_attributes['mail']
|
||||
assert adapter.lookup_user(idp, saml_attributes) is None
|
||||
|
||||
# simulate no attribute value
|
||||
saml_attributes['first_name'] = []
|
||||
mapping = {
|
||||
'attribute': 'first_name',
|
||||
'saml_attribute': 'first_name',
|
||||
}
|
||||
with pytest.raises(MappingError, match='no value for first_name'):
|
||||
adapter.action_set_attribute(user, idp, saml_attributes, mapping)
|
||||
assert User.objects.count() == 0
|
||||
assert adapter.lookup_user(idp, saml_attributes) is None
|
||||
assert User.objects.count() == 0
|
||||
|
||||
|
||||
def test_apply_attribute_mapping_missing_attribute_logged(caplog, adapter, idp, saml_attributes, title_attribute, user):
|
||||
caplog.set_level('WARNING')
|
||||
saml_attributes['http://fucking/attribute/givenName'] = []
|
||||
adapter.apply_attribute_mapping(user, idp, saml_attributes, idp['A2_ATTRIBUTE_MAPPING'])
|
||||
assert re.match('.*no value.*first_name', caplog.records[-1].message)
|
||||
|
||||
|
||||
def test_apply_attribute_mapping_missing_attribute_exception(adapter, idp, saml_attributes, title_attribute, user):
|
||||
saml_attributes['http://fucking/attribute/givenName'] = []
|
||||
idp['A2_ATTRIBUTE_MAPPING'][-1]['mandatory'] = True
|
||||
with pytest.raises(MappingError, match='no value'):
|
||||
adapter.apply_attribute_mapping(user, idp, saml_attributes, idp['A2_ATTRIBUTE_MAPPING'])
|
||||
|
||||
|
||||
@pytest.mark.parametrize('action_name', ['add-role', 'toggle-role'])
|
||||
def test_provision_add_role(db, simple_role, action_name):
|
||||
from authentic2_auth_saml.adapters import AuthenticAdapter
|
||||
|
||||
adapter = AuthenticAdapter()
|
||||
User = get_user_model()
|
||||
user = User.objects.create()
|
||||
idp = {
|
||||
'A2_ATTRIBUTE_MAPPING': [
|
||||
{
|
||||
'action': action_name,
|
||||
'role': {
|
||||
'name': simple_role.name,
|
||||
'ou': {
|
||||
'name': simple_role.ou.name,
|
||||
class TestAddRole:
|
||||
@pytest.fixture
|
||||
def idp(self, action_name, simple_role):
|
||||
return {
|
||||
'A2_ATTRIBUTE_MAPPING': [
|
||||
{
|
||||
'action': action_name,
|
||||
'role': {
|
||||
'name': simple_role.name,
|
||||
'ou': {
|
||||
'name': simple_role.ou.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
'condition': "roles == 'A'",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
saml_attributes = {
|
||||
'issuer': 'https://idp.com/',
|
||||
'name_id_content': 'xxx',
|
||||
'name_id_format': lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
|
||||
}
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
user.refresh_from_db()
|
||||
assert simple_role not in user.roles.all()
|
||||
assert user.ou.default is True
|
||||
user.delete()
|
||||
|
||||
# if a toggle-role is mandatory, failure to evaluate condition block user creation
|
||||
assert idp['A2_ATTRIBUTE_MAPPING'][-1]['action'] == action_name
|
||||
idp['A2_ATTRIBUTE_MAPPING'][-1]['mandatory'] = True
|
||||
assert adapter.lookup_user(idp, saml_attributes) is None
|
||||
|
||||
saml_attributes['roles'] = ['A']
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
user.refresh_from_db()
|
||||
assert simple_role in user.roles.all()
|
||||
user.delete()
|
||||
|
||||
idp['A2_ATTRIBUTE_MAPPING'][-1]['condition'] = "'A' in roles__list"
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
user.refresh_from_db()
|
||||
assert simple_role in user.roles.all()
|
||||
|
||||
saml_attributes['roles'] = []
|
||||
adapter.provision(user, idp, saml_attributes)
|
||||
# condition failed, so role should be removed
|
||||
assert simple_role not in user.roles.all()
|
||||
user.delete()
|
||||
|
||||
# on missing mandatory attribute, no user is created
|
||||
del saml_attributes['mail']
|
||||
assert adapter.lookup_user(idp, saml_attributes) is None
|
||||
|
||||
# simulate no attribute value
|
||||
saml_attributes['first_name'] = []
|
||||
attribute_mapping = [
|
||||
{
|
||||
'mandatory': True,
|
||||
'attribute': 'first_name',
|
||||
'saml_attribute': 'first_name',
|
||||
'condition': "roles == 'A'",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
# fail fast
|
||||
with pytest.raises(MappingError, match='no value.*first_name'):
|
||||
adapter.apply_attribute_mapping(user, idp, saml_attributes, attribute_mapping)
|
||||
@pytest.fixture
|
||||
def saml_attributes(self):
|
||||
return {
|
||||
'issuer': 'https://idp.com/',
|
||||
'name_id_content': 'xxx',
|
||||
'name_id_format': lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
|
||||
}
|
||||
|
||||
# or log a warning
|
||||
caplog.clear()
|
||||
del attribute_mapping[0]['mandatory']
|
||||
adapter.apply_attribute_mapping(user, idp, saml_attributes, attribute_mapping)
|
||||
assert re.match('.*no value.*first_name', caplog.records[0].message)
|
||||
def test_lookup_user_condition_fails(self, adapter, simple_role, idp, saml_attributes):
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
assert simple_role not in user.roles.all()
|
||||
|
||||
def test_lookup_user_condition_success(self, adapter, simple_role, idp, saml_attributes):
|
||||
saml_attributes['roles'] = ['A']
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
assert simple_role in user.roles.all()
|
||||
|
||||
def test_lookup_user_mandatory_condition(self, adapter, simple_role, idp, saml_attributes):
|
||||
# if a toggle-role is mandatory, failure to evaluate condition block user creation
|
||||
idp['A2_ATTRIBUTE_MAPPING'][0]['mandatory'] = True
|
||||
assert adapter.lookup_user(idp, saml_attributes) is None
|
||||
|
||||
def test_lookup_user_mandatory(self, adapter, simple_role, idp, saml_attributes):
|
||||
idp['A2_ATTRIBUTE_MAPPING'][0]['mandatory'] = True
|
||||
saml_attributes['roles'] = ['A']
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
assert simple_role in user.roles.all()
|
||||
|
||||
def test_lookup_user_use_list(self, adapter, simple_role, idp, saml_attributes):
|
||||
idp['A2_ATTRIBUTE_MAPPING'][0]['condition'] = "'A' in roles__list"
|
||||
saml_attributes['roles'] = ['A']
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
assert simple_role in user.roles.all()
|
||||
|
||||
def test_lookup_user_add_and_remove(self, adapter, simple_role, idp, saml_attributes, caplog):
|
||||
saml_attributes['roles'] = ['A']
|
||||
user = adapter.lookup_user(idp, saml_attributes)
|
||||
assert simple_role in user.roles.all()
|
||||
|
||||
saml_attributes['roles'] = []
|
||||
adapter.provision(user, idp, saml_attributes)
|
||||
# condition failed, so role should be removed
|
||||
user.refresh_from_db()
|
||||
assert simple_role not in user.roles.all()
|
||||
|
||||
|
||||
def test_login_with_conditionnal_authenticators(db, app, settings, caplog):
|
||||
|
|
Loading…
Reference in New Issue