providers/saml: make SAML metadata generation consistent

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-05-13 17:40:18 +02:00
parent 25910bb577
commit 1363226697
3 changed files with 36 additions and 4 deletions

View File

@ -1,4 +1,5 @@
"""SAML Identity Provider Metadata Processor""" """SAML Identity Provider Metadata Processor"""
from hashlib import sha256
from typing import Iterator, Optional from typing import Iterator, Optional
import xmlsec # nosec import xmlsec # nosec
@ -7,7 +8,6 @@ from django.urls import reverse
from lxml.etree import Element, SubElement, tostring # nosec from lxml.etree import Element, SubElement, tostring # nosec
from authentik.providers.saml.models import SAMLProvider from authentik.providers.saml.models import SAMLProvider
from authentik.providers.saml.utils import get_random_id
from authentik.providers.saml.utils.encoding import strip_pem_header from authentik.providers.saml.utils.encoding import strip_pem_header
from authentik.sources.saml.processors.constants import ( from authentik.sources.saml.processors.constants import (
DIGEST_ALGORITHM_TRANSLATION_MAP, DIGEST_ALGORITHM_TRANSLATION_MAP,
@ -35,7 +35,7 @@ class MetadataProcessor:
self.provider = provider self.provider = provider
self.http_request = request self.http_request = request
self.force_binding = None self.force_binding = None
self.xml_id = get_random_id() self.xml_id = sha256(f"{provider.name}-{provider.pk}".encode("ascii")).hexdigest()
def get_signing_key_descriptor(self) -> Optional[Element]: def get_signing_key_descriptor(self) -> Optional[Element]:
"""Get Signing KeyDescriptor, if enabled for the provider""" """Get Signing KeyDescriptor, if enabled for the provider"""

View File

@ -1,10 +1,12 @@
"""Test Service-Provider Metadata Parser""" """Test Service-Provider Metadata Parser"""
# flake8: noqa # flake8: noqa
from django.test import TestCase from django.test import RequestFactory, TestCase
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.metadata import MetadataProcessor
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
METADATA_SIMPLE = """<?xml version="1.0"?> METADATA_SIMPLE = """<?xml version="1.0"?>
@ -66,6 +68,23 @@ class TestServiceProviderMetadataParser(TestCase):
def setUp(self) -> None: def setUp(self) -> None:
self.flow = create_test_flow() self.flow = create_test_flow()
self.factory = RequestFactory()
def test_consistent(self):
"""Test that metadata generation is consistent"""
provider = SAMLProvider.objects.create(
name="test",
authorization_flow=self.flow,
)
Application.objects.create(
name="test",
slug="test",
provider=provider,
)
request = self.factory.get("/")
metadata_a = MetadataProcessor(provider, request).build_entity_descriptor()
metadata_b = MetadataProcessor(provider, request).build_entity_descriptor()
self.assertEqual(metadata_a, metadata_b)
def test_simple(self): def test_simple(self):
"""Test simple metadata without Signing""" """Test simple metadata without Signing"""

View File

@ -29,6 +29,19 @@ class TestMetadataProcessor(TestCase):
schema = etree.XMLSchema(etree.parse("xml/saml-schema-metadata-2.0.xsd")) # nosec schema = etree.XMLSchema(etree.parse("xml/saml-schema-metadata-2.0.xsd")) # nosec
self.assertTrue(schema.validate(metadata)) self.assertTrue(schema.validate(metadata))
def test_metadata_consistent(self):
"""Test Metadata generation being consistent (xml stays the same)"""
source = SAMLSource.objects.create(
slug="provider",
issuer="authentik",
signing_kp=create_test_cert(),
pre_authentication_flow=create_test_flow(),
)
request = self.factory.get("/")
xml_a = MetadataProcessor(source, request).build_entity_descriptor()
xml_b = MetadataProcessor(source, request).build_entity_descriptor()
self.assertEqual(xml_a, xml_b)
def test_metadata(self): def test_metadata(self):
"""Test Metadata generation being valid""" """Test Metadata generation being valid"""
source = SAMLSource.objects.create( source = SAMLSource.objects.create(