-
Notifications
You must be signed in to change notification settings - Fork 135
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement saml:AuthzDecisionStatement element (#322)
- Loading branch information
Showing
4 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SimpleSAML\SAML2\XML\saml; | ||
|
||
use DOMElement; | ||
use SimpleSAML\Assert\Assert; | ||
use SimpleSAML\SAML2\Constants as C; | ||
use SimpleSAML\SAML2\Exception\ProtocolViolationException; | ||
use SimpleSAML\XML\Exception\InvalidDOMElementException; | ||
use SimpleSAML\XML\Exception\MissingElementException; | ||
use SimpleSAML\XML\Exception\SchemaViolationException; | ||
use SimpleSAML\XML\Exception\TooManyElementsException; | ||
use SimpleSAML\XML\Utils as XMLUtils; | ||
|
||
use function array_pop; | ||
use function gmdate; | ||
|
||
/** | ||
* Class representing a SAML2 AuthzDecisionStatement | ||
* | ||
* @package simplesamlphp/saml2 | ||
*/ | ||
final class AuthzDecisionStatement extends AbstractStatementType | ||
{ | ||
/** | ||
* Initialize an AuthzDecisionStatement. | ||
* | ||
* @param string $resource | ||
* @param string $decision | ||
* @param \SimpleSAML\SAML2\XML\saml\Action[] $action | ||
* @param \SimpleSAML\SAML2\XML\saml\Evidence|null | ||
*/ | ||
public function __construct( | ||
protected string $resource, | ||
protected string $decision, | ||
protected array $action, | ||
protected ?Evidence $evidence = null, | ||
) { | ||
Assert::validURI($resource); | ||
Assert::oneOf($decision, C::AUTHZ_DECISIONS, ProtocolViolationException::class); | ||
Assert::allIsInstanceOf($action, Action::class, SchemaViolationException::class); | ||
} | ||
|
||
|
||
/** | ||
* Collect the value of the resource-property | ||
* | ||
* @return string | ||
*/ | ||
public function getResource(): string | ||
{ | ||
return $this->resource; | ||
} | ||
|
||
|
||
/** | ||
* Collect the value of the decision-property | ||
* | ||
* @return string | ||
*/ | ||
public function getDecision(): string | ||
{ | ||
return $this->decision; | ||
} | ||
|
||
|
||
/** | ||
* Collect the value of the action-property | ||
* | ||
* @return array | ||
*/ | ||
public function getAction(): array | ||
{ | ||
return $this->action; | ||
} | ||
|
||
|
||
/** | ||
* Collect the value of the evidence-property | ||
* | ||
* @return \SimpleSAML\SAML2\XML\saml\Evidence|null | ||
*/ | ||
public function getEvidence(): ?Evidence | ||
{ | ||
return $this->evidence; | ||
} | ||
|
||
|
||
/** | ||
* Convert XML into an AuthzDecisionStatement | ||
* | ||
* @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\MissingElementException | ||
* if one of the mandatory child-elements is missing | ||
* @throws \Exception if the authentication instant is not a valid timestamp. | ||
*/ | ||
public static function fromXML(DOMElement $xml): static | ||
{ | ||
Assert::same($xml->localName, 'AuthzDecisionStatement', InvalidDOMElementException::class); | ||
Assert::same($xml->namespaceURI, AuthzDecisionStatement::NS, InvalidDOMElementException::class); | ||
|
||
$action = Action::getChildrenOfClass($xml); | ||
Assert::minCount( | ||
$action, | ||
1, | ||
'Missing <saml:Action> in <saml:AuthzDecisionStatement>', | ||
MissingElementException::class, | ||
); | ||
|
||
$evidence = Evidence::getChildrenOfClass($xml); | ||
Assert::maxCount( | ||
$evidence, | ||
1, | ||
'Too many <saml:Evidence> in <saml:AuthzDecisionStatement>', | ||
TooManyElementException::class, | ||
); | ||
|
||
return new static( | ||
self::getAttribute($xml, 'Resource'), | ||
self::getAttribute($xml, 'Decision'), | ||
$action, | ||
array_pop($evidence), | ||
); | ||
} | ||
|
||
|
||
/** | ||
* Convert this AuthzDecisionStatement to XML. | ||
* | ||
* @param \DOMElement|null $parent The element we should append this AuthzDecisionStatement to. | ||
* @return \DOMElement | ||
*/ | ||
public function toXML(DOMElement $parent = null): DOMElement | ||
{ | ||
$e = $this->instantiateParentElement($parent); | ||
|
||
$e->setAttribute('Resource', $this->getResource()); | ||
$e->setAttribute('Decision', $this->getDecision()); | ||
|
||
foreach ($this->getAction() as $action) { | ||
$action->toXML($e); | ||
} | ||
|
||
if ($this->getEvidence() !== null && !$this->getEvidence()->isEmptyElement()) { | ||
$this->getEvidence()->toXML($e); | ||
} | ||
|
||
return $e; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SimpleSAML\SAML2\Test\SAML2\XML\saml; | ||
|
||
use DOMDocument; | ||
use PHPUnit\Framework\TestCase; | ||
use SimpleSAML\SAML2\XML\saml\Action; | ||
use SimpleSAML\SAML2\XML\saml\AuthzDecisionStatement; | ||
use SimpleSAML\SAML2\XML\saml\Evidence; | ||
use SimpleSAML\Test\XML\SchemaValidationTestTrait; | ||
use SimpleSAML\Test\XML\SerializableElementTestTrait; | ||
use SimpleSAML\XML\DOMDocumentFactory; | ||
|
||
use function dirname; | ||
use function strval; | ||
|
||
/** | ||
* Class \SimpleSAML\SAML2\XML\saml\AuthzDecisionStatementTest | ||
* | ||
* @covers \SimpleSAML\SAML2\XML\saml\AuthzDecisionStatement | ||
* @covers \SimpleSAML\SAML2\XML\saml\AbstractStatement | ||
* @covers \SimpleSAML\SAML2\XML\saml\AbstractSamlElement | ||
* | ||
* @package simplesamlphp/saml2 | ||
*/ | ||
final class AuthzDecisionStatementTest extends TestCase | ||
{ | ||
use SchemaValidationTestTrait; | ||
use SerializableElementTestTrait; | ||
|
||
/** @var \DOMDocument $evidence */ | ||
private DOMDocument $evidence; | ||
|
||
|
||
/** | ||
*/ | ||
protected function setUp(): void | ||
{ | ||
$this->schema = dirname(__FILE__, 5) . '/schemas/saml-schema-assertion-2.0.xsd'; | ||
|
||
$this->testedClass = AuthzDecisionStatement::class; | ||
|
||
$this->xmlRepresentation = DOMDocumentFactory::fromFile( | ||
dirname(__FILE__, 4) . '/resources/xml/saml_AuthzDecisionStatement.xml', | ||
); | ||
|
||
$this->evidence = DOMDocumentFactory::fromFile( | ||
dirname(__FILE__, 4) . '/resources/xml/saml_Evidence.xml', | ||
); | ||
} | ||
|
||
|
||
/** | ||
*/ | ||
public function testMarshalling(): void | ||
{ | ||
$authzDecisionStatement = new AuthzDecisionStatement( | ||
'urn:x-simplesamlphp:resource', | ||
'Permit', | ||
[ | ||
new Action('urn:x-simplesamlphp:namespace', 'SomeAction'), | ||
new Action('urn:x-simplesamlphp:namespace', 'OtherAction'), | ||
], | ||
Evidence::fromXML($this->evidence->documentElement), | ||
); | ||
|
||
$this->assertEquals( | ||
$this->xmlRepresentation->saveXML($this->xmlRepresentation->documentElement), | ||
strval($authzDecisionStatement), | ||
); | ||
} | ||
|
||
|
||
/** | ||
*/ | ||
public function testUnmarshalling(): void | ||
{ | ||
$authzDecisionStatement = AuthzDecisionStatement::fromXML($this->xmlRepresentation->documentElement); | ||
|
||
$this->assertEquals( | ||
$this->xmlRepresentation->saveXML($this->xmlRepresentation->documentElement), | ||
strval($authzDecisionStatement), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<saml:AuthzDecisionStatement xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Resource="urn:x-simplesamlphp:resource" Decision="Permit"> | ||
<saml:Action Namespace="urn:x-simplesamlphp:namespace">SomeAction</saml:Action> | ||
<saml:Action Namespace="urn:x-simplesamlphp:namespace">OtherAction</saml:Action> | ||
<saml:Evidence> | ||
<saml:AssertionIDRef>_Test</saml:AssertionIDRef> | ||
<saml:AssertionURIRef>urn:x-simplesamlphp:reference</saml:AssertionURIRef> | ||
<saml:Assertion Version="2.0" ID="_93af655219464fb403b34436cfb0c5cb1d9a5502" IssueInstant="1970-01-01T01:33:31Z"> | ||
<saml:Issuer>Provider</saml:Issuer> | ||
<saml:Subject> | ||
<saml:NameID SPNameQualifier="https://sp.example.org/authentication/sp/metadata" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">SomeNameIDValue</saml:NameID> | ||
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> | ||
<saml:NameID SPNameQualifier="https://sp.example.org/authentication/sp/metadata" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">SomeOtherNameIDValue</saml:NameID> | ||
<saml:SubjectConfirmationData NotOnOrAfter="2011-08-31T08:51:05Z" Recipient="https://sp.example.org/authentication/sp/consume-assertion" InResponseTo="_13603a6565a69297e9809175b052d115965121c8" /> | ||
</saml:SubjectConfirmation> | ||
</saml:Subject> | ||
<saml:Conditions NotBefore="2011-08-31T08:51:05Z" NotOnOrAfter="2011-08-31T08:51:05Z"> | ||
<saml:AudienceRestriction> | ||
<saml:Audience>https://simplesamlphp.org/sp/metadata</saml:Audience> | ||
</saml:AudienceRestriction> | ||
</saml:Conditions> | ||
<saml:AuthnStatement AuthnInstant="2011-08-31T08:51:05Z" SessionIndex="_93af655219464fb403b34436cfb0c5cb1d9a5502"> | ||
<saml:SubjectLocality Address="127.0.0.1"/> | ||
<saml:AuthnContext> | ||
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef> | ||
</saml:AuthnContext> | ||
</saml:AuthnStatement> | ||
<saml:AttributeStatement> | ||
<saml:Attribute Name="urn:test:ServiceID"> | ||
<saml:AttributeValue>1</saml:AttributeValue> | ||
</saml:Attribute> | ||
<saml:Attribute Name="urn:test:EntityConcernedID"> | ||
<saml:AttributeValue>1</saml:AttributeValue> | ||
</saml:Attribute> | ||
<saml:Attribute Name="urn:test:EntityConcernedSubID"> | ||
<saml:AttributeValue>1</saml:AttributeValue> | ||
</saml:Attribute> | ||
</saml:AttributeStatement> | ||
</saml:Assertion> | ||
<saml:EncryptedAssertion> | ||
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element"> | ||
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2009xmlenc11#aes256-gcm"/> | ||
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> | ||
<xenc:EncryptedKey> | ||
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/> | ||
<xenc:CipherData> | ||
<xenc:CipherValue>sNLWjwyj/R0oPwSgNnqowahiOwM0YU3YaH3jsH0t2YUDcHkcgouvW5x6YbNdgvGq0ImsNrkjI//0hrL4HvrOX33+DkhCo2FX5+a7UCdftfBfSjvt0houF8z3Zq/XOm6HxBUbWt5MULYpMKMZ9iAY6+raydxk2tFWgnAyHaBfzvU=</xenc:CipherValue> | ||
</xenc:CipherData> | ||
</xenc:EncryptedKey> | ||
<ds:RetrievalMethod URI="#Encrypted_KEY_ID" Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey"> | ||
<ds:Transforms> | ||
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> | ||
<ds:XPath xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">self::xenc:CipherValue[@Id="example1"]</ds:XPath> | ||
</ds:Transform> | ||
</ds:Transforms> | ||
</ds:RetrievalMethod> | ||
</ds:KeyInfo> | ||
<xenc:CipherData> | ||
<xenc:CipherValue>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</xenc:CipherValue> | ||
</xenc:CipherData> | ||
</xenc:EncryptedData> | ||
</saml:EncryptedAssertion> | ||
</saml:Evidence> | ||
</saml:AuthzDecisionStatement> |