Projet

Général

Profil

0001-auth_saml-remove-rename-attribute-action-68383.patch

Valentin Deniaud, 15 septembre 2022 17:29

Télécharger (16,2 ko)

Voir les différences:

Subject: [PATCH] auth_saml: remove rename attribute action (#68383)

 src/authentic2_auth_saml/adapters.py          |  6 ---
 .../0009_statically_rename_attributes.py      | 33 ++++++++++++
 .../0010_delete_renameattributeaction.py      | 16 ++++++
 src/authentic2_auth_saml/models.py            | 12 -----
 .../authenticator_detail.html                 |  5 --
 src/authentic2_auth_saml/views.py             | 10 +---
 tests/test_auth_saml.py                       | 50 ++++++++++++++++---
 tests/test_manager_authenticators.py          | 11 ----
 tests/test_manager_journal.py                 | 24 ++++-----
 9 files changed, 106 insertions(+), 61 deletions(-)
 create mode 100644 src/authentic2_auth_saml/migrations/0009_statically_rename_attributes.py
 create mode 100644 src/authentic2_auth_saml/migrations/0010_delete_renameattributeaction.py
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
-