Skip to content

Commit

Permalink
Add some more elements for the ecp-namespace (#341)
Browse files Browse the repository at this point in the history
* Add ecp:SubjectConfirmation

* Add ecp:RelayState

* Add ecp:Request
  • Loading branch information
tvdijen committed Jun 3, 2023
1 parent 8cd7860 commit a11f078
Show file tree
Hide file tree
Showing 15 changed files with 817 additions and 27 deletions.
2 changes: 1 addition & 1 deletion composer.json
Expand Up @@ -32,7 +32,7 @@
"psr/log": "^2.0 || ^3.0",
"simplesamlphp/xml-common": "^1.11.2",
"simplesamlphp/xml-security": "^1.6.5",
"simplesamlphp/xml-soap": "^1.2.0",
"simplesamlphp/xml-soap": "^1.2.1",
"simplesamlphp/assert": "^1.0.4"
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion src/SAML2/SOAP.php
Expand Up @@ -47,7 +47,7 @@ public function getOutputToSend(AbstractMessage $message)
// containing another message (e.g. a Response), however in the ECP
// profile, this is the Response itself.
if ($message instanceof SAML2_Response) {
$requestAuthenticated = new RequestAuthenticated(1);
$requestAuthenticated = new RequestAuthenticated(true);

$destination = $this->destination ?: $message->getDestination();
if ($destination === null) {
Expand Down
2 changes: 2 additions & 0 deletions src/SAML2/XML/ecp/AbstractEcpElement.php
Expand Up @@ -11,6 +11,8 @@
* Abstract class to be implemented by all the classes in this namespace
*
* @package simplesamlphp/saml2
*
* @see http://docs.oasis-open.org/security/saml/Post2.0/saml-ecp/v2.0/saml-ecp-v2.0.html
*/
abstract class AbstractEcpElement extends AbstractElement
{
Expand Down
105 changes: 105 additions & 0 deletions src/SAML2/XML/ecp/RelayState.php
@@ -0,0 +1,105 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\XML\ecp;

use DOMElement;
use SimpleSAML\Assert\Assert;
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
use SimpleSAML\SOAP\Constants as C;
use SimpleSAML\XML\Exception\InvalidDOMElementException;
use SimpleSAML\XML\Exception\MissingAttributeException;
use SimpleSAML\XML\Exception\TooManyElementsException;
use SimpleSAML\XML\Exception\SchemaViolationException;
use SimpleSAML\XML\StringElementTrait;

use function boolval;
use function intval;
use function strval;

/**
* Class representing the ECP RelayState element.
*
* @package simplesamlphp/saml2
*/
final class RelayState extends AbstractEcpElement
{
use StringElementTrait;

/**
* Create a ECP RelayState element.
*
* @param string $relayState
*/
public function __construct(
string $relayState,
) {
$this->setContent($relayState);
}


/**
* Convert XML into a RelayState
*
* @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
* @throws \SimpleSAML\XML\Exception\MissingAttributeException
* if the supplied element is missing any of the mandatory attributes
*/
public static function fromXML(DOMElement $xml): static
{
Assert::same($xml->localName, 'RelayState', InvalidDOMElementException::class);
Assert::same($xml->namespaceURI, RelayState::NS, InvalidDOMElementException::class);

// Assert required attributes
Assert::true(
$xml->hasAttributeNS(C::NS_SOAP_ENV_11, 'actor'),
'Missing env:actor attribute in <ecp:RelayState>.',
MissingAttributeException::class,
);
Assert::true(
$xml->hasAttributeNS(C::NS_SOAP_ENV_11, 'mustUnderstand'),
'Missing env:mustUnderstand attribute in <ecp:RelayState>.',
MissingAttributeException::class,
);

$mustUnderstand = $xml->getAttributeNS(C::NS_SOAP_ENV_11, 'mustUnderstand');
Assert::same(
$mustUnderstand,
'1',
'Invalid value of env:mustUnderstand attribute in <ecp:RelayState>.',
ProtocolViolationException::class,
);

$actor = $xml->getAttributeNS(C::NS_SOAP_ENV_11, 'actor');
Assert::same(
$actor,
C::SOAP_ACTOR_NEXT,
'Invalid value of env:actor attribute in <ecp:RelayState>.',
ProtocolViolationException::class,
);

return new static($xml->textContent);
}


/**
* Convert this ECP RelayState to XML.
*
* @param \DOMElement|null $parent The element we should append this element to.
* @return \DOMElement
*/
public function toXML(DOMElement $parent = null): DOMElement
{
$e = $this->instantiateParentElement($parent);
$e->setAttributeNS(C::NS_SOAP_ENV_11, 'env:mustUnderstand', '1');
$e->setAttributeNS(C::NS_SOAP_ENV_11, 'env:actor', C::SOAP_ACTOR_NEXT);
$e->textContent = $this->getContent();

return $e;
}
}
178 changes: 178 additions & 0 deletions src/SAML2/XML/ecp/Request.php
@@ -0,0 +1,178 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\XML\ecp;

use DOMElement;
use SimpleSAML\Assert\Assert;
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
use SimpleSAML\SAML2\XML\saml\Issuer;
use SimpleSAML\SAML2\XML\samlp\IDPList;
use SimpleSAML\SOAP\Constants as C;
use SimpleSAML\XML\Exception\InvalidDOMElementException;
use SimpleSAML\XML\Exception\MissingAttributeException;
use SimpleSAML\XML\Exception\TooManyElementsException;
use SimpleSAML\XML\Exception\SchemaViolationException;

use function boolval;
use function intval;
use function is_null;
use function is_numeric;
use function strval;

/**
* Class representing the ECP Request element.
*
* @package simplesamlphp/saml2
*/
final class Request extends AbstractEcpElement
{
/**
* Create a ECP Request element.
*
* @param \SimpleSAML\SAML2\XML\saml\Issuer $issuer
* @param \SimpleSAML\SAML2\XML\samlp\IDPList|null $idpList
* @param string|null $providerName
* @param bool|null $isPassive
*/
public function __construct(
protected Issuer $issuer,
protected ?IDPList $idpList = null,
protected ?string $providerName = null,
protected ?bool $isPassive = null,
) {
}


/**
* Collect the value of the isPassive-property
*
* @return bool|null
*/
public function getIsPassive(): ?bool
{
return $this->isPassive;
}


/**
* Collect the value of the providerName-property
*
* @return string|null
*/
public function getProviderName(): ?string
{
return $this->providerName;
}


/**
* Collect the value of the issuer-property
*
* @return \SimpleSAML\SAML2\XML\saml\Issuer
*/
public function getIssuer(): Issuer
{
return $this->issuer;
}
/**
* Collect the value of the idpList-property
*
* @return \SimpleSAML\SAML2\XML\samlp\IDPList|null
*/
public function getIDPList(): ?IDPList
{
return $this->idpList;
}


/**
* Convert XML into a Request
*
* @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
* @throws \SimpleSAML\XML\Exception\MissingAttributeException
* if the supplied element is missing any of the mandatory attributes
*/
public static function fromXML(DOMElement $xml): static
{
Assert::same($xml->localName, 'Request', InvalidDOMElementException::class);
Assert::same($xml->namespaceURI, Request::NS, InvalidDOMElementException::class);

// Assert required attributes
Assert::true(
$xml->hasAttributeNS(C::NS_SOAP_ENV_11, 'actor'),
'Missing env:actor attribute in <ecp:Request>.',
MissingAttributeException::class,
);
Assert::true(
$xml->hasAttributeNS(C::NS_SOAP_ENV_11, 'mustUnderstand'),
'Missing env:mustUnderstand attribute in <ecp:Request>.',
MissingAttributeException::class,
);

$mustUnderstand = $xml->getAttributeNS(C::NS_SOAP_ENV_11, 'mustUnderstand');
Assert::same(
$mustUnderstand,
'1',
'Invalid value of env:mustUnderstand attribute in <ecp:Request>.',
ProtocolViolationException::class,
);

$actor = $xml->getAttributeNS(C::NS_SOAP_ENV_11, 'actor');
Assert::same(
$actor,
C::SOAP_ACTOR_NEXT,
'Invalid value of env:actor attribute in <ecp:Request>.',
ProtocolViolationException::class,
);

$issuer = Issuer::getChildrenOfClass($xml);
Assert::count(
$issuer,
1,
'More than one <saml:Issuer> in <ecp:Request>.',
TooManyElementsException::class,
);

$idpList = IDPList::getChildrenOfClass($xml);

return new static(
array_pop($issuer),
array_pop($idpList),
self::getOptionalAttribute($xml, 'ProviderName', null),
self::getOptionalBooleanAttribute($xml, 'IsPassive', null),
);
}


/**
* Convert this ECP SubjectConfirmation to XML.
*
* @param \DOMElement|null $parent The element we should append this element to.
* @return \DOMElement
*/
public function toXML(DOMElement $parent = null): DOMElement
{
$e = $this->instantiateParentElement($parent);
$e->setAttributeNS(C::NS_SOAP_ENV_11, 'env:mustUnderstand', '1');
$e->setAttributeNS(C::NS_SOAP_ENV_11, 'env:actor', C::SOAP_ACTOR_NEXT);

if ($this->getProviderName() !== null) {
$e->setAttribute('ProviderName', $this->getProviderName());
}

if ($this->getIsPassive() !== null) {
$e->setAttribute('IsPassive', strval(intval($this->getIsPassive())));
}

$this->getIssuer()->toXML($e);
$this->getIDPList()?->toXML($e);

return $e;
}
}
36 changes: 13 additions & 23 deletions src/SAML2/XML/ecp/RequestAuthenticated.php
Expand Up @@ -11,6 +11,7 @@
use SimpleSAML\XML\Exception\InvalidDOMElementException;
use SimpleSAML\XML\Exception\MissingAttributeException;

use function boolval;
use function is_null;
use function is_numeric;
use function strval;
Expand All @@ -25,26 +26,20 @@ final class RequestAuthenticated extends AbstractEcpElement
/**
* Create a ECP RequestAuthenticated element.
*
* @param int|null $mustUnderstand
* @param bool $mustUnderstand
*/
public function __construct(
protected ?int $mustUnderstand,
protected bool $mustUnderstand
) {
Assert::oneOf(
$mustUnderstand,
[null, 0, 1],
'Invalid value of env:mustUnderstand attribute in <ecp:Response>.',
ProtocolViolationException::class,
);
}


/**
* Collect the value of the mustUnderstand-property
*
* @return int|null
* @return bool
*/
public function getMustUnderstand(): ?int
public function getMustUnderstand(): bool
{
return $this->mustUnderstand;
}
Expand Down Expand Up @@ -78,20 +73,18 @@ public static function fromXML(DOMElement $xml): static

Assert::oneOf(
$mustUnderstand,
['', '0', '1'],
'Invalid value of env:mustUnderstand attribute in <ecp:Response>.',
['0', '1'],
'Invalid value of env:mustUnderstand attribute in <ecp:RequestAuthenticated>.',
ProtocolViolationException::class,
);
Assert::same(
$actor,
'http://schemas.xmlsoap.org/soap/actor/next',
'Invalid value of env:actor attribute in <ecp:Response>.',
'Invalid value of env:actor attribute in <ecp:RequestAuthenticated>.',
ProtocolViolationException::class,
);

$mustUnderstand = ($mustUnderstand === '') ? null : intval($mustUnderstand);

return new static($mustUnderstand);
return new static(boolval($mustUnderstand));
}


Expand All @@ -103,13 +96,10 @@ public static function fromXML(DOMElement $xml): static
*/
public function toXML(DOMElement $parent = null): DOMElement
{
$response = $this->instantiateParentElement($parent);

if ($this->getMustUnderstand() !== null) {
$response->setAttributeNS(C::NS_SOAP_ENV_11, 'env:mustUnderstand', strval($this->getMustUnderstand()));
}
$response->setAttributeNS(C::NS_SOAP_ENV_11, 'env:actor', 'http://schemas.xmlsoap.org/soap/actor/next');
$e = $this->instantiateParentElement($parent);
$e->setAttributeNS(C::NS_SOAP_ENV_11, 'env:mustUnderstand', strval(intval($this->getMustUnderstand())));
$e->setAttributeNS(C::NS_SOAP_ENV_11, 'env:actor', C::SOAP_ACTOR_NEXT);

return $response;
return $e;
}
}

0 comments on commit a11f078

Please sign in to comment.