Skip to content

Commit

Permalink
Introduce a separate class to respresent SAML artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
tvdijen committed Jul 20, 2024
1 parent 21cc660 commit 8dce3ea
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 14 deletions.
4 changes: 3 additions & 1 deletion src/SAML2/HTTPArtifact.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use SimpleSAML\SAML2\Utils;
use SimpleSAML\SAML2\XML\saml\Issuer;
use SimpleSAML\SAML2\XML\samlp\AbstractMessage;
use SimpleSAML\SAML2\XML\samlp\Artifact;
use SimpleSAML\SAML2\XML\samlp\ArtifactResolve;
use SimpleSAML\SAML2\XML\samlp\ArtifactResponse;
use SimpleSAML\Store\StoreFactory;
Expand Down Expand Up @@ -168,7 +169,7 @@ public function receive(ServerRequestInterface $request): AbstractMessage
$issuer = new Issuer($this->spMetadata->getString('entityid'));

// Construct the ArtifactResolve Request
$ar = new ArtifactResolve($query['SAMLart'], null, $issuer, null, '2.0', $endpoint['Location']);
$ar = new ArtifactResolve(new Artifact($artifact), null, $issuer, null, '2.0', $endpoint['Location']);

// sign the request
/** @psalm-suppress UndefinedClass */
Expand All @@ -193,6 +194,7 @@ public function receive(ServerRequestInterface $request): AbstractMessage

$samlResponse->addValidator([get_class($this), 'validateSignature'], $artifactResponse);

$query = $request->getQueryParams();
if (isset($query['RelayState'])) {
$this->setRelayState($query['RelayState']);
}
Expand Down
63 changes: 63 additions & 0 deletions src/SAML2/XML/samlp/Artifact.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\XML\samlp;

use DOMElement;
use SimpleSAML\Assert\Assert;
use SimpleSAML\XML\Base64ElementTrait;
use SimpleSAML\XML\Exception\InvalidDOMElementException;
use SimpleSAML\XML\Exception\SchemaViolationException;

/**
* Class for SAML artifacts.
*
* @package simplesamlphp/saml2
*/
final class Artifact extends AbstractSamlpElement
{
use Base64ElementTrait;

/**
* Initialize an artifact.
*
* @param string $content
*/
public function __construct(
string $content,
) {
$this->setContent($content);
}


/**
* Validate the content of the element.
*
* @param string $content The value to go in the XML textContent
* @throws \Exception on failure
* @return void
*/
protected function validateContent(string $content): void
{
Assert::validURI($content, SchemaViolationException::class); // Covers the empty string
}


/**
* Convert XML into an Artifact
*
* @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, 'Artifact', InvalidDOMElementException::class);
Assert::same($xml->namespaceURI, Artifact::NS, InvalidDOMElementException::class);

return new static($xml->textContent);
}
}
21 changes: 8 additions & 13 deletions src/SAML2/XML/samlp/ArtifactResolve.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
use DateTimeImmutable;
use DOMElement;
use SimpleSAML\Assert\Assert;
use SimpleSAML\SAML2\Constants as C;
use SimpleSAML\SAML2\Exception\Protocol\RequestVersionTooHighException;
use SimpleSAML\SAML2\Exception\Protocol\RequestVersionTooLowException;
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
use SimpleSAML\SAML2\Utils\XPath;
use SimpleSAML\SAML2\XML\saml\Issuer;
use SimpleSAML\XML\Exception\InvalidDOMElementException;
use SimpleSAML\XML\Exception\MissingElementException;
use SimpleSAML\XML\Exception\TooManyElementsException;
use SimpleSAML\XMLSecurity\XML\ds\Signature;

Expand All @@ -32,7 +31,7 @@ class ArtifactResolve extends AbstractRequest
/**
* Initialize an ArtifactResolve.
*
* @param string $artifact
* @param \SimpleSAML\SAML2\XML\samlp\Artifact $artifact
* @param \DateTimeImmutable $issueInstant
* @param \SimpleSAML\SAML2\XML\saml\Issuer|null $issuer
* @param string|null $id
Expand All @@ -44,7 +43,7 @@ class ArtifactResolve extends AbstractRequest
* @throws \Exception
*/
final public function __construct(
protected string $artifact,
protected Artifact $artifact,
DateTimeImmutable $issueInstant,
?Issuer $issuer = null,
?string $id = null,
Expand All @@ -61,12 +60,8 @@ final public function __construct(

/**
* Retrieve the Artifact in this response.
*
* @return string artifact.
*
* @throws \SimpleSAML\Assert\AssertionFailedException if assertions are false
*/
public function getArtifact(): string
public function getArtifact(): Artifact
{
return $this->artifact;
}
Expand Down Expand Up @@ -118,8 +113,9 @@ public static function fromXML(DOMElement $xml): static
$signature = Signature::getChildrenOfClass($xml);
Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);

$results = XPath::xpQuery($xml, './saml_protocol:Artifact', XPath::getXPath($xml));
$artifact = $results[0]->textContent;
$artifact = Artifact::getChildrenOfClass($xml);
Assert::minCount($artifact, 1, 'At least one samlp:Artifact is required.', MissingElementException::class);
Assert::maxCount($artifact, 1, 'Only one samlp:Artifact is allowed.', TooManyElementsException::class);

$resolve = new static(
$artifact,
Expand Down Expand Up @@ -152,8 +148,7 @@ protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
Assert::notEmpty($this->artifact, 'Cannot convert ArtifactResolve to XML without an Artifact set.');

$e = parent::toUnsignedXML($parent);
$artifactelement = $e->ownerDocument->createElementNS(C::NS_SAMLP, 'Artifact', $this->getArtifact());
$e->appendChild($artifactelement);
$this->getArtifact()->toXML($e);

return $e;
}
Expand Down
57 changes: 57 additions & 0 deletions tests/SAML2/XML/samlp/ArtifactTest.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\samlp;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use SimpleSAML\SAML2\XML\samlp\AbstractSamlpElement;
use SimpleSAML\SAML2\XML\samlp\Artifact;
use SimpleSAML\XML\DOMDocumentFactory;
use SimpleSAML\XML\TestUtils\SchemaValidationTestTrait;
use SimpleSAML\XML\TestUtils\SerializableElementTestTrait;

use function dirname;
use function strval;

/**
* Class \SimpleSAML\SAML2\XML\samlp\ArtifactTest
*
* @package simplesamlphp/saml2
*/
#[Group('samlp')]
#[CoversClass(Artifact::class)]
#[CoversClass(AbstractSamlpElement::class)]
final class ArtifactTest extends TestCase
{
use SchemaValidationTestTrait;
use SerializableElementTestTrait;

/**
*/
public static function setUpBeforeClass(): void
{
self::$schemaFile = dirname(__FILE__, 5) . '/resources/schemas/saml-schema-protocol-2.0.xsd';

self::$testedClass = Artifact::class;

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


/**
*/
public function testMarshalling(): void
{
$artifact = new Artifact('cGhwdW5pdA==');

$this->assertEquals(
self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
strval($artifact),
);
}
}
1 change: 1 addition & 0 deletions tests/resources/xml/samlp_Artifact.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<samlp:Artifact xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">cGhwdW5pdA==</samlp:Artifact>

0 comments on commit 8dce3ea

Please sign in to comment.