Skip to content

Commit

Permalink
Backport CustomRoleDescriptor
Browse files Browse the repository at this point in the history
  • Loading branch information
tvdijen committed Nov 18, 2023
1 parent e3664b3 commit 265810f
Showing 1 changed file with 185 additions and 0 deletions.
185 changes: 185 additions & 0 deletions tests/SAML2/CustomRoleDescriptor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\Test\SAML2;

use DateTimeImmutable;
use DOMElement;
use SimpleSAML\Assert\Assert;
use SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor;
use SimpleSAML\SAML2\XML\md\ContactPerson;
use SimpleSAML\SAML2\XML\md\Extensions;
use SimpleSAML\SAML2\XML\md\KeyDescriptor;
use SimpleSAML\SAML2\XML\md\Organization;
use SimpleSAML\Test\SAML2\Constants as C;
use SimpleSAML\XML\Chunk;
use SimpleSAML\XML\Exception\InvalidDOMElementException;
use SimpleSAML\XML\Exception\MissingElementException;
use SimpleSAML\XML\Exception\TooManyElementsException;

/**
* Example class to demonstrate how RoleDescriptor can be extended.
*
* @package simplesamlphp\saml2
*/
final class CustomRoleDescriptor extends AbstractRoleDescriptor
{
/** @var string */
protected const XSI_TYPE_NAME = 'CustomRoleDescriptorType';

/** @var string */
protected const XSI_TYPE_NAMESPACE = C::NAMESPACE;

/** @var string */
protected const XSI_TYPE_PREFIX = 'ssp';


/**
* CustomRoleDescriptor constructor.
*
* @param \SimpleSAML\XML\Chunk[] $chunk
* @param string[] $protocolSupportEnumeration A set of URI specifying the protocols supported.
* @param string|null $ID The ID for this document. Defaults to null.
* @param \DateTimeImmutable|null $validUntil Unix time of validity for this document. Defaults to null.
* @param string|null $cacheDuration Maximum time this document can be cached. Defaults to null.
* @param \SimpleSAML\SAML2\XML\md\Extensions|null $extensions An Extensions object. Defaults to null.
* @param string|null $errorURL An URI where to redirect users for support. Defaults to null.
* @param \SimpleSAML\SAML2\XML\md\KeyDescriptor[] $keyDescriptor An array of KeyDescriptor elements.
* Defaults to an empty array.
* @param \SimpleSAML\SAML2\XML\md\Organization|null $organization
* The organization running this entity. Defaults to null.
* @param \SimpleSAML\SAML2\XML\md\ContactPerson[] $contacts
* An array of contacts for this entity. Defaults to an empty array.
* @param list<\SimpleSAML\XML\Attribute> $namespacedAttributes
*/
public function __construct(
protected array $chunk,
array $protocolSupportEnumeration,
?string $ID = null,
?DateTimeImmutable $validUntil = null,
?string $cacheDuration = null,
?Extensions $extensions = null,
?string $errorURL = null,
array $keyDescriptor = [],
?Organization $organization = null,
array $contact = [],
array $namespacedAttributes = []
) {
Assert::allIsInstanceOf($chunk, Chunk::class);

parent::__construct(
self::XSI_TYPE_PREFIX . ':' . self::XSI_TYPE_NAME,
$protocolSupportEnumeration,
$ID,
$validUntil,
$cacheDuration,
$extensions,
$errorURL,
$keyDescriptor,
$organization,
$contact,
$namespacedAttributes,
);
}


/**
* Get the value of the chunk-attribute.
*
* @return \SimpleSAML\XML\Chunk[]
*/
public function getChunk(): array
{
return $this->chunk;
}


/**
* Convert XML into a RoleDescriptor
*
* @param \DOMElement $xml The XML element we should load
* @return static
*
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
* if the qualified name of the supplied element is wrong
*/
public static function fromXML(DOMElement $xml): static
{
Assert::same($xml->localName, 'RoleDescriptor', InvalidDOMElementException::class);
Assert::notNull($xml->namespaceURI, InvalidDOMElementException::class);
Assert::same($xml->namespaceURI, AbstractRoleDescriptor::NS, InvalidDOMElementException::class);
Assert::true(
$xml->hasAttributeNS(C::NS_XSI, 'type'),
'Missing required xsi:type in <saml:RoleDescriptor> element.',
InvalidDOMElementException::class
);

$type = $xml->getAttributeNS(C::NS_XSI, 'type');
Assert::same($type, self::XSI_TYPE_PREFIX . ':' . self::XSI_TYPE_NAME);

$protocols = self::getAttribute($xml, 'protocolSupportEnumeration');

$validUntil = self::getOptionalAttribute($xml, 'validUntil', null);
Assert::nullOrValidDateTimeZulu($validUntil);

$orgs = Organization::getChildrenOfClass($xml);
Assert::maxCount(
$orgs,
1,
'More than one Organization found in this descriptor',
TooManyElementsException::class,
);

$extensions = Extensions::getChildrenOfClass($xml);
Assert::maxCount(
$extensions,
1,
'Only one md:Extensions element is allowed.',
TooManyElementsException::class,
);

$chunk = [];
foreach ($xml->childNodes as $c) {
if (!($c instanceof DOMElement)) {
continue;
} elseif ($c->namespaceURI === C::NS_MD) {
continue;
}

$chunk[] = new Chunk($c);
}
Assert::minCount($chunk, 1, 'At least one ssp:Chunk element must be provided.', MissingElementException::class);

return new static(
$chunk,
preg_split('/[\s]+/', trim($protocols)),
self::getOptionalAttribute($xml, 'ID', null),
$validUntil !== null ? new DateTimeImmutable($validUntil) : null,
self::getOptionalAttribute($xml, 'cacheDuration', null),
!empty($extensions) ? $extensions[0] : null,
self::getOptionalAttribute($xml, 'errorURL', null),
KeyDescriptor::getChildrenOfClass($xml),
!empty($orgs) ? $orgs[0] : null,
ContactPerson::getChildrenOfClass($xml)
);
}


/**
* Convert this RoleDescriptor to XML.
*
* @param \DOMElement $parent The element we are converting to XML.
* @return \DOMElement The XML element after adding the data corresponding to this RoleDescriptor.
*/
public function toUnsignedXML(DOMElement $parent = null): DOMElement
{
$e = parent::toUnsignedXML($parent);

foreach ($this->getChunk() as $chunk) {
$chunk->toXML($e);
}

return $e;
}
}

0 comments on commit 265810f

Please sign in to comment.