Projet

Général

Profil

0002-auth_saml-display-xml-metadata-in-separate-view-7049.patch

Valentin Deniaud, 20 octobre 2022 17:42

Télécharger (6,25 ko)

Voir les différences:

Subject: [PATCH 2/2] auth_saml: display xml metadata in separate view (#70492)

 src/authentic2/apps/authenticators/models.py | 10 +++++----
 src/authentic2_auth_saml/models.py           |  9 ++++++++
 src/authentic2_auth_saml/urls.py             | 11 ++++++++--
 src/authentic2_auth_saml/views.py            | 23 ++++++++++++++++++++
 tests/test_manager_authenticators.py         | 19 ++++++++++++++++
 5 files changed, 66 insertions(+), 6 deletions(-)
src/authentic2/apps/authenticators/models.py
24 24
from django.db.models import Max
25 25
from django.shortcuts import render, reverse
26 26
from django.utils.formats import date_format
27
from django.utils.html import format_html
27 28
from django.utils.text import capfirst
28 29
from django.utils.translation import gettext_lazy as _
29 30
from django.utils.translation import pgettext_lazy
......
126 127
            if isinstance(value, datetime.datetime):
127 128
                value = date_format(value, 'DATETIME_FORMAT')
128 129

  
129
            yield _('%(field)s: %(value)s') % {
130
                'field': capfirst(self._meta.get_field(field).verbose_name),
131
                'value': value,
132
            }
130
            yield format_html(
131
                _('{field}: {value}'),
132
                field=capfirst(self._meta.get_field(field).verbose_name),
133
                value=value,
134
            )
133 135

  
134 136
    def shown(self, ctx=()):
135 137
        if not self.show_condition:
src/authentic2_auth_saml/models.py
21 21
from django.contrib.postgres.fields import JSONField
22 22
from django.core.exceptions import ValidationError
23 23
from django.db import models
24
from django.urls import reverse
25
from django.utils.safestring import mark_safe
24 26
from django.utils.translation import gettext_lazy as _
25 27

  
26 28
from authentic2.apps.authenticators.models import (
......
221 223
            getattr(settings, 'MELLON_PRIVATE_KEY', '') and getattr(settings, 'MELLON_PUBLIC_KEYS', '')
222 224
        )
223 225

  
226
    def get_metadata_display(self):
227
        if not self.metadata:
228
            return ''
229

  
230
        url = reverse('a2-manager-saml-authenticator-metadata', kwargs={'pk': self.pk})
231
        return mark_safe('<a href=%s>%s</a>' % (url, _('View metadata')))
232

  
224 233
    def login(self, request, *args, **kwargs):
225 234
        from . import views
226 235

  
src/authentic2_auth_saml/urls.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from django.urls import include, re_path
17
from django.urls import include, path, re_path
18

  
19
from . import views
18 20

  
19 21
urlpatterns = [
20 22
    re_path(
21 23
        r'^accounts/saml/',
22 24
        include('mellon.urls'),
23 25
        kwargs={'template_base': 'authentic2/base.html', 'logout_next_url': '/logout/'},
24
    )
26
    ),
27
    path(
28
        'authenticators/<int:pk>/metadata.xml',
29
        views.authenticator_metadata,
30
        name='a2-manager-saml-authenticator-metadata',
31
    ),
25 32
]
src/authentic2_auth_saml/views.py
1
import xml.etree.ElementTree as ET
2

  
3
from django.http import Http404, HttpResponse
1 4
from django.shortcuts import render
2 5
from django.template.loader import render_to_string
6
from django.views.generic import DetailView
3 7
from mellon.utils import get_idp
4 8

  
5 9
from authentic2.utils.misc import redirect_to_login
6 10

  
11
from .models import SAMLAuthenticator
12

  
7 13

  
8 14
def login(request, authenticator, *args, **kwargs):
9 15
    context = kwargs.pop('context', {}).copy()
......
34 40
        user_saml_identifier.idp = get_idp(user_saml_identifier.issuer.entity_id)
35 41
    context['user_saml_identifiers'] = user_saml_identifiers
36 42
    return render_to_string('authentic2_auth_saml/profile.html', context, request=request)
43

  
44

  
45
class SAMLAuthenticatorMetadataView(DetailView):
46
    model = SAMLAuthenticator
47

  
48
    def get(self, *args, **kwargs):
49
        authenticator = self.get_object()
50
        if not authenticator.metadata:
51
            raise Http404()
52

  
53
        metadata = ET.fromstring(authenticator.metadata)
54
        ET.indent(metadata)
55

  
56
        return HttpResponse(ET.tostring(metadata, encoding='utf-8'), content_type='text/xml')
57

  
58

  
59
authenticator_metadata = SAMLAuthenticatorMetadataView.as_view()
tests/test_manager_authenticators.py
505 505
    resp.form.submit(status=302)
506 506

  
507 507

  
508
def test_authenticators_saml_view_metadata(app, superuser):
509
    authenticator = SAMLAuthenticator.objects.create(slug='idp1')
510

  
511
    resp = login(app, superuser)
512
    resp = app.get('/manage/authenticators/%s/detail/' % authenticator.pk)
513

  
514
    assert 'Metadata (XML):' not in resp.text
515
    assert app.get('/manage/authenticators/%s/metadata.xml' % authenticator.pk, status=404)
516

  
517
    authenticator.metadata = '<a><b></b></a>'
518
    authenticator.save()
519

  
520
    resp = app.get('/manage/authenticators/%s/detail/' % authenticator.pk)
521
    assert 'Metadata (XML):' in resp.text
522

  
523
    resp = resp.click('View metadata')
524
    assert resp.text == '<a>\n  <b />\n</a>'
525

  
526

  
508 527
def test_authenticators_saml_missing_signing_key(app, superuser, settings):
509 528
    authenticator = SAMLAuthenticator.objects.create(slug='idp1')
510 529

  
511
-