0001-auth_saml-prefer-metadata-file-upload-over-metadata-.patch
src/authentic2/apps/authenticators/models.py | ||
---|---|---|
20 | 20 | |
21 | 21 |
from django.core.exceptions import ValidationError |
22 | 22 |
from django.db import models |
23 |
from django.db.models.fields.files import FieldFile |
|
23 | 24 |
from django.shortcuts import render, reverse |
24 | 25 |
from django.utils.formats import date_format |
26 |
from django.utils.html import format_html |
|
27 |
from django.utils.safestring import mark_safe |
|
25 | 28 |
from django.utils.text import capfirst |
26 | 29 |
from django.utils.translation import pgettext_lazy |
27 | 30 |
from django.utils.translation import ugettext_lazy as _ |
... | ... | |
111 | 114 | |
112 | 115 |
if isinstance(value, datetime.datetime): |
113 | 116 |
value = date_format(value, 'DATETIME_FORMAT') |
114 | ||
115 |
yield _('%(field)s: %(value)s') % { |
|
116 |
'field': capfirst(self._meta.get_field(field).verbose_name), |
|
117 |
'value': value, |
|
118 |
} |
|
117 |
elif isinstance(value, FieldFile): |
|
118 |
value = mark_safe(f'<a href={value.url}>{value.name}</a>') |
|
119 | ||
120 |
yield format_html( |
|
121 |
_('{field}: {value}'), |
|
122 |
field=capfirst(self._meta.get_field(field).verbose_name), |
|
123 |
value=value, |
|
124 |
) |
|
119 | 125 | |
120 | 126 |
def shown(self, ctx=()): |
121 | 127 |
if not self.show_condition: |
src/authentic2_auth_saml/forms.py | ||
---|---|---|
27 | 27 |
model = SAMLAuthenticator |
28 | 28 |
exclude = ('ou',) |
29 | 29 | |
30 |
def __init__(self, *args, **kwargs): |
|
31 |
super().__init__(*args, **kwargs) |
|
32 |
if not self.initial.get('metadata_path'): |
|
33 |
del self.fields['metadata_path'] |
|
34 | ||
30 | 35 | |
31 | 36 |
class RoleChoiceField(forms.ModelChoiceField): |
32 | 37 |
def __init__(self, *args, **kwargs): |
src/authentic2_auth_saml/migrations/0008_samlauthenticator_metadata_file.py | ||
---|---|---|
1 |
# Generated by Django 2.2.26 on 2022-08-24 13:12 |
|
2 | ||
3 |
from django.db import migrations, models |
|
4 | ||
5 | ||
6 |
class Migration(migrations.Migration): |
|
7 | ||
8 |
dependencies = [ |
|
9 |
('authentic2_auth_saml', '0007_remove_jsonfields'), |
|
10 |
] |
|
11 | ||
12 |
operations = [ |
|
13 |
migrations.AddField( |
|
14 |
model_name='samlauthenticator', |
|
15 |
name='metadata_file', |
|
16 |
field=models.FileField(blank=True, null=True, upload_to=''), |
|
17 |
), |
|
18 |
] |
src/authentic2_auth_saml/models.py | ||
---|---|---|
30 | 30 |
metadata_cache_time = models.PositiveSmallIntegerField(_('Metadata cache time'), default=3600) |
31 | 31 |
metadata_http_timeout = models.PositiveSmallIntegerField(_('Metadata HTTP timeout'), default=10) |
32 | 32 | |
33 |
metadata_file = models.FileField(null=True, blank=True) |
|
33 | 34 |
metadata_path = models.CharField( |
34 | 35 |
_('Metadata file path'), |
35 | 36 |
max_length=300, |
... | ... | |
147 | 148 |
description_fields = [ |
148 | 149 |
'show_condition', |
149 | 150 |
'metadata_url', |
151 |
'metadata_file', |
|
150 | 152 |
'metadata_path', |
151 | 153 |
'metadata', |
152 | 154 |
'provision', |
... | ... | |
166 | 168 |
if not settings[setting]: |
167 | 169 |
del settings[setting] |
168 | 170 | |
171 |
if self.metadata_file: |
|
172 |
settings['METADATA_PATH'] = self.metadata_file.path |
|
173 | ||
169 | 174 |
settings['LOOKUP_BY_ATTRIBUTES'] = [lookup.as_dict() for lookup in self.attribute_lookups.all()] |
170 | 175 | |
171 | 176 |
settings['authenticator'] = self |
... | ... | |
178 | 183 |
return SAMLAuthenticatorForm |
179 | 184 | |
180 | 185 |
def clean(self): |
181 |
if not (self.metadata or self.metadata_path or self.metadata_url): |
|
186 |
if not (self.metadata or self.metadata_path or self.metadata_url or self.metadata_file):
|
|
182 | 187 |
raise ValidationError(_('One of the metadata fields must be filled.')) |
183 | 188 | |
184 | 189 |
def autorun(self, request, block_id): |
tests/test_manager_authenticators.py | ||
---|---|---|
17 | 17 |
import pytest |
18 | 18 |
from django import VERSION as DJ_VERSION |
19 | 19 |
from django.utils.html import escape |
20 |
from webtest import Upload |
|
20 | 21 | |
21 | 22 |
from authentic2.a2_rbac.utils import get_default_ou |
22 | 23 |
from authentic2.apps.authenticators.models import BaseAuthenticator, LoginPasswordAuthenticator |
... | ... | |
256 | 257 |
resp = app.get(authenticator.get_absolute_url()) |
257 | 258 |
assert 'Username template: {attributes[name_id_content]}@{realm}' in resp.text |
258 | 259 |
assert 'Provision: True' in resp.text |
259 |
assert 'Metadata file path' not in resp.text
|
|
260 |
assert 'Metadata file' not in resp.text |
|
260 | 261 | |
261 | 262 |
assert 'Enable' not in resp.text |
262 | 263 |
assert 'configuration is not complete' in resp.text |
263 | 264 | |
264 | 265 |
resp = resp.click('Edit') |
266 |
assert 'metadata_path' not in resp.form.fields |
|
267 | ||
265 | 268 |
resp = resp.form.submit() |
266 | 269 |
assert 'One of the metadata fields must be filled.' in resp.text |
267 | 270 | |
268 |
resp.form['metadata_path'] = '/var/lib/authentic2/metadata.xml'
|
|
271 |
resp.form['metadata_file'] = Upload('metadata.xml', b'<xml>some-xml</xml>', 'text/xml')
|
|
269 | 272 |
resp.form['attribute_mapping'] = '[{"attribute": "email", "saml_attribute": "mail", "mandatory": false}]' |
270 | 273 |
resp = resp.form.submit().follow() |
271 | 274 | |
272 |
assert 'Metadata file path: /var/lib/authentic2/metadata.xml' in resp.text
|
|
275 |
assert 'Metadata file: <a href=/media/metadata.xml>metadata.xml</a>' in resp.text
|
|
273 | 276 | |
274 | 277 |
authenticator.refresh_from_db() |
275 | 278 |
assert authenticator.attribute_mapping == [ |
... | ... | |
279 | 282 |
resp = resp.click('Enable').follow() |
280 | 283 |
assert 'Authenticator has been enabled.' in resp.text |
281 | 284 | |
285 |
authenticator.metadata_file = None |
|
286 |
authenticator.metadata_path = '/var/lib/authentic2/metadata.xml' |
|
287 |
authenticator.save() |
|
288 | ||
289 |
resp = resp.click('Edit') |
|
290 |
assert 'metadata_path' in resp.form.fields |
|
291 | ||
282 | 292 | |
283 | 293 |
def test_authenticators_saml_attribute_lookup(app, superuser): |
284 | 294 |
authenticator = SAMLAuthenticator.objects.create(metadata='meta1.xml', slug='idp1') |
285 |
- |