0001-auth_saml-remove-rename-attribute-action-68383.patch
src/authentic2_auth_saml/adapters.py | ||
---|---|---|
111 | 111 |
def provision_a2_attributes(self, user, idp, saml_attributes): |
112 | 112 |
saml_attributes = saml_attributes.copy() |
113 | 113 | |
114 |
self.rename_attributes(idp, saml_attributes) |
|
115 | 114 |
self.set_attributes(user, idp, saml_attributes) |
116 | 115 |
self.action_add_role(user, idp, saml_attributes) |
117 | 116 | |
118 |
def rename_attributes(self, idp, saml_attributes): |
|
119 |
for action in idp['authenticator'].rename_attribute_actions.all(): |
|
120 |
if action.from_name in saml_attributes: |
|
121 |
saml_attributes[action.to_name] = saml_attributes[action.from_name] |
|
122 | ||
123 | 117 |
def set_attributes(self, user, idp, saml_attributes): |
124 | 118 |
user_modified = False |
125 | 119 |
for action in idp['authenticator'].set_attribute_actions.all(): |
src/authentic2_auth_saml/migrations/0010_statically_rename_attributes.py | ||
---|---|---|
1 |
# Generated by Django 2.2.26 on 2022-08-24 14:55 |
|
2 | ||
3 |
import logging |
|
4 | ||
5 |
from django.db import migrations |
|
6 | ||
7 |
logger = logging.getLogger('authentic2.auth_saml') |
|
8 | ||
9 | ||
10 |
def rename_attributes(apps, schema_editor): |
|
11 |
SAMLAuthenticator = apps.get_model('authentic2_auth_saml', 'SAMLAuthenticator') |
|
12 | ||
13 |
for authenticator in SAMLAuthenticator.objects.all(): |
|
14 |
rename_map = {x.to_name: x.from_name for x in authenticator.rename_attribute_actions.all()} |
|
15 | ||
16 |
for action in authenticator.set_attribute_actions.all(): |
|
17 |
action.saml_attribute = rename_map.get(action.saml_attribute, action.saml_attribute) |
|
18 |
action.save() |
|
19 | ||
20 |
for lookup in authenticator.attribute_lookups.all(): |
|
21 |
lookup.saml_attribute = rename_map.get(lookup.saml_attribute, lookup.saml_attribute) |
|
22 |
lookup.save() |
|
23 | ||
24 | ||
25 |
class Migration(migrations.Migration): |
|
26 | ||
27 |
dependencies = [ |
|
28 |
('authentic2_auth_saml', '0009_rename_attribute_field'), |
|
29 |
] |
|
30 | ||
31 |
operations = [ |
|
32 |
migrations.RunPython(rename_attributes, reverse_code=migrations.RunPython.noop), |
|
33 |
] |
src/authentic2_auth_saml/migrations/0011_delete_renameattributeaction.py | ||
---|---|---|
1 |
# Generated by Django 2.2.26 on 2022-08-24 15:07 |
|
2 | ||
3 |
from django.db import migrations |
|
4 | ||
5 | ||
6 |
class Migration(migrations.Migration): |
|
7 | ||
8 |
dependencies = [ |
|
9 |
('authentic2_auth_saml', '0010_statically_rename_attributes'), |
|
10 |
] |
|
11 | ||
12 |
operations = [ |
|
13 |
migrations.DeleteModel( |
|
14 |
name='RenameAttributeAction', |
|
15 |
), |
|
16 |
] |
src/authentic2_auth_saml/models.py | ||
---|---|---|
221 | 221 |
return SelectAttributeWidget.get_options().get(self.user_field, self.user_field) |
222 | 222 | |
223 | 223 | |
224 |
class RenameAttributeAction(SAMLRelatedObjectBase): |
|
225 |
from_name = models.CharField(_('From'), max_length=1024) |
|
226 |
to_name = models.CharField(_('To'), max_length=64) |
|
227 | ||
228 |
class Meta: |
|
229 |
default_related_name = 'rename_attribute_actions' |
|
230 |
verbose_name = _('Rename an attribute') |
|
231 | ||
232 |
def __str__(self): |
|
233 |
return '%s → %s' % (self.from_name, self.to_name) |
|
234 | ||
235 | ||
236 | 224 |
class SAMLAttributeLookup(SAMLRelatedObjectBase): |
237 | 225 |
user_field = models.CharField(_('User field'), max_length=256) |
238 | 226 |
saml_attribute = models.CharField(_('SAML attribute'), max_length=1024) |
src/authentic2_auth_saml/views.py | ||
---|---|---|
11 | 11 |
from authentic2.utils.misc import redirect_to_login |
12 | 12 | |
13 | 13 |
from .forms import RoleChoiceField, SelectAttributeWidget |
14 |
from .models import ( |
|
15 |
AddRoleAction, |
|
16 |
RenameAttributeAction, |
|
17 |
SAMLAttributeLookup, |
|
18 |
SAMLAuthenticator, |
|
19 |
SetAttributeAction, |
|
20 |
) |
|
14 |
from .models import AddRoleAction, SAMLAttributeLookup, SAMLAuthenticator, SetAttributeAction |
|
21 | 15 | |
22 | 16 | |
23 | 17 |
def login(request, authenticator, *args, **kwargs): |
... | ... | |
52 | 46 | |
53 | 47 | |
54 | 48 |
class SAMLAuthenticatorMixin(MediaMixin, TitleMixin): |
55 |
allowed_models = (SAMLAttributeLookup, RenameAttributeAction, SetAttributeAction, AddRoleAction)
|
|
49 |
allowed_models = (SAMLAttributeLookup, SetAttributeAction, AddRoleAction) |
|
56 | 50 | |
57 | 51 |
def dispatch(self, request, *args, **kwargs): |
58 | 52 |
self.authenticator = get_object_or_404(SAMLAuthenticator, pk=kwargs.get('authenticator_pk')) |
tests/test_auth_saml.py | ||
---|---|---|
30 | 30 |
from authentic2_auth_saml.adapters import AuthenticAdapter, MappingError |
31 | 31 |
from authentic2_auth_saml.models import ( |
32 | 32 |
AddRoleAction, |
33 |
RenameAttributeAction, |
|
34 | 33 |
SAMLAttributeLookup, |
35 | 34 |
SAMLAuthenticator, |
36 | 35 |
SetAttributeAction, |
... | ... | |
101 | 100 |
user_field='first_name', |
102 | 101 |
saml_attribute='first_name', |
103 | 102 |
) |
104 |
RenameAttributeAction.objects.create( |
|
105 |
authenticator=authenticator, |
|
106 |
from_name='http://nice/attribute/givenName', |
|
107 |
to_name='first_name', |
|
108 |
) |
|
109 | 103 |
return authenticator.settings |
110 | 104 | |
111 | 105 | |
... | ... | |
122 | 116 |
'name_id_format': lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT, |
123 | 117 |
'mail': ['john.doe@example.com'], |
124 | 118 |
'title': ['Mr.'], |
125 |
'http://nice/attribute/givenName': ['John'],
|
|
119 |
'first_name': ['John'],
|
|
126 | 120 |
} |
127 | 121 | |
128 | 122 | |
... | ... | |
155 | 149 |
caplog, adapter, idp, saml_attributes, title_attribute, user |
156 | 150 |
): |
157 | 151 |
caplog.set_level('WARNING') |
158 |
saml_attributes['http://nice/attribute/givenName'] = []
|
|
152 |
saml_attributes['first_name'] = []
|
|
159 | 153 |
adapter.provision_a2_attributes(user, idp, saml_attributes) |
160 | 154 |
assert re.match('.*no value.*first_name', caplog.records[-1].message) |
161 | 155 | |
... | ... | |
163 | 157 |
def test_apply_attribute_mapping_missing_attribute_exception( |
164 | 158 |
adapter, idp, saml_attributes, title_attribute, user, rf |
165 | 159 |
): |
166 |
saml_attributes['http://nice/attribute/givenName'] = []
|
|
160 |
saml_attributes['first_name'] = []
|
|
167 | 161 |
SetAttributeAction.objects.filter(user_field='first_name').update(mandatory=True) |
168 | 162 |
with pytest.raises(MappingError, match='no value'): |
169 | 163 |
adapter.provision_a2_attributes(user, idp, saml_attributes) |
... | ... | |
679 | 673 |
'lookup by attributes for SAMLAuthenticator object (%s): [{"user_field": "email", "saml_attribute": "email"}]' |
680 | 674 |
% authenticator.pk, |
681 | 675 |
] |
676 | ||
677 | ||
678 |
def test_saml_authenticator_data_migration_rename_attributes(migration, settings): |
|
679 |
migrate_from = [('authentic2_auth_saml', '0009_rename_attribute_field')] |
|
680 |
migrate_to = [('authentic2_auth_saml', '0010_statically_rename_attributes')] |
|
681 | ||
682 |
old_apps = migration.before(migrate_from) |
|
683 |
SAMLAuthenticator = old_apps.get_model('authentic2_auth_saml', 'SAMLAuthenticator') |
|
684 |
RenameAttributeAction = old_apps.get_model('authentic2_auth_saml', 'RenameAttributeAction') |
|
685 |
SetAttributeAction = old_apps.get_model('authentic2_auth_saml', 'SetAttributeAction') |
|
686 |
SAMLAttributeLookup = old_apps.get_model('authentic2_auth_saml', 'SAMLAttributeLookup') |
|
687 | ||
688 |
authenticator = SAMLAuthenticator.objects.create(slug='idp1') |
|
689 |
RenameAttributeAction.objects.create( |
|
690 |
authenticator=authenticator, from_name='http://nice/attribute/givenName', to_name='first_name' |
|
691 |
) |
|
692 |
SAMLAttributeLookup.objects.create( |
|
693 |
authenticator=authenticator, user_field='first_name', saml_attribute='first_name' |
|
694 |
) |
|
695 |
SAMLAttributeLookup.objects.create( |
|
696 |
authenticator=authenticator, user_field='title', saml_attribute='title' |
|
697 |
) |
|
698 |
SetAttributeAction.objects.create( |
|
699 |
authenticator=authenticator, user_field='first_name', saml_attribute='first_name' |
|
700 |
) |
|
701 |
SetAttributeAction.objects.create(authenticator=authenticator, user_field='title', saml_attribute='title') |
|
702 | ||
703 |
new_apps = migration.apply(migrate_to) |
|
704 |
SAMLAuthenticator = new_apps.get_model('authentic2_auth_saml', 'SAMLAuthenticator') |
|
705 |
authenticator = SAMLAuthenticator.objects.get() |
|
706 | ||
707 |
attribute_lookup1, attribute_lookup2 = authenticator.attribute_lookups.all().order_by('pk') |
|
708 |
assert attribute_lookup1.saml_attribute == 'http://nice/attribute/givenName' |
|
709 |
assert attribute_lookup1.user_field == 'first_name' |
|
710 |
assert attribute_lookup2.saml_attribute == 'title' |
|
711 |
assert attribute_lookup2.user_field == 'title' |
|
712 | ||
713 |
set_attribute1, set_attribute2 = authenticator.set_attribute_actions.all().order_by('pk') |
|
714 |
assert set_attribute1.saml_attribute == 'http://nice/attribute/givenName' |
|
715 |
assert set_attribute1.user_field == 'first_name' |
|
716 |
assert set_attribute2.saml_attribute == 'title' |
|
717 |
assert set_attribute2.user_field == 'title' |
tests/test_manager_authenticators.py | ||
---|---|---|
323 | 323 |
assert_event('authenticator.saml.related_object.deletion', user=superuser, session=app.session) |
324 | 324 | |
325 | 325 | |
326 |
def test_authenticators_saml_rename_attribute(app, superuser): |
|
327 |
authenticator = SAMLAuthenticator.objects.create(metadata='meta1.xml', slug='idp1') |
|
328 |
resp = login(app, superuser, path=authenticator.get_absolute_url()) |
|
329 | ||
330 |
resp = resp.click('Add', href='renameattributeaction') |
|
331 |
resp.form['from_name'] = 'a' |
|
332 |
resp.form['to_name'] = 'b' |
|
333 |
resp = resp.form.submit().follow() |
|
334 |
assert 'a → b' in resp.text |
|
335 | ||
336 | ||
337 | 326 |
def test_authenticators_saml_set_attribute(app, superuser): |
338 | 327 |
authenticator = SAMLAuthenticator.objects.create(metadata='meta1.xml', slug='idp1') |
339 | 328 |
resp = login(app, superuser, path=authenticator.get_absolute_url()) |
tests/test_manager_journal.py | ||
---|---|---|
28 | 28 |
from authentic2.custom_user.models import Profile, ProfileType, User |
29 | 29 |
from authentic2.journal import journal |
30 | 30 |
from authentic2.models import Service |
31 |
from authentic2_auth_saml.models import RenameAttributeAction, SAMLAuthenticator
|
|
31 |
from authentic2_auth_saml.models import SAMLAuthenticator, SetAttributeAction
|
|
32 | 32 | |
33 | 33 |
from .utils import login, logout, text_content |
34 | 34 | |
... | ... | |
60 | 60 |
service = Service.objects.create(name="service") |
61 | 61 |
authenticator = LoginPasswordAuthenticator.objects.create(slug='test') |
62 | 62 |
saml_authenticator = SAMLAuthenticator.objects.create(slug='saml') |
63 |
rename_attribute_action = RenameAttributeAction.objects.create(authenticator=saml_authenticator)
|
|
63 |
rename_attribute_action = SetAttributeAction.objects.create(authenticator=saml_authenticator)
|
|
64 | 64 | |
65 | 65 |
class EventFactory: |
66 | 66 |
date = make_aware(datetime.datetime(2020, 1, 1)) |
... | ... | |
358 | 358 | |
359 | 359 |
def test_global_journal(app, superuser, events): |
360 | 360 |
response = login(app, user=superuser, path="/manage/") |
361 |
rename_attribute_action = RenameAttributeAction.objects.get()
|
|
361 |
rename_attribute_action = SetAttributeAction.objects.get()
|
|
362 | 362 | |
363 | 363 |
# remove event about admin login |
364 | 364 |
Event.objects.filter(user=superuser).delete() |
... | ... | |
715 | 715 |
'user': 'agent', |
716 | 716 |
}, |
717 | 717 |
{ |
718 |
'message': 'creation of RenameAttributeAction (%s) in authenticator "SAML"'
|
|
718 |
'message': 'creation of SetAttributeAction (%s) in authenticator "SAML"'
|
|
719 | 719 |
% rename_attribute_action.pk, |
720 | 720 |
'timestamp': 'Jan. 3, 2020, 8 a.m.', |
721 | 721 |
'type': 'authenticator.saml.related_object.creation', |
722 | 722 |
'user': 'agent', |
723 | 723 |
}, |
724 | 724 |
{ |
725 |
'message': 'edit RenameAttributeAction (%s) in authenticator "SAML" (from_name)'
|
|
725 |
'message': 'edit SetAttributeAction (%s) in authenticator "SAML" (from_name)'
|
|
726 | 726 |
% rename_attribute_action.pk, |
727 | 727 |
'timestamp': 'Jan. 3, 2020, 9 a.m.', |
728 | 728 |
'type': 'authenticator.saml.related_object.edit', |
729 | 729 |
'user': 'agent', |
730 | 730 |
}, |
731 | 731 |
{ |
732 |
'message': 'deletion of RenameAttributeAction (%s) in authenticator "SAML"'
|
|
732 |
'message': 'deletion of SetAttributeAction (%s) in authenticator "SAML"'
|
|
733 | 733 |
% rename_attribute_action.pk, |
734 | 734 |
'timestamp': 'Jan. 3, 2020, 10 a.m.', |
735 | 735 |
'type': 'authenticator.saml.related_object.deletion', |
736 |
- |