Skip to content

Commit bb9c926

Browse files
committed
Add testable CustomSignable and CustomSigned
1 parent 2def928 commit bb9c926

6 files changed

Lines changed: 215 additions & 4 deletions

File tree

bin/generate_CustomSignable.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
require_once('../vendor/autoload.php');
4+
5+
use SimpleSAML\XML\Chunk;
6+
use SimpleSAML\XML\DOMDocumentFactory;
7+
use SimpleSAML\XMLSecurity\Test\XML\CustomSignable;
8+
use SimpleSAML\XMLSecurity\TestUtils\PEMCertificatesMock;
9+
use SimpleSAML\XMLSecurity\XMLSecurityKey;
10+
11+
$chunk = new Chunk(DOMDocumentFactory::fromString('<some>Chunk</some>')->documentElement);
12+
$signable = new CustomSignable($chunk);
13+
14+
$privateKey = PEMCertificatesMock::getPrivateKey(XMLSecurityKey::RSA_SHA256, PEMCertificatesMock::SELFSIGNED_PRIVATE_KEY);
15+
$x = $signable->sign($privateKey);
16+
echo $x;
17+
//var_dump($x);

src/XML/AbstractSignedXMLElement.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,25 @@ abstract class AbstractSignedXMLElement implements SignedElementInterface
3838
* @param \SimpleSAML\XMLSecurity\XML\SignableElementInterface $elt
3939
* @param \SimpleSAML\XMLSecurity\XML\ds\Signature $signature
4040
*/
41-
private function __construct(DOMElement $xml, SignableElementInterface $elt, Signature $signature)
41+
protected function __construct(DOMElement $xml, SignableElementInterface $elt, Signature $signature)
4242
{
4343
$this->setStructure($xml);
4444
$this->setElement($elt);
4545
$this->setSignature($signature);
4646
}
4747

4848

49+
/**
50+
* Output the class as an XML-formatted string
51+
*
52+
* @return string
53+
*/
54+
public function __toString(): string
55+
{
56+
return $this->structure->ownerDocument->saveXML();
57+
}
58+
59+
4960
/**
5061
* Collect the value of the unsigned element
5162
*

src/XML/SignableElementTrait.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
use DOMElement;
88
use DOMNode;
99
use SimpleSAML\Assert\Assert;
10+
use SimpleSAML\XML\Utils as XMLUtils;
1011
use SimpleSAML\XMLSecurity\Utils\Security as XMLSecurityUtils;
1112
use SimpleSAML\XMLSecurity\XML\ds\Signature;
1213
use SimpleSAML\XMLSecurity\XMLSecurityKey;
13-
use SimpleSAML\XML\Utils as XMLUtils;
1414

1515
/**
1616
* Helper trait for processing signed elements.
@@ -34,7 +34,6 @@ private function toSignedXML(XMLSecurityKey $signingKey, array $certificates, DO
3434

3535
if ($insertBefore !== null) {
3636
XMLSecurityUtils::insertSignature($signingKey, $certificates, $root, $insertBefore);
37-
$doc = clone $root->ownerDocument;
3837
} else {
3938
$signature = new Signature($signingKey->getAlgorithm(), $certificates, $signingKey);
4039
$signature->toXML($root);

src/XML/SignedElementTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ public function validate(XMLSecurityKey $key): bool
6363
return false;
6464
}
6565

66-
$signer = $this->signature->getSigner();
6766
Assert::eq(
6867
$key->getAlgorithm(),
6968
$this->signature->getAlgorithm(),
7069
'Algorithm provided in key does not match algorithm used in signature.'
7170
);
7271

7372
// check the signature
73+
$signer = $this->signature->getSigner();
7474
if ($signer->verify($key) === 1) {
7575
return true;
7676
}

tests/XML/CustomSignable.php

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\Test\XML;
6+
7+
use DOMElement;
8+
use SimpleSAML\Assert\Assert;
9+
use SimpleSAML\XML\AbstractXMLElement;
10+
use SimpleSAML\XML\Chunk;
11+
use SimpleSAML\XML\Exception\InvalidDOMElementException;
12+
use SimpleSAML\XML\Exception\MissingElementException;
13+
use SimpleSAML\XML\Exception\TooManyElementsException;
14+
use SimpleSAML\XMLSecurity\XML\SignableElementInterface;
15+
use SimpleSAML\XMLSecurity\XML\SignableElementTrait;
16+
use SimpleSAML\XMLSecurity\XML\SignedElementInterface;
17+
use SimpleSAML\XMLSecurity\XMLSecurityKey;
18+
19+
/**
20+
* @package simplesamlphp\saml2
21+
*/
22+
final class CustomSignable extends AbstractXMLElement implements SignableElementInterface
23+
{
24+
use SignableElementTrait;
25+
26+
/** @var string */
27+
public const NS = 'urn:simplesamlphp:test';
28+
29+
/** @var string */
30+
public const NS_PREFIX = 'ssp';
31+
32+
/** @var \SimpleSAML\XML\Chunk $element */
33+
protected $element;
34+
35+
/**
36+
* Constructor
37+
*
38+
* @param \SimpleSAML\XML\Chunk $elt
39+
*/
40+
public function __construct(Chunk $elt) {
41+
$this->setElement($elt);
42+
}
43+
44+
45+
/**
46+
* Get the namespace for the element.
47+
*
48+
* @return string
49+
*/
50+
public static function getNamespaceURI(): string
51+
{
52+
return static::NS;
53+
}
54+
55+
56+
/**
57+
* Get the namespace-prefix for the element.
58+
*
59+
* @return string
60+
*/
61+
public static function getNamespacePrefix(): string
62+
{
63+
return static::NS_PREFIX;
64+
}
65+
66+
67+
/**
68+
* Collect the value of the $element property
69+
*
70+
* @return \SimpleSAML\XML\XML\Chunk
71+
*/
72+
public function getElement(): Chunk
73+
{
74+
return $this->element;
75+
}
76+
77+
78+
/**
79+
* Set the value of the elment-property
80+
*
81+
* @param \SimpleSAML\XML\Chunk $elt
82+
*/
83+
private function setElement(Chunk $elt): void
84+
{
85+
$this->element = $elt;
86+
}
87+
88+
89+
/**
90+
* Sign the 'Element' and return a 'SignedElement'
91+
*
92+
* @param \SimpleSAML\XMLSecurity\XMLSecurityKey $signingKey The private key we should use to sign the message
93+
* @param string[] $certificates The certificates should be strings with the PEM encoded data
94+
* @return \SimpleSAML\XMLSecurity\XML\SignedElementInterface
95+
*/
96+
public function sign(XMLSecurityKey $signingKey, array $certificates = []): SignedElementInterface
97+
{
98+
return CustomSigned::fromXML($this->toSignedXML($signingKey, $certificates));
99+
}
100+
101+
102+
/**
103+
* Convert XML into a CustomSignable
104+
*
105+
* @param \DOMElement $xml The XML element we should load
106+
* @return \SimpleSAML\XMLSecurity\Test\XML\CustomSignable
107+
*
108+
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
109+
*/
110+
public static function fromXML(DOMElement $xml): object
111+
{
112+
Assert::same($xml->localName, 'CustomSignable', InvalidDOMElementException::class);
113+
Assert::same($xml->namespaceURI, static::NS, InvalidDOMElementException::class);
114+
115+
Assert::minCount($xml->childNodes, 1, MissingElementException::class);
116+
Assert::maxCount($xml->childNodes, 2, TooManyElementsException::class);
117+
$element = new Chunk($xml->childNodes[0]);
118+
119+
return new self($element);
120+
}
121+
122+
123+
/**
124+
* Convert this CustomSignable to XML.
125+
*
126+
* @param \DOMElement|null $element The element we are converting to XML.
127+
* @return \DOMElement The XML element after adding the data corresponding to this CustomSignable.
128+
*/
129+
public function toXML(DOMElement $parent = null): DOMElement
130+
{
131+
/** @psalm-var \DOMDocument $e->ownerDocument */
132+
$e = $this->instantiateParentElement($parent);
133+
134+
$e->appendChild($e->ownerDocument->importNode($this->element->getXML(), true));
135+
return $e;
136+
}
137+
}

tests/XML/CustomSigned.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\Test\XML;
6+
7+
use DOMElement;
8+
use SimpleSAML\Assert\Assert;
9+
use SimpleSAML\XML\Chunk;
10+
use SimpleSAML\XML\Exception\MissingElementException;
11+
use SimpleSAML\XML\Exception\TooManyElementsException;
12+
use SimpleSAML\XML\Utils as XMLUtils;
13+
use SimpleSAML\XMLSecurity\XML\ds\Signature;
14+
use SimpleSAML\XMLSecurity\XML\AbstractSignedXMLElement;
15+
use SimpleSAML\XMLSecurity\XML\SignedElementInterface;
16+
use SimpleSAML\XMLSecurity\XML\SignedElementTrait;
17+
18+
/**
19+
* @package simplesamlphp\saml2
20+
*/
21+
final class CustomSigned extends AbstractSignedXMLElement
22+
{
23+
use SignedElementTrait;
24+
25+
26+
/**
27+
* Create a class from XML
28+
*
29+
* @param \DOMElement $xml
30+
* @return self
31+
*/
32+
public static function fromXML(DOMElement $xml): object
33+
{
34+
Assert::same($xml->localName, 'CustomSignable', InvalidDOMElementException::class);
35+
Assert::same($xml->namespaceURI, CustomSignable::NS, InvalidDOMElementException::class);
36+
37+
$signature = Signature::getChildrenOfClass($xml);
38+
Assert::minCount($signature, 1, MissingElementException::class);
39+
Assert::minCount($signature, 1, TooManyElementsException::class);
40+
41+
return new self(
42+
$xml,
43+
CustomSignable::fromXML($xml),
44+
array_pop($signature)
45+
);
46+
}
47+
}

0 commit comments

Comments
 (0)