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/0009_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', '0008_auto_20220913_1105'), |
|
29 |
] |
|
30 | ||
31 |
operations = [ |
|
32 |
migrations.RunPython(rename_attributes, reverse_code=migrations.RunPython.noop), |
|
33 |
] |
src/authentic2_auth_saml/migrations/0010_delete_renameattributeaction.py | ||
---|---|---|
1 |
# Generated by Django 2.2.26 on 2022-09-14 12:46 |
|
2 | ||
3 |
from django.db import migrations |
|
4 | ||
5 | ||
6 |
class Migration(migrations.Migration): |
|
7 | ||
8 |
dependencies = [ |
|
9 |
('authentic2_auth_saml', '0009_statically_rename_attributes'), |
|
10 |
] |
|
11 | ||
12 |
operations = [ |
|
13 |
migrations.DeleteModel( |
|
14 |
name='RenameAttributeAction', |
|
15 |
), |
|
16 |
] |
src/authentic2_auth_saml/models.py | ||
---|---|---|
214 | 214 |
return SelectAttributeWidget.get_options().get(self.user_field, self.user_field) |
215 | 215 | |
216 | 216 | |
217 |
class RenameAttributeAction(SAMLRelatedObjectBase): |
|
218 |
from_name = models.CharField(_('From'), max_length=1024) |
|
219 |
to_name = models.CharField(_('To'), max_length=64) |
|
220 | ||
221 |
class Meta: |
|
222 |
default_related_name = 'rename_attribute_actions' |
|
223 |
verbose_name = _('Rename an attribute') |
|
224 | ||
225 |
def __str__(self): |
|
226 |
return '%s → %s' % (self.from_name, self.to_name) |
|
227 | ||
228 | ||
229 | 217 |
class SAMLAttributeLookup(SAMLRelatedObjectBase): |
230 | 218 |
user_field = models.CharField(_('User field'), max_length=256) |
231 | 219 |
saml_attribute = models.CharField(_('SAML attribute'), max_length=1024) |
src/authentic2_auth_saml/templates/authentic2_auth_saml/authenticator_detail.html | ||
---|---|---|
13 | 13 | |
14 | 14 |
{% block extra-tab-buttons %} |
15 | 15 |
<button aria-controls="panel-samlattributelookup" aria-selected="false" id="tab-samlattributelookup" role="tab" tabindex="-1">{% trans "Lookup by attributes" %}</button> |
16 |
<button aria-controls="panel-renameattributeaction" aria-selected="false" id="tab-renameattributeaction" role="tab" tabindex="-1">{% trans "Rename attributes" %}</button> |
|
17 | 16 |
<button aria-controls="panel-setattributeaction" aria-selected="false" id="tab-setattributeaction" role="tab" tabindex="-1">{% trans "Set attributes" %}</button> |
18 | 17 |
<button aria-controls="panel-addroleaction" aria-selected="false" id="tab-addroleaction" role="tab" tabindex="-1">{% trans "Add roles" %}</button> |
19 | 18 |
{% endblock %} |
... | ... | |
23 | 22 |
{% include 'authentic2_auth_saml/related_object_list.html' with object_list=object.attribute_lookups.all model_name='samlattributelookup' %} |
24 | 23 |
</div> |
25 | 24 | |
26 |
<div aria-labelledby="tab-renameattributeaction" hidden="" id="panel-renameattributeaction" role="tabpanel" tabindex="0"> |
|
27 |
{% include 'authentic2_auth_saml/related_object_list.html' with object_list=object.rename_attribute_actions.all model_name='renameattributeaction' %} |
|
28 |
</div> |
|
29 | ||
30 | 25 |
<div aria-labelledby="tab-setattributeaction" hidden="" id="panel-setattributeaction" role="tabpanel" tabindex="0"> |
31 | 26 |
{% include 'authentic2_auth_saml/related_object_list.html' with object_list=object.set_attribute_actions.all model_name='setattributeaction' %} |
32 | 27 |
</div> |
src/authentic2_auth_saml/views.py | ||
---|---|---|
12 | 12 |
from authentic2.utils.misc import redirect_to_login |
13 | 13 | |
14 | 14 |
from .forms import RoleChoiceField |
15 |
from .models import ( |
|
16 |
AddRoleAction, |
|
17 |
RenameAttributeAction, |
|
18 |
SAMLAttributeLookup, |
|
19 |
SAMLAuthenticator, |
|
20 |
SetAttributeAction, |
|
21 |
) |
|
15 |
from .models import AddRoleAction, SAMLAttributeLookup, SAMLAuthenticator, SetAttributeAction |
|
22 | 16 | |
23 | 17 | |
24 | 18 |
def login(request, authenticator, *args, **kwargs): |
... | ... | |
53 | 47 | |
54 | 48 | |
55 | 49 |
class SAMLAuthenticatorMixin(MediaMixin, TitleMixin): |
56 |
allowed_models = (SAMLAttributeLookup, RenameAttributeAction, SetAttributeAction, AddRoleAction)
|
|
50 |
allowed_models = (SAMLAttributeLookup, SetAttributeAction, AddRoleAction) |
|
57 | 51 | |
58 | 52 |
def dispatch(self, request, *args, **kwargs): |
59 | 53 |
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, |
... | ... | |
99 | 98 |
SetAttributeAction.objects.create( |
100 | 99 |
authenticator=authenticator, |
101 | 100 |
user_field='first_name', |
102 |
saml_attribute='first_name', |
|
103 |
) |
|
104 |
RenameAttributeAction.objects.create( |
|
105 |
authenticator=authenticator, |
|
106 |
from_name='http://nice/attribute/givenName', |
|
107 |
to_name='first_name', |
|
101 |
saml_attribute='http://nice/attribute/givenName', |
|
108 | 102 |
) |
109 | 103 |
return authenticator.settings |
110 | 104 | |
... | ... | |
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', '0008_auto_20220913_1105')] |
|
680 |
migrate_to = [('authentic2_auth_saml', '0009_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 | ||
---|---|---|
379 | 379 |
assert_event('authenticator.saml.related_object.deletion', user=superuser, session=app.session) |
380 | 380 | |
381 | 381 | |
382 |
def test_authenticators_saml_rename_attribute(app, superuser): |
|
383 |
authenticator = SAMLAuthenticator.objects.create(metadata='meta1.xml', slug='idp1') |
|
384 |
resp = login(app, superuser, path=authenticator.get_absolute_url()) |
|
385 | ||
386 |
resp = resp.click('Add', href='renameattributeaction') |
|
387 |
resp.form['from_name'] = 'a' |
|
388 |
resp.form['to_name'] = 'b' |
|
389 |
resp = resp.form.submit().follow() |
|
390 |
assert 'a → b' in resp.text |
|
391 | ||
392 | ||
393 | 382 |
def test_authenticators_saml_set_attribute(app, superuser): |
394 | 383 |
authenticator = SAMLAuthenticator.objects.create(metadata='meta1.xml', slug='idp1') |
395 | 384 |
resp = login(app, superuser, path=authenticator.get_absolute_url()) |
tests/test_manager_journal.py | ||
---|---|---|
29 | 29 |
from authentic2.journal import journal |
30 | 30 |
from authentic2.models import Service |
31 | 31 |
from authentic2_auth_oidc.models import OIDCClaimMapping, OIDCProvider |
32 |
from authentic2_auth_saml.models import RenameAttributeAction, SAMLAuthenticator
|
|
32 |
from authentic2_auth_saml.models import SAMLAuthenticator, SetAttributeAction
|
|
33 | 33 | |
34 | 34 |
from .utils import login, logout, text_content |
35 | 35 | |
... | ... | |
61 | 61 |
service = Service.objects.create(name="service") |
62 | 62 |
authenticator = LoginPasswordAuthenticator.objects.create(slug='test') |
63 | 63 |
saml_authenticator = SAMLAuthenticator.objects.create(slug='saml') |
64 |
rename_attribute_action = RenameAttributeAction.objects.create(authenticator=saml_authenticator)
|
|
64 |
set_attribute_action = SetAttributeAction.objects.create(authenticator=saml_authenticator)
|
|
65 | 65 |
oidc_provider = OIDCProvider.objects.create(slug='oidc') |
66 | 66 |
oidc_claim_mapping = OIDCClaimMapping.objects.create(provider=oidc_provider) |
67 | 67 | |
... | ... | |
311 | 311 |
'authenticator.saml.related_object.creation', |
312 | 312 |
user=agent, |
313 | 313 |
session=session2, |
314 |
related_object=rename_attribute_action,
|
|
314 |
related_object=set_attribute_action,
|
|
315 | 315 |
) |
316 | 316 |
action_edit_form = mock.Mock(spec=['instance', 'initial', 'changed_data', 'cleaned_data']) |
317 |
action_edit_form.instance = rename_attribute_action
|
|
317 |
action_edit_form.instance = set_attribute_action
|
|
318 | 318 |
action_edit_form.initial = {'from_name': 'old'} |
319 | 319 |
action_edit_form.changed_data = ['from_name'] |
320 | 320 |
action_edit_form.cleaned_data = {'from_name': 'new'} |
... | ... | |
323 | 323 |
'authenticator.saml.related_object.deletion', |
324 | 324 |
user=agent, |
325 | 325 |
session=session2, |
326 |
related_object=rename_attribute_action,
|
|
326 |
related_object=set_attribute_action,
|
|
327 | 327 |
) |
328 | 328 |
make('authenticator.oidc.claim.creation', user=agent, session=session2, claim=oidc_claim_mapping) |
329 | 329 |
claim_edit_form = mock.Mock(spec=['instance', 'initial', 'changed_data', 'cleaned_data']) |
... | ... | |
369 | 369 | |
370 | 370 |
def test_global_journal(app, superuser, events): |
371 | 371 |
response = login(app, user=superuser, path="/manage/") |
372 |
rename_attribute_action = RenameAttributeAction.objects.get()
|
|
372 |
set_attribute_action = SetAttributeAction.objects.get()
|
|
373 | 373 |
oidc_claim_mapping = OIDCClaimMapping.objects.get() |
374 | 374 | |
375 | 375 |
# remove event about admin login |
... | ... | |
727 | 727 |
'user': 'agent', |
728 | 728 |
}, |
729 | 729 |
{ |
730 |
'message': 'creation of RenameAttributeAction (%s) in authenticator "SAML"'
|
|
731 |
% rename_attribute_action.pk,
|
|
730 |
'message': 'creation of SetAttributeAction (%s) in authenticator "SAML"'
|
|
731 |
% set_attribute_action.pk,
|
|
732 | 732 |
'timestamp': 'Jan. 3, 2020, 8 a.m.', |
733 | 733 |
'type': 'authenticator.saml.related_object.creation', |
734 | 734 |
'user': 'agent', |
735 | 735 |
}, |
736 | 736 |
{ |
737 |
'message': 'edit RenameAttributeAction (%s) in authenticator "SAML" (from_name)'
|
|
738 |
% rename_attribute_action.pk,
|
|
737 |
'message': 'edit SetAttributeAction (%s) in authenticator "SAML" (from_name)'
|
|
738 |
% set_attribute_action.pk,
|
|
739 | 739 |
'timestamp': 'Jan. 3, 2020, 9 a.m.', |
740 | 740 |
'type': 'authenticator.saml.related_object.edit', |
741 | 741 |
'user': 'agent', |
742 | 742 |
}, |
743 | 743 |
{ |
744 |
'message': 'deletion of RenameAttributeAction (%s) in authenticator "SAML"'
|
|
745 |
% rename_attribute_action.pk,
|
|
744 |
'message': 'deletion of SetAttributeAction (%s) in authenticator "SAML"'
|
|
745 |
% set_attribute_action.pk,
|
|
746 | 746 |
'timestamp': 'Jan. 3, 2020, 10 a.m.', |
747 | 747 |
'type': 'authenticator.saml.related_object.deletion', |
748 | 748 |
'user': 'agent', |
749 |
- |