Projet

Général

Profil

0001-auth_saml-validate-xml-metadata-70492.patch

Valentin Deniaud, 24 octobre 2022 12:20

Télécharger (4,85 ko)

Voir les différences:

Subject: [PATCH 1/2] auth_saml: validate xml metadata (#70492)

 .../migrations/0001_initial.py                | 11 ++++++++-
 src/authentic2_auth_saml/models.py            | 19 ++++++++++++++-
 tests/test_manager_authenticators.py          | 24 +++++++++++++++++++
 3 files changed, 52 insertions(+), 2 deletions(-)
src/authentic2_auth_saml/migrations/0001_initial.py
4 4
import django.db.models.deletion
5 5
from django.db import migrations, models
6 6

  
7
import authentic2_auth_saml.models
8

  
7 9

  
8 10
class Migration(migrations.Migration):
9 11

  
......
46 48
                        verbose_name='Metadata file path',
47 49
                    ),
48 50
                ),
49
                ('metadata', models.TextField(blank=True, verbose_name='Metadata (XML)')),
51
                (
52
                    'metadata',
53
                    models.TextField(
54
                        blank=True,
55
                        validators=[authentic2_auth_saml.models.validate_metadata],
56
                        verbose_name='Metadata (XML)',
57
                    ),
58
                ),
50 59
                (
51 60
                    'provision',
52 61
                    models.BooleanField(
src/authentic2_auth_saml/models.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
import xml.etree.ElementTree as ET
18

  
19
import lasso
17 20
from django.conf import settings
18 21
from django.contrib.postgres.fields import JSONField
19 22
from django.core.exceptions import ValidationError
......
28 31
from authentic2.utils.misc import redirect_to_login
29 32

  
30 33

  
34
def validate_metadata(metadata):
35
    try:
36
        doc = ET.fromstring(metadata)
37
    except (TypeError, ET.ParseError) as e:
38
        raise ValidationError(_('Cannot parse metadata, %s') % e)
39

  
40
    tag_name = '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF
41
    if doc.tag != tag_name:
42
        raise ValidationError(_('Invalid metadata, missing tag %s') % tag_name)
43

  
44
    if 'entityID' not in doc.attrib:
45
        raise ValidationError(_('Invalid metadata, missing entityID'))
46

  
47

  
31 48
class SAMLAuthenticator(BaseAuthenticator):
32 49
    metadata_url = models.URLField(_('Metadata URL'), max_length=300, blank=True)
33 50
    metadata_cache_time = models.PositiveSmallIntegerField(_('Metadata cache time'), default=3600)
......
39 56
        help_text=_('Absolute path to the IdP metadata file.'),
40 57
        blank=True,
41 58
    )
42
    metadata = models.TextField(_('Metadata (XML)'), blank=True)
59
    metadata = models.TextField(_('Metadata (XML)'), blank=True, validators=[validate_metadata])
43 60

  
44 61
    provision = models.BooleanField(_('Create user if their username does not already exists'), default=True)
45 62
    verify_ssl_certificate = models.BooleanField(
tests/test_manager_authenticators.py
481 481
    assert 'Metadata HTTP timeout' in resp.text
482 482

  
483 483

  
484
def test_authenticators_saml_validate_metadata(app, superuser):
485
    authenticator = SAMLAuthenticator.objects.create(slug='idp1')
486

  
487
    resp = login(app, superuser)
488
    resp = app.get('/manage/authenticators/%s/edit/' % authenticator.pk)
489
    resp.form['metadata'] = 'invalid'
490

  
491
    resp.form['metadata'] = '<a/>'
492
    resp = resp.form.submit()
493
    assert 'Invalid metadata, missing tag {urn:oasis:names:tc:SAML:2.0:metadata}EntityDescriptor' in resp.text
494

  
495
    resp.form[
496
        'metadata'
497
    ] = '<ns0:EntityDescriptor xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"></ns0:EntityDescriptor>'
498
    resp = resp.form.submit()
499
    assert 'Invalid metadata, missing entityID' in resp.text
500

  
501
    resp.form['metadata'] = (
502
        '<ns0:EntityDescriptor xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"'
503
        ' entityID="https://example.com"></ns0:EntityDescriptor>'
504
    )
505
    resp.form.submit(status=302)
506

  
507

  
484 508
def test_authenticators_saml_missing_signing_key(app, superuser, settings):
485 509
    authenticator = SAMLAuthenticator.objects.create(slug='idp1')
486 510

  
487
-