From 71753bfebd236d21944790f3aefc35c72176472a Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Wed, 5 Aug 2026 10:31:36 +0200 Subject: [PATCH 01/11] Import schema --- resources/schemas/saml-async-slo-v1.0.xsd | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 resources/schemas/saml-async-slo-v1.0.xsd diff --git a/resources/schemas/saml-async-slo-v1.0.xsd b/resources/schemas/saml-async-slo-v1.0.xsd new file mode 100644 index 000000000..2a64b8917 --- /dev/null +++ b/resources/schemas/saml-async-slo-v1.0.xsd @@ -0,0 +1,13 @@ + + + + + + + + + + From 9bfe530c1dd2afac2853d801212da5d654ace953 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Wed, 5 Aug 2026 10:49:23 +0200 Subject: [PATCH 02/11] Update class-registry --- classes/element.registry.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/classes/element.registry.php b/classes/element.registry.php index 04b8d47de..c33e56524 100644 --- a/classes/element.registry.php +++ b/classes/element.registry.php @@ -3,6 +3,9 @@ declare(strict_types=1); return [ + 'urn:oasis:names:tc:SAML:2.0:protocol:ext:async-slo' => [ + 'Asynchronous' => '\SimpleSAML\SAML2\XML\aslo\Asynchronous', + ], 'urn:oasis:names:tc:SAML:metadata:algsupport' => [ 'DigestMethod' => '\SimpleSAML\SAML2\XML\alg\DigestMethod', 'SigningMethod' => '\SimpleSAML\SAML2\XML\alg\SigningMethod', From 4450458c27298f28622a47763dcec9f32c076e89 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Wed, 5 Aug 2026 10:51:51 +0200 Subject: [PATCH 03/11] Add abstract and NS-constant --- src/Constants.php | 5 +++++ src/XML/aslo/AbstractAlsoElement.php | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/XML/aslo/AbstractAlsoElement.php diff --git a/src/Constants.php b/src/Constants.php index 968fd7817..ac884ff07 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -226,6 +226,11 @@ class Constants extends \SimpleSAML\XMLSecurity\Constants */ public const string NS_ALG = 'urn:oasis:names:tc:SAML:metadata:algsupport'; + /** + * The namespace for the SAML 2 Asynchronous Single Logout Profile Extension + */ + public const string NS_ASLO = 'urn:oasis:names:tc:SAML:2.0:protocol:ext:async-slo'; + /** * The namespace for the ECP protocol. */ diff --git a/src/XML/aslo/AbstractAlsoElement.php b/src/XML/aslo/AbstractAlsoElement.php new file mode 100644 index 000000000..054ae8f14 --- /dev/null +++ b/src/XML/aslo/AbstractAlsoElement.php @@ -0,0 +1,23 @@ + Date: Mon, 10 Aug 2026 22:04:11 +0200 Subject: [PATCH 04/11] Implement Asynchronous SLO schema items --- src/XML/aslo/Asynchronous.php | 45 ++++++++++++ src/XML/aslo/SupportsAsynchronousTrait.php | 34 +++++++++ src/XML/md/SingleLogoutService.php | 80 ++++++++++++++++++++++ tests/SAML2/XML/aslo/AsynchronousTest.php | 57 +++++++++++++++ tests/resources/xml/aslo_Asynchronous.xml | 1 + 5 files changed, 217 insertions(+) create mode 100644 src/XML/aslo/Asynchronous.php create mode 100644 src/XML/aslo/SupportsAsynchronousTrait.php create mode 100644 tests/SAML2/XML/aslo/AsynchronousTest.php create mode 100644 tests/resources/xml/aslo_Asynchronous.xml diff --git a/src/XML/aslo/Asynchronous.php b/src/XML/aslo/Asynchronous.php new file mode 100644 index 000000000..50ffca5ea --- /dev/null +++ b/src/XML/aslo/Asynchronous.php @@ -0,0 +1,45 @@ +localName, 'Asynchronous', InvalidDOMElementException::class); + Assert::same($xml->namespaceURI, Asynchronous::NS, InvalidDOMElementException::class); + + return new static(); + } + + + /** + * Convert this Asynchronous to XML. + */ + public function toXML(?Dom\Element $parent = null): Dom\Element + { + return $this->instantiateParentElement($parent); + } +} diff --git a/src/XML/aslo/SupportsAsynchronousTrait.php b/src/XML/aslo/SupportsAsynchronousTrait.php new file mode 100644 index 000000000..e928a97a3 --- /dev/null +++ b/src/XML/aslo/SupportsAsynchronousTrait.php @@ -0,0 +1,34 @@ +supportsAsynchronous; + } + + + /** + * @param \SimpleSAML\XMLSchema\Type\BooleanValue $supportsAsynchronous|null + */ + private function setSupportsAsynchronous(?BooleanValue $supportsAsynchronous): void + { + $this->supportsAsynchronous = $supportsAsynchronous; + } +} diff --git a/src/XML/md/SingleLogoutService.php b/src/XML/md/SingleLogoutService.php index 6cfcf1842..ad78dc96b 100644 --- a/src/XML/md/SingleLogoutService.php +++ b/src/XML/md/SingleLogoutService.php @@ -4,6 +4,10 @@ namespace SimpleSAML\SAML2\XML\md; +use Dom; +use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait; +use SimpleSAML\XMLSchema\Type\BooleanValue; + /** * SingleLogoutService element of type EndpointType * @@ -11,4 +15,80 @@ */ final class SingleLogoutService extends AbstractEndpointType { + use SupportsAsynchronousTrait; + + + /** + * SingleLogoutService constructor. + * + * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue $binding + * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue $location + * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null $responseLocation + * @param \SimpleSAML\XMLSchema\Type\BooleanValue $supportsAsynchronous + * @param \SimpleSAML\XML\ElementInterface[] $children + * @param array<\SimpleSAML\XML\Attribute> $attributes + * + * @throws \SimpleSAML\Assert\AssertionFailedException + */ + public function __construct( + SAMLAnyURIValue $binding, + SAMLAnyURIValue $location, + ?SAMLAnyURIValue $responseLocation = null, + protected ?BooleanValue $supportsAsynchronous = null, + array $children = [], + array $attributes = [], + ) { + $this->setSupportsAsynchronous($supportsAsynchronous); + + parent::__construct($binding, $location, $responseLocation, $children, $attributes); + } + + + + /** + * Initialize a SingleLogoutService. + * + * @param \Dom\Element $xml The XML element we should load. + * + * @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException + * if the qualified name of the supplied element is wrong + * @throws \SimpleSAML\XMLSchema\Exception\MissingAttributeException + * if the supplied element is missing any of the mandatory attributes + */ + public static function fromXML(Dom\Element $xml): static + { + $qualifiedName = static::getClassName(static::class); + Assert::eq( + $xml->localName, + $qualifiedName, + 'Unexpected name for endpoint: ' . $xml->localName . '. Expected: ' . $qualifiedName . '.', + InvalidDOMElementException::class, + ); + + return new static( + self::getAttribute($xml, 'Binding', SAMLAnyURIValue::class), + self::getAttribute($xml, 'Location', SAMLAnyURIValue::class), + self::getOptionalAttribute($xml, 'ResponseLocation', SAMLAnyURIValue::class, null), + self::getOptionalAttribute($xml, 'supportsAsynchronous', BooleanValue::class, null), + self::getChildElementsFromXML($xml), + self::getAttributesNSFromXML($xml), + ); + } + + + /** + * Add this endpoint to an XML element. + * + * @param \Dom\Element $parent The element we should append this endpoint to. + */ + public function toXML(?Dom\Element $parent = null): Dom\Element + { + $e = parent::instantiateParentElement($parent); + + if ($this->getSupportsAsynchronous() !== null) { + $e->setAttribute('supportsAsynchronous', $this->getSupportsAsynchronous()->getValue()); + } + + return $e; + } } diff --git a/tests/SAML2/XML/aslo/AsynchronousTest.php b/tests/SAML2/XML/aslo/AsynchronousTest.php new file mode 100644 index 000000000..09e7609b8 --- /dev/null +++ b/tests/SAML2/XML/aslo/AsynchronousTest.php @@ -0,0 +1,57 @@ +saveXml(self::$xmlRepresentation->documentElement); + $this->assertNotFalse($expectedXml); + $actualXml = strval($asynchronous); + + $this->assertXmlStringEqualsXmlString($expectedXml, $actualXml); + } +} diff --git a/tests/resources/xml/aslo_Asynchronous.xml b/tests/resources/xml/aslo_Asynchronous.xml new file mode 100644 index 000000000..9b47da8f6 --- /dev/null +++ b/tests/resources/xml/aslo_Asynchronous.xml @@ -0,0 +1 @@ + From c637668926f3e2a8fdaeca41a12728cb8f7cab9c Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 10 Aug 2026 22:12:11 +0200 Subject: [PATCH 05/11] Fix typos --- .../aslo/{AbstractAlsoElement.php => AbstractAsloElement.php} | 2 +- src/XML/md/SingleLogoutService.php | 4 +++- tests/resources/xml/aslo_Asynchronous.xml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) rename src/XML/aslo/{AbstractAlsoElement.php => AbstractAsloElement.php} (90%) diff --git a/src/XML/aslo/AbstractAlsoElement.php b/src/XML/aslo/AbstractAsloElement.php similarity index 90% rename from src/XML/aslo/AbstractAlsoElement.php rename to src/XML/aslo/AbstractAsloElement.php index 054ae8f14..02fdd7938 100644 --- a/src/XML/aslo/AbstractAlsoElement.php +++ b/src/XML/aslo/AbstractAsloElement.php @@ -13,7 +13,7 @@ * @see https://docs.oasis-open.org/security/saml/Post2.0/saml-async-slo/v1.0/saml-async-slo-v1.0.pdf * @package simplesamlphp/saml2 */ -abstract class AbstractAlgElement extends AbstractElement +abstract class AbstractAsloElement extends AbstractElement { public const string NS = C::NS_ASLO; diff --git a/src/XML/md/SingleLogoutService.php b/src/XML/md/SingleLogoutService.php index ad78dc96b..306a52b4c 100644 --- a/src/XML/md/SingleLogoutService.php +++ b/src/XML/md/SingleLogoutService.php @@ -5,6 +5,8 @@ namespace SimpleSAML\SAML2\XML\md; use Dom; +use SimpleSAML\SAML2\Assert\Assert; +use SimpleSAML\SAML2\Type\SAMLAnyURIValue; use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait; use SimpleSAML\XMLSchema\Type\BooleanValue; @@ -83,7 +85,7 @@ public static function fromXML(Dom\Element $xml): static */ public function toXML(?Dom\Element $parent = null): Dom\Element { - $e = parent::instantiateParentElement($parent); + $e = parent::toXML($parent); if ($this->getSupportsAsynchronous() !== null) { $e->setAttribute('supportsAsynchronous', $this->getSupportsAsynchronous()->getValue()); diff --git a/tests/resources/xml/aslo_Asynchronous.xml b/tests/resources/xml/aslo_Asynchronous.xml index 9b47da8f6..d4dcb6243 100644 --- a/tests/resources/xml/aslo_Asynchronous.xml +++ b/tests/resources/xml/aslo_Asynchronous.xml @@ -1 +1 @@ - + From ec7f6ae250bf1af0687897621cdc27d4c44dd557 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 10 Aug 2026 22:13:21 +0200 Subject: [PATCH 06/11] Fix codesniffer --- src/XML/md/SingleLogoutService.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/XML/md/SingleLogoutService.php b/src/XML/md/SingleLogoutService.php index 306a52b4c..38c478da4 100644 --- a/src/XML/md/SingleLogoutService.php +++ b/src/XML/md/SingleLogoutService.php @@ -46,7 +46,6 @@ public function __construct( } - /** * Initialize a SingleLogoutService. * From 1157ff023f73dc00461a002fbb2cc53a566ad307 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 10 Aug 2026 22:16:39 +0200 Subject: [PATCH 07/11] Fix static analysis issues --- src/XML/md/SingleLogoutService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/XML/md/SingleLogoutService.php b/src/XML/md/SingleLogoutService.php index 38c478da4..414a94a76 100644 --- a/src/XML/md/SingleLogoutService.php +++ b/src/XML/md/SingleLogoutService.php @@ -8,6 +8,7 @@ use SimpleSAML\SAML2\Assert\Assert; use SimpleSAML\SAML2\Type\SAMLAnyURIValue; use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait; +use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException; use SimpleSAML\XMLSchema\Type\BooleanValue; /** From f095f71f989a8e99fd7453698319dea1c3a3ea23 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Wed, 12 Aug 2026 20:38:36 +0200 Subject: [PATCH 08/11] Add unit-test for SingleLogoutService --- src/XML/md/SingleLogoutService.php | 5 +- .../SAML2/XML/md/SingleLogoutServiceTest.php | 78 +++++++++++++++++++ .../resources/xml/md_SingleLogoutService.xml | 1 + 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/SAML2/XML/md/SingleLogoutServiceTest.php create mode 100644 tests/resources/xml/md_SingleLogoutService.xml diff --git a/src/XML/md/SingleLogoutService.php b/src/XML/md/SingleLogoutService.php index 414a94a76..1d8aa69f7 100644 --- a/src/XML/md/SingleLogoutService.php +++ b/src/XML/md/SingleLogoutService.php @@ -8,6 +8,8 @@ use SimpleSAML\SAML2\Assert\Assert; use SimpleSAML\SAML2\Type\SAMLAnyURIValue; use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait; +use SimpleSAML\XML\SchemaValidatableElementInterface; +use SimpleSAML\XML\SchemaValidatableElementTrait; use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException; use SimpleSAML\XMLSchema\Type\BooleanValue; @@ -16,8 +18,9 @@ * * @package simplesamlphp/saml2 */ -final class SingleLogoutService extends AbstractEndpointType +final class SingleLogoutService extends AbstractEndpointType implements SchemaValidatableElementInterface { + use SchemaValidatableElementTrait; use SupportsAsynchronousTrait; diff --git a/tests/SAML2/XML/md/SingleLogoutServiceTest.php b/tests/SAML2/XML/md/SingleLogoutServiceTest.php new file mode 100644 index 000000000..5c87a7e17 --- /dev/null +++ b/tests/SAML2/XML/md/SingleLogoutServiceTest.php @@ -0,0 +1,78 @@ +saveXml(self::$xmlRepresentation->documentElement); + $this->assertNotFalse($expectedXml); + $actualXml = strval($sloep); + + $this->assertXmlStringEqualsXmlString($expectedXml, $actualXml); + } +} diff --git a/tests/resources/xml/md_SingleLogoutService.xml b/tests/resources/xml/md_SingleLogoutService.xml new file mode 100644 index 000000000..871e8766d --- /dev/null +++ b/tests/resources/xml/md_SingleLogoutService.xml @@ -0,0 +1 @@ + From 3eb4ecad50c20ecb2b2f2ae321650315d9a3a57d Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Wed, 12 Aug 2026 21:27:57 +0200 Subject: [PATCH 09/11] Refactor --- src/XML/aslo/SupportsAsynchronousTrait.php | 14 ++-- src/XML/md/SingleLogoutService.php | 66 ++----------------- .../SAML2/XML/md/SingleLogoutServiceTest.php | 1 + 3 files changed, 17 insertions(+), 64 deletions(-) diff --git a/src/XML/aslo/SupportsAsynchronousTrait.php b/src/XML/aslo/SupportsAsynchronousTrait.php index e928a97a3..b238525f7 100644 --- a/src/XML/aslo/SupportsAsynchronousTrait.php +++ b/src/XML/aslo/SupportsAsynchronousTrait.php @@ -4,6 +4,7 @@ namespace SimpleSAML\SAML2\XML\aslo; +use SimpleSAML\SAML2\Constants as C; use SimpleSAML\XMLSchema\Type\BooleanValue; /** @@ -12,7 +13,7 @@ trait SupportsAsynchronousTrait { /** @var \SimpleSAML\XMLSchema\Type\BooleanValue|null */ - protected ?BooleanValue $supportsAsynchronous; + protected ?BooleanValue $supportsAsynchronous = null; /** @@ -25,10 +26,15 @@ public function getSupportsAsynchronous(): ?BooleanValue /** - * @param \SimpleSAML\XMLSchema\Type\BooleanValue $supportsAsynchronous|null + * @param array<\SimpleSAML\XML\Attribute> $namespacedAttributes */ - private function setSupportsAsynchronous(?BooleanValue $supportsAsynchronous): void + private function setSupportsAsynchronous(array $namespacedAttributes = []): void { - $this->supportsAsynchronous = $supportsAsynchronous; + foreach ($namespacedAttributes as $attr) { + if ($attr->getNamespaceURI() === C::NS_ASLO && $attr->getAttrName() === 'supportsAsynchronous') { + $this->supportsAsynchronous = BooleanValue::fromString($attr->getAttrValue()->getValue()); + return; + } + } } } diff --git a/src/XML/md/SingleLogoutService.php b/src/XML/md/SingleLogoutService.php index 1d8aa69f7..4f9567f68 100644 --- a/src/XML/md/SingleLogoutService.php +++ b/src/XML/md/SingleLogoutService.php @@ -4,14 +4,10 @@ namespace SimpleSAML\SAML2\XML\md; -use Dom; -use SimpleSAML\SAML2\Assert\Assert; -use SimpleSAML\SAML2\Type\SAMLAnyURIValue; -use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait; use SimpleSAML\XML\SchemaValidatableElementInterface; use SimpleSAML\XML\SchemaValidatableElementTrait; -use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException; -use SimpleSAML\XMLSchema\Type\BooleanValue; +use SimpleSAML\SAML2\Type\SAMLAnyURIValue; +use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait; /** * SingleLogoutService element of type EndpointType @@ -30,70 +26,20 @@ final class SingleLogoutService extends AbstractEndpointType implements SchemaVa * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue $binding * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue $location * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null $responseLocation - * @param \SimpleSAML\XMLSchema\Type\BooleanValue $supportsAsynchronous * @param \SimpleSAML\XML\ElementInterface[] $children * @param array<\SimpleSAML\XML\Attribute> $attributes * * @throws \SimpleSAML\Assert\AssertionFailedException */ public function __construct( - SAMLAnyURIValue $binding, - SAMLAnyURIValue $location, - ?SAMLAnyURIValue $responseLocation = null, - protected ?BooleanValue $supportsAsynchronous = null, + protected SAMLAnyURIValue $binding, + protected SAMLAnyURIValue $location, + protected ?SAMLAnyURIValue $responseLocation = null, array $children = [], array $attributes = [], ) { - $this->setSupportsAsynchronous($supportsAsynchronous); + $this->setSupportsAsynchronous($attributes); parent::__construct($binding, $location, $responseLocation, $children, $attributes); } - - - /** - * Initialize a SingleLogoutService. - * - * @param \Dom\Element $xml The XML element we should load. - * - * @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException - * if the qualified name of the supplied element is wrong - * @throws \SimpleSAML\XMLSchema\Exception\MissingAttributeException - * if the supplied element is missing any of the mandatory attributes - */ - public static function fromXML(Dom\Element $xml): static - { - $qualifiedName = static::getClassName(static::class); - Assert::eq( - $xml->localName, - $qualifiedName, - 'Unexpected name for endpoint: ' . $xml->localName . '. Expected: ' . $qualifiedName . '.', - InvalidDOMElementException::class, - ); - - return new static( - self::getAttribute($xml, 'Binding', SAMLAnyURIValue::class), - self::getAttribute($xml, 'Location', SAMLAnyURIValue::class), - self::getOptionalAttribute($xml, 'ResponseLocation', SAMLAnyURIValue::class, null), - self::getOptionalAttribute($xml, 'supportsAsynchronous', BooleanValue::class, null), - self::getChildElementsFromXML($xml), - self::getAttributesNSFromXML($xml), - ); - } - - - /** - * Add this endpoint to an XML element. - * - * @param \Dom\Element $parent The element we should append this endpoint to. - */ - public function toXML(?Dom\Element $parent = null): Dom\Element - { - $e = parent::toXML($parent); - - if ($this->getSupportsAsynchronous() !== null) { - $e->setAttribute('supportsAsynchronous', $this->getSupportsAsynchronous()->getValue()); - } - - return $e; - } } diff --git a/tests/SAML2/XML/md/SingleLogoutServiceTest.php b/tests/SAML2/XML/md/SingleLogoutServiceTest.php index 5c87a7e17..dfda64817 100644 --- a/tests/SAML2/XML/md/SingleLogoutServiceTest.php +++ b/tests/SAML2/XML/md/SingleLogoutServiceTest.php @@ -66,6 +66,7 @@ public function testMarshalling(): void SAMLAnyURIValue::fromString(C::BINDING_HTTP_POST), SAMLAnyURIValue::fromString(C::LOCATION_A), SAMLAnyURIValue::fromString(C::LOCATION_B), + [], [$supportsAsynchronous], ); From 2e7dd45e4f466afdde078d3bca44ce1061cd5cc2 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Wed, 12 Aug 2026 22:11:46 +0200 Subject: [PATCH 10/11] Add unit-test for AuthnRequest containing aslo:Asynchronous --- src/XML/samlp/Extensions.php | 10 +++++++- tests/SAML2/XML/samlp/AuthnRequestTest.php | 29 ++++++++++++++++------ tests/resources/xml/samlp_AuthnRequest.xml | 5 +++- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/XML/samlp/Extensions.php b/src/XML/samlp/Extensions.php index 5f7884e5d..d6534d1d7 100644 --- a/src/XML/samlp/Extensions.php +++ b/src/XML/samlp/Extensions.php @@ -9,6 +9,7 @@ use SimpleSAML\SAML2\Utils\XPath; use SimpleSAML\SAML2\XML\ExtensionsTrait; use SimpleSAML\XML\Chunk; +use SimpleSAML\XML\Registry\ElementRegistry; use SimpleSAML\XML\SchemaValidatableElementInterface; use SimpleSAML\XML\SchemaValidatableElementTrait; use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException; @@ -63,11 +64,18 @@ public static function fromXML(Dom\Element $xml): static 'Invalid Extensions element \'' . $xml->localName . '\'', InvalidDOMElementException::class, ); + + $registry = ElementRegistry::getInstance(); $ret = []; /** @var \Dom\Element $node */ foreach (XPath::xpQuery($xml, './*', XPath::getXPath($xml)) as $node) { - $ret[] = new Chunk($node); + $result = $registry->getElementHandler($node->namespaceURI, $node->localName); + if ($result !== null) { + $ret[] = $result::fromXML($node); + } else { + $ret[] = new Chunk($node); + } } return new static($ret); diff --git a/tests/SAML2/XML/samlp/AuthnRequestTest.php b/tests/SAML2/XML/samlp/AuthnRequestTest.php index 08fcb58c4..4a4b679be 100644 --- a/tests/SAML2/XML/samlp/AuthnRequestTest.php +++ b/tests/SAML2/XML/samlp/AuthnRequestTest.php @@ -17,6 +17,7 @@ use SimpleSAML\SAML2\Type\SAMLStringValue; use SimpleSAML\SAML2\Utils; use SimpleSAML\SAML2\Utils\XPath; +use SimpleSAML\SAML2\XML\aslo\Asynchronous; use SimpleSAML\SAML2\XML\saml\Audience; use SimpleSAML\SAML2\XML\saml\AudienceRestriction; use SimpleSAML\SAML2\XML\saml\AuthnContextClassRef; @@ -31,6 +32,7 @@ use SimpleSAML\SAML2\XML\samlp\AbstractSamlpElement; use SimpleSAML\SAML2\XML\samlp\AuthnContextComparisonTypeEnum; use SimpleSAML\SAML2\XML\samlp\AuthnRequest; +use SimpleSAML\SAML2\XML\samlp\Extensions; use SimpleSAML\SAML2\XML\samlp\GetComplete; use SimpleSAML\SAML2\XML\samlp\IDPEntry; use SimpleSAML\SAML2\XML\samlp\IDPList; @@ -101,6 +103,10 @@ public function testMarshalling(): void ), ); + $extensions = new Extensions([ + new Asynchronous(), + ]); + $authnRequest = new AuthnRequest( subject: $subject, issuer: new Issuer( @@ -110,6 +116,7 @@ public function testMarshalling(): void id: IDValue::fromString('_2b0226190ca1c22de6f66e85f5c95158'), issueInstant: SAMLDateTimeValue::fromString('2014-09-22T13:42:00Z'), destination: SAMLAnyURIValue::fromString('https://tiqr.stepup.org/idp/profile/saml2/Redirect/SSO'), + extensions: $extensions, ); $expectedXml = self::$xmlRepresentation->saveXml(self::$xmlRepresentation->documentElement); @@ -181,6 +188,11 @@ public function testMarshallingElementOrdering(): void [$requesterId], ); + // Create Extensions + $extensions = new Extensions([ + new Asynchronous(), + ]); + $authnRequest = new AuthnRequest( id: IDValue::fromString('SomeIDValue'), requestedAuthnContext: $rac, @@ -192,27 +204,30 @@ public function testMarshallingElementOrdering(): void SAMLStringValue::fromString('https://gateway.stepup.org/saml20/sp/metadata'), ), scoping: $scoping, + extensions: $extensions, ); $authnRequestElement = $authnRequest->toXML(); // Test for a Subject $xpCache = XPath::getXPath($authnRequestElement); - $authnRequestElements = XPath::xpQuery($authnRequestElement, './saml_assertion:Subject', $xpCache); + $authnRequestElements = XPath::xpQuery($authnRequestElement, './saml_assertion:Issuer', $xpCache); $this->assertCount(1, $authnRequestElements); // Test ordering of AuthnRequest contents /** @var \Dom\Element[] $authnRequestElements */ $authnRequestElements = XPath::xpQuery( $authnRequestElement, - './saml_assertion:Subject/following-sibling::*', + './saml_assertion:Issuer/following-sibling::*', $xpCache, ); - $this->assertCount(4, $authnRequestElements); - $this->assertEquals('samlp:NameIDPolicy', $authnRequestElements[0]->tagName); - $this->assertEquals('saml:Conditions', $authnRequestElements[1]->tagName); - $this->assertEquals('samlp:RequestedAuthnContext', $authnRequestElements[2]->tagName); - $this->assertEquals('samlp:Scoping', $authnRequestElements[3]->tagName); + $this->assertCount(6, $authnRequestElements); + $this->assertEquals('samlp:Extensions', $authnRequestElements[0]->tagName); + $this->assertEquals('saml:Subject', $authnRequestElements[1]->tagName); + $this->assertEquals('samlp:NameIDPolicy', $authnRequestElements[2]->tagName); + $this->assertEquals('saml:Conditions', $authnRequestElements[3]->tagName); + $this->assertEquals('samlp:RequestedAuthnContext', $authnRequestElements[4]->tagName); + $this->assertEquals('samlp:Scoping', $authnRequestElements[5]->tagName); } diff --git a/tests/resources/xml/samlp_AuthnRequest.xml b/tests/resources/xml/samlp_AuthnRequest.xml index 5eea6f099..6d8970f4c 100644 --- a/tests/resources/xml/samlp_AuthnRequest.xml +++ b/tests/resources/xml/samlp_AuthnRequest.xml @@ -1,5 +1,8 @@ - + https://gateway.stepup.org/saml20/sp/metadata + + + user@example.org From 80772e1c1e9472fb504726db18387ff5038ddd4b Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Wed, 12 Aug 2026 22:13:06 +0200 Subject: [PATCH 11/11] Fix codesniffer issues --- src/XML/md/SingleLogoutService.php | 4 ++-- tests/SAML2/XML/md/SingleLogoutServiceTest.php | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/XML/md/SingleLogoutService.php b/src/XML/md/SingleLogoutService.php index 4f9567f68..eb4e0cd4f 100644 --- a/src/XML/md/SingleLogoutService.php +++ b/src/XML/md/SingleLogoutService.php @@ -4,10 +4,10 @@ namespace SimpleSAML\SAML2\XML\md; -use SimpleSAML\XML\SchemaValidatableElementInterface; -use SimpleSAML\XML\SchemaValidatableElementTrait; use SimpleSAML\SAML2\Type\SAMLAnyURIValue; use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait; +use SimpleSAML\XML\SchemaValidatableElementInterface; +use SimpleSAML\XML\SchemaValidatableElementTrait; /** * SingleLogoutService element of type EndpointType diff --git a/tests/SAML2/XML/md/SingleLogoutServiceTest.php b/tests/SAML2/XML/md/SingleLogoutServiceTest.php index dfda64817..95245d0da 100644 --- a/tests/SAML2/XML/md/SingleLogoutServiceTest.php +++ b/tests/SAML2/XML/md/SingleLogoutServiceTest.php @@ -7,7 +7,6 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; -use SimpleSAML\SAML2\Exception\ProtocolViolationException; use SimpleSAML\SAML2\Type\SAMLAnyURIValue; use SimpleSAML\SAML2\XML\md\AbstractMdElement; use SimpleSAML\SAML2\XML\md\SingleLogoutService;