Project

General

Profile

0001-idp_oidc-remove-client-config-through-django-s-admin.patch

Paul Marillonnet, 25 November 2022 11:02 AM

Download (8.09 KB)

View differences:

Subject: [PATCH] idp_oidc: remove client config through django's admin pages
 (#71700)

This removal ensures that OIDC configuration happens through /manage/ pages as part of
Publik's backoffice interface.
 src/authentic2_idp_oidc/admin.py | 125 -------------------------------
 tests/idp_oidc/conftest.py       |   5 +-
 tests/idp_oidc/test_misc.py      |  28 -------
 3 files changed, 2 insertions(+), 156 deletions(-)
 delete mode 100644 src/authentic2_idp_oidc/admin.py
src/authentic2_idp_oidc/admin.py
1
# authentic2 - versatile identity manager
2
# Copyright (C) 2010-2019 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from functools import partialmethod
18

  
19
from django import forms
20
from django.contrib import admin
21

  
22
from authentic2.attributes_ng.engine import get_service_attributes
23
from authentic2.forms.widgets import DatalistTextInput
24

  
25
from . import app_settings, models
26

  
27

  
28
class OIDCClaimInlineForm(forms.ModelForm):
29
    def __init__(self, *args, **kwargs):
30
        super().__init__(*args, **kwargs)
31
        data = dict(get_service_attributes(getattr(self.instance, 'client', None))).keys()
32
        widget = self.fields['value'].widget
33
        widget.data = data
34
        widget.name = 'list__oidcclaim-inline'
35
        widget.attrs.update({'list': 'list__oidcclaim-inline'})
36

  
37
    class Meta:
38
        model = models.OIDCClaim
39
        fields = ['name', 'value', 'scopes']
40
        widgets = {
41
            'value': DatalistTextInput,
42
        }
43

  
44

  
45
class OIDCClaimInlineAdmin(admin.TabularInline):
46

  
47
    model = models.OIDCClaim
48
    form = OIDCClaimInlineForm
49
    extra = 0
50

  
51
    def get_formset(self, request, obj=None, **kwargs):
52
        initial = []
53
        # formsets are only saved if formset.has_changed() is True, so only set initial
54
        # values on the GET (display of the creation form)
55
        if request.method == 'GET' and not obj:
56
            initial.extend(app_settings.DEFAULT_MAPPINGS)
57
            self.extra = 5
58
        formset = super().get_formset(request, obj=obj, **kwargs)
59
        formset.__init__ = partialmethod(formset.__init__, initial=initial)
60
        return formset
61

  
62

  
63
class OIDCClientAdmin(admin.ModelAdmin):
64
    list_display = [
65
        'name',
66
        'slug',
67
        'client_id',
68
        'ou',
69
        'identifier_policy',
70
        'created',
71
        'modified',
72
        'activate_user_profiles',
73
    ]
74
    list_filter = ['ou', 'identifier_policy']
75
    date_hierarchy = 'modified'
76
    readonly_fields = ['created', 'modified']
77
    inlines = [OIDCClaimInlineAdmin]
78

  
79

  
80
class OIDCAuthorizationAdmin(admin.ModelAdmin):
81
    list_display = ['client', 'user', 'created', 'expired']
82
    search_fields = ['user__first_name', 'user__last_name', 'user__email', 'user__username']
83
    date_hierarchy = 'created'
84
    readonly_fields = ['created', 'expired']
85

  
86
    def get_queryset(self, request):
87
        qs = super().get_queryset(request)
88
        qs = qs.prefetch_related('client')
89
        return qs
90

  
91
    def get_search_results(self, request, queryset, search_term):
92
        from django.contrib.contenttypes.models import ContentType
93

  
94
        from authentic2.a2_rbac.models import OrganizationalUnit as OU
95

  
96
        queryset, use_distinct = super().get_search_results(request, queryset, search_term)
97
        clients = models.OIDCClient.objects.filter(name__contains=search_term).values_list('pk')
98
        ous = OU.objects.filter(name__contains=search_term).values_list('pk')
99
        queryset |= self.model.objects.filter(
100
            client_ct=ContentType.objects.get_for_model(models.OIDCClient), client_id=clients
101
        )
102
        queryset |= self.model.objects.filter(client_ct=ContentType.objects.get_for_model(OU), client_id=ous)
103
        return queryset, use_distinct
104

  
105

  
106
class OIDCCodeAdmin(admin.ModelAdmin):
107
    list_display = ['client', 'user', 'uuid', 'created', 'expired']
108
    list_filter = ['client']
109
    search_fields = ['user__first_name', 'user__last_name', 'user__email', 'user__username', 'client__name']
110
    date_hierarchy = 'created'
111
    readonly_fields = ['uuid', 'created', 'expired', 'user', 'uuid', 'client', 'state', 'nonce']
112

  
113

  
114
class OIDCAccessTokenAdmin(admin.ModelAdmin):
115
    list_display = ['client', 'user', 'uuid', 'created', 'expired']
116
    list_filter = ['client']
117
    search_fields = ['user__first_name', 'user__last_name', 'user__email', 'user__username', 'client__name']
118
    date_hierarchy = 'created'
119
    readonly_fields = ['uuid', 'created', 'expired']
120

  
121

  
122
admin.site.register(models.OIDCClient, OIDCClientAdmin)
123
admin.site.register(models.OIDCAuthorization, OIDCAuthorizationAdmin)
124
admin.site.register(models.OIDCCode, OIDCCodeAdmin)
125
admin.site.register(models.OIDCAccessToken, OIDCAccessTokenAdmin)
tests/idp_oidc/conftest.py
138 138

  
139 139
@pytest.fixture
140 140
def normal_oidc_client(superuser, app, simple_user):
141
    url = reverse('admin:authentic2_idp_oidc_oidcclient_add')
141
    url = reverse('a2-manager-add-oidc-service')
142 142
    assert OIDCClient.objects.count() == 0
143 143
    response = utils.login(app, superuser, path=url)
144 144
    response.form.set('name', 'oidcclient')
145
    response.form.set('slug', 'oidcclient')
146 145
    response.form.set('ou', get_default_ou().pk)
147 146
    response.form.set('unauthorized_url', 'https://example.com/southpark/')
148 147
    response.form.set('redirect_uris', 'https://example.com/callbac%C3%A9')
149
    response = response.form.submit(name='_save').follow()
148
    response = response.form.submit().follow()
150 149
    assert OIDCClient.objects.count() == 1
151 150
    client = OIDCClient.objects.get()
152 151
    utils.logout(app)
tests/idp_oidc/test_misc.py
109 109
]
110 110

  
111 111

  
112
@pytest.mark.parametrize('other_attributes', OIDC_CLIENT_PARAMS)
113
def test_admin(other_attributes, app, superuser, oidc_settings):
114
    Attribute.objects.create(
115
        name='cityscape_image',
116
        label='cityscape',
117
        kind='profile_image',
118
        asked_on_registration=True,
119
        required=False,
120
        user_visible=True,
121
        user_editable=True,
122
    )
123

  
124
    url = reverse('admin:authentic2_idp_oidc_oidcclient_add')
125
    assert OIDCClient.objects.count() == 0
126
    response = utils.login(app, superuser, path=url)
127
    response.form.set('name', 'oidcclient')
128
    response.form.set('slug', 'oidcclient')
129
    response.form.set('ou', get_default_ou().pk)
130
    response.form.set('unauthorized_url', 'https://example.com/southpark/')
131
    response.form.set('redirect_uris', 'https://example.com/callbac%C3%A9')
132
    for key, value in other_attributes.items():
133
        if isinstance(value, datetime.timedelta):
134
            value = f'{value.total_seconds()}'
135
        response.form.set(key, value)
136
    response = response.form.submit().follow()
137
    assert OIDCClient.objects.count() == 1
138

  
139

  
140 112
def test_login_from_client_with_home_url(oidc_client, app, simple_user):
141 113
    redirect_uri = oidc_client.redirect_uris.split()[0]
142 114
    params = {
143
-