Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions classes/element.registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
13 changes: 13 additions & 0 deletions resources/schemas/saml-async-slo-v1.0.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>

<schema xmlns:aslo="urn:oasis:names:tc:SAML:2.0:protocol:ext:async-slo"
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:oasis:names:tc:SAML:2.0:protocol:ext:async-slo"
elementFormDefault="qualified">

<element name="Asynchronous" type="aslo:AsynchronousType" />
<complexType name="AsynchronousType" />

<attribute name="supportsAsynchronous" type="boolean"/>

</schema>
5 changes: 5 additions & 0 deletions src/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
23 changes: 23 additions & 0 deletions src/XML/aslo/AbstractAsloElement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\XML\aslo;

use SimpleSAML\SAML2\Constants as C;
use SimpleSAML\XML\AbstractElement;

/**
* Abstract class to be implemented by all the classes in this namespace
*
* @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 AbstractAsloElement extends AbstractElement
{
public const string NS = C::NS_ASLO;

public const string NS_PREFIX = 'aslo';

public const string SCHEMA = 'resources/schemas/saml-async-slo-v1.0.xsd';
}
45 changes: 45 additions & 0 deletions src/XML/aslo/Asynchronous.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\XML\aslo;

use Dom;
use SimpleSAML\SAML2\Assert\Assert;
use SimpleSAML\XML\SchemaValidatableElementInterface;
use SimpleSAML\XML\SchemaValidatableElementTrait;
use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException;

/**
* Class representing a aslo:Asynchronous element.
*
* @package simplesaml/saml2
*/
final class Asynchronous extends AbstractAsloElement implements SchemaValidatableElementInterface
{
use SchemaValidatableElementTrait;


/**
* Convert XML into a Asynchronous
*
* @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException
* if the qualified name of the supplied element is wrong
*/
public static function fromXML(Dom\Element $xml): static
{
Assert::same($xml->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);
}
}
40 changes: 40 additions & 0 deletions src/XML/aslo/SupportsAsynchronousTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\XML\aslo;

use SimpleSAML\SAML2\Constants as C;
use SimpleSAML\XMLSchema\Type\BooleanValue;

/**
* @package simplesamlphp/saml2
*/
trait SupportsAsynchronousTrait
{
/** @var \SimpleSAML\XMLSchema\Type\BooleanValue|null */
protected ?BooleanValue $supportsAsynchronous = null;


/**
* @return \SimpleSAML\XMLSchema\Type\BooleanValue|null
*/
public function getSupportsAsynchronous(): ?BooleanValue
{
return $this->supportsAsynchronous;
}


/**
* @param array<\SimpleSAML\XML\Attribute> $namespacedAttributes
*/
private function setSupportsAsynchronous(array $namespacedAttributes = []): void
{
foreach ($namespacedAttributes as $attr) {
if ($attr->getNamespaceURI() === C::NS_ASLO && $attr->getAttrName() === 'supportsAsynchronous') {
$this->supportsAsynchronous = BooleanValue::fromString($attr->getAttrValue()->getValue());
return;
}
}
}
}
33 changes: 32 additions & 1 deletion src/XML/md/SingleLogoutService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,42 @@

namespace SimpleSAML\SAML2\XML\md;

use SimpleSAML\SAML2\Type\SAMLAnyURIValue;
use SimpleSAML\SAML2\XML\aslo\SupportsAsynchronousTrait;
use SimpleSAML\XML\SchemaValidatableElementInterface;
use SimpleSAML\XML\SchemaValidatableElementTrait;

/**
* SingleLogoutService element of type EndpointType
*
* @package simplesamlphp/saml2
*/
final class SingleLogoutService extends AbstractEndpointType
final class SingleLogoutService extends AbstractEndpointType implements SchemaValidatableElementInterface
{
use SchemaValidatableElementTrait;
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\XML\ElementInterface[] $children
* @param array<\SimpleSAML\XML\Attribute> $attributes
*
* @throws \SimpleSAML\Assert\AssertionFailedException
*/
public function __construct(
protected SAMLAnyURIValue $binding,
protected SAMLAnyURIValue $location,
protected ?SAMLAnyURIValue $responseLocation = null,
array $children = [],
array $attributes = [],
) {
$this->setSupportsAsynchronous($attributes);

parent::__construct($binding, $location, $responseLocation, $children, $attributes);
}
}
10 changes: 9 additions & 1 deletion src/XML/samlp/Extensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
57 changes: 57 additions & 0 deletions tests/SAML2/XML/aslo/AsynchronousTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Test\SAML2\XML\aslo;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use SimpleSAML\SAML2\XML\aslo\AbstractAsloElement;
use SimpleSAML\SAML2\XML\aslo\Asynchronous;
use SimpleSAML\XML\DOMDocumentFactory;
use SimpleSAML\XML\TestUtils\SchemaValidationTestTrait;
use SimpleSAML\XML\TestUtils\SerializableElementTestTrait;

use function dirname;
use function strval;

/**
* Class \SimpleSAML\SAML2\XML\aslo\AsynchronousTest
*
* @package simplesamlphp/saml2
*/
#[Group('aslo')]
#[CoversClass(Asynchronous::class)]
#[CoversClass(AbstractAsloElement::class)]
final class AsynchronousTest extends TestCase
{
use SchemaValidationTestTrait;
use SerializableElementTestTrait;


/**
*/
public static function setUpBeforeClass(): void
{
self::$testedClass = Asynchronous::class;

self::$xmlRepresentation = DOMDocumentFactory::fromFile(
dirname(__FILE__, 4) . '/resources/xml/aslo_Asynchronous.xml',
);
}


/**
*/
public function testMarshalling(): void
{
$asynchronous = new Asynchronous();

$expectedXml = self::$xmlRepresentation->saveXml(self::$xmlRepresentation->documentElement);
$this->assertNotFalse($expectedXml);
$actualXml = strval($asynchronous);

$this->assertXmlStringEqualsXmlString($expectedXml, $actualXml);
}
}
78 changes: 78 additions & 0 deletions tests/SAML2/XML/md/SingleLogoutServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\Test\SAML2\XML\md;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use SimpleSAML\SAML2\Type\SAMLAnyURIValue;
use SimpleSAML\SAML2\XML\md\AbstractMdElement;
use SimpleSAML\SAML2\XML\md\SingleLogoutService;
use SimpleSAML\Test\SAML2\Constants as C;
use SimpleSAML\XML\Attribute as XMLAttribute;
use SimpleSAML\XML\DOMDocumentFactory;
use SimpleSAML\XML\TestUtils\SchemaValidationTestTrait;
use SimpleSAML\XML\TestUtils\SerializableElementTestTrait;
use SimpleSAML\XMLSchema\Type\BooleanValue;

use function dirname;
use function strval;

/**
* Tests for md:SingleLogoutService.
*
* @package simplesamlphp/saml2
*/
#[Group('md')]
#[CoversClass(SingleLogoutService::class)]
#[CoversClass(AbstractMdElement::class)]
final class SingleLogoutServiceTest extends TestCase
{
use SchemaValidationTestTrait;
use SerializableElementTestTrait;


/**
*/
public static function setUpBeforeClass(): void
{
self::$testedClass = SingleLogoutService::class;

self::$xmlRepresentation = DOMDocumentFactory::fromFile(
dirname(__FILE__, 4) . '/resources/xml/md_SingleLogoutService.xml',
);
}


// test marshalling


/**
* Test creating a SingleLogoutService from scratch.
*/
public function testMarshalling(): void
{
$supportsAsynchronous = new XMLAttribute(
C::NS_ASLO,
'aslo',
'supportsAsynchronous',
BooleanValue::fromBoolean(true),
);

$sloep = new SingleLogoutService(
SAMLAnyURIValue::fromString(C::BINDING_HTTP_POST),
SAMLAnyURIValue::fromString(C::LOCATION_A),
SAMLAnyURIValue::fromString(C::LOCATION_B),
[],
[$supportsAsynchronous],
);

$expectedXml = self::$xmlRepresentation->saveXml(self::$xmlRepresentation->documentElement);
$this->assertNotFalse($expectedXml);
$actualXml = strval($sloep);

$this->assertXmlStringEqualsXmlString($expectedXml, $actualXml);
}
}
Loading
Loading