Skip to content

Commit 55e334d

Browse files
authored
Add XML-representation for ds:DigestMethod and ds:DigestValue elements (#13)
* Fix phpdoc (unrelated) * Add XML-representation for ds:DigestMethod and ds:DigestValue elements * Add assertion * Properly marshall elements * Reduce marshall-tests to minimum
1 parent f223947 commit 55e334d

7 files changed

Lines changed: 374 additions & 1 deletion

File tree

src/XML/ds/DigestMethod.php

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\XML\ds;
6+
7+
use DOMElement;
8+
use SimpleSAML\Assert\Assert;
9+
use SimpleSAML\XML\Chunk;
10+
use SimpleSAML\XML\Exception\InvalidDOMElementException;
11+
use SimpleSAML\XMLSecurity\Constants;
12+
use SimpleSAML\XMLSecurity\Exception\InvalidArgumentException;
13+
14+
/**
15+
* Class representing a ds:DigestMethod element.
16+
*
17+
* @package simplesamlphp/xml-security
18+
*/
19+
final class DigestMethod extends AbstractDsElement
20+
{
21+
/**
22+
* The algorithm.
23+
*
24+
* @var string
25+
*/
26+
protected string $Algorithm;
27+
28+
/**
29+
* @var \SimpleSAML\XML\Chunk[]
30+
*/
31+
protected array $elements;
32+
33+
34+
/**
35+
* Initialize a DigestMethod element.
36+
*
37+
* @param string $algorithm
38+
* @param \SimpleSAML\XML\Chunk[] $elements
39+
*/
40+
public function __construct(string $algorithm, array $elements = [])
41+
{
42+
$this->setAlgorithm($algorithm);
43+
$this->setElements($elements);
44+
}
45+
46+
47+
/**
48+
* Collect the value of the Algorithm-property
49+
*
50+
* @return string
51+
*/
52+
public function getAlgorithm(): string
53+
{
54+
return $this->Algorithm;
55+
}
56+
57+
58+
/**
59+
* Set the value of the Algorithm-property
60+
*
61+
* @param string $algorithm
62+
*/
63+
private function setAlgorithm(string $algorithm): void
64+
{
65+
Assert::oneOf(
66+
$algorithm,
67+
[
68+
Constants::DIGEST_SHA1,
69+
Constants::DIGEST_SHA224,
70+
Constants::DIGEST_SHA256,
71+
Constants::DIGEST_SHA384,
72+
Constants::DIGEST_SHA512,
73+
Constants::DIGEST_RIPEMD160,
74+
],
75+
'Invalid digest method',
76+
InvalidArgumentException::class
77+
);
78+
79+
$this->Algorithm = $algorithm;
80+
}
81+
82+
83+
/**
84+
* Collect the embedded elements
85+
*
86+
* @return \SimpleSAML\XML\Chunk[]
87+
*/
88+
public function getElements(): array
89+
{
90+
return $this->elements;
91+
}
92+
93+
94+
/**
95+
* Set the value of the elements-property
96+
*
97+
* @param \SimpleSAML\XML\Chunk[] $elements
98+
* @throws \SimpleSAML\Assert\AssertionFailedException if the supplied array contains anything other than Chunk objects
99+
*/
100+
private function setElements(array $elements): void
101+
{
102+
Assert::allIsInstanceOf($elements, Chunk::class);
103+
104+
$this->elements = $elements;
105+
}
106+
107+
108+
/**
109+
* Convert XML into a DigestMethod
110+
*
111+
* @param \DOMElement $xml The XML element we should load
112+
* @return self
113+
*
114+
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
115+
* If the qualified name of the supplied element is wrong
116+
*/
117+
public static function fromXML(DOMElement $xml): object
118+
{
119+
Assert::same($xml->localName, 'DigestMethod', InvalidDOMElementException::class);
120+
Assert::same($xml->namespaceURI, DigestMethod::NS, InvalidDOMElementException::class);
121+
122+
$Algorithm = DigestMethod::getAttribute($xml, 'Algorithm');
123+
124+
$elements = [];
125+
foreach ($xml->childNodes as $elt) {
126+
if (!($elt instanceof DOMElement)) {
127+
continue;
128+
}
129+
130+
$elements[] = new Chunk($elt);
131+
}
132+
133+
return new self($Algorithm, $elements);
134+
}
135+
136+
137+
/**
138+
* Convert this DigestMethod element to XML.
139+
*
140+
* @param \DOMElement|null $parent The element we should append this DigestMethod element to.
141+
* @return \DOMElement
142+
*/
143+
public function toXML(DOMElement $parent = null): DOMElement
144+
{
145+
$e = $this->instantiateParentElement($parent);
146+
$e->setAttribute('Algorithm', $this->Algorithm);
147+
148+
foreach ($this->elements as $elt) {
149+
$e->appendChild($e->ownerDocument->importNode($elt->getXML(), true));
150+
}
151+
152+
return $e;
153+
}
154+
}

src/XML/ds/DigestValue.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\XML\ds;
6+
7+
use DOMElement;
8+
use SimpleSAML\Assert\Assert;
9+
use SimpleSAML\XML\Exception\InvalidDOMElementException;
10+
11+
/**
12+
* Class representing a ds:DigestValue element.
13+
*
14+
* @package simplesaml/xml-security
15+
*/
16+
final class DigestValue extends AbstractDsElement
17+
{
18+
/**
19+
* The digest value.
20+
*
21+
* @var string
22+
*/
23+
protected string $digest;
24+
25+
26+
/**
27+
* Initialize a DigestValue element.
28+
*
29+
* @param string $digest
30+
*/
31+
public function __construct(string $digest)
32+
{
33+
$this->setDigest($digest);
34+
}
35+
36+
37+
/**
38+
* Collect the value of the digest-property
39+
*
40+
* @return string
41+
*/
42+
public function getDigest(): string
43+
{
44+
return $this->digest;
45+
}
46+
47+
48+
/**
49+
* Set the value of the digest-property
50+
*
51+
* @param string $digest
52+
*/
53+
private function setDigest(string $digest): void
54+
{
55+
Assert::notEmpty($digest, 'DigestValue cannot be empty');
56+
Assert::stringPlausibleBase64($digest, 'ds:DigestValue is not a valid Base64 encoded string');
57+
$this->digest = $digest;
58+
}
59+
60+
61+
/**
62+
* Convert XML into a DigestValue
63+
*
64+
* @param \DOMElement $xml The XML element we should load
65+
* @return self
66+
*
67+
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
68+
* If the qualified name of the supplied element is wrong
69+
*/
70+
public static function fromXML(DOMElement $xml): object
71+
{
72+
Assert::same($xml->localName, 'DigestValue', InvalidDOMElementException::class);
73+
Assert::same($xml->namespaceURI, DigestValue::NS, InvalidDOMElementException::class);
74+
75+
return new self($xml->textContent);
76+
}
77+
78+
79+
/**
80+
* Convert this DigestValue element to XML.
81+
*
82+
* @param \DOMElement|null $parent The element we should append this DigestValue element to.
83+
* @return \DOMElement
84+
*/
85+
public function toXML(DOMElement $parent = null): DOMElement
86+
{
87+
$e = $this->instantiateParentElement($parent);
88+
$e->textContent = $this->digest;
89+
90+
return $e;
91+
}
92+
}

src/XML/ds/SignatureMethod.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public static function fromXML(DOMElement $xml): object
101101
/**
102102
* Convert this SignatureMethod element to XML.
103103
*
104-
* @param \DOMElement|null $parent The element we should append this KeyName element to.
104+
* @param \DOMElement|null $parent The element we should append this SignatureMethod element to.
105105
* @return \DOMElement
106106
*/
107107
public function toXML(DOMElement $parent = null): DOMElement

tests/XML/ds/DigestMethodTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\Test\XML\ds;
6+
7+
use DOMDocument;
8+
use PHPUnit\Framework\TestCase;
9+
use SimpleSAML\Test\XML\SerializableXMLTestTrait;
10+
use SimpleSAML\XML\Chunk;
11+
use SimpleSAML\XML\DOMDocumentFactory;
12+
use SimpleSAML\XMLSecurity\Constants;
13+
use SimpleSAML\XMLSecurity\XML\ds\DigestMethod;
14+
15+
/**
16+
* Class \SimpleSAML\XMLSecurity\XML\ds\DigestMethodTest
17+
*
18+
* @covers \SimpleSAML\XMLSecurity\XML\ds\AbstractDsElement
19+
* @covers \SimpleSAML\XMLSecurity\XML\ds\DigestMethod
20+
*
21+
* @package simplesamlphp/xml-security
22+
*/
23+
final class DigestMethodTest extends TestCase
24+
{
25+
use SerializableXMLTestTrait;
26+
27+
28+
/**
29+
*/
30+
protected function setUp(): void
31+
{
32+
$this->testedClass = DigestMethod::class;
33+
34+
$this->xmlRepresentation = DOMDocumentFactory::fromFile(
35+
dirname(dirname(dirname(dirname(__FILE__)))) . '/tests/resources/xml/ds_DigestMethod.xml'
36+
);
37+
}
38+
39+
40+
/**
41+
*/
42+
public function testMarshalling(): void
43+
{
44+
$digestMethod = new DigestMethod(
45+
Constants::DIGEST_SHA256,
46+
[new Chunk(DOMDocumentFactory::fromString('<some:Chunk>Random</some:Chunk>')->documentElement)]
47+
);
48+
49+
$this->assertEquals(
50+
$this->xmlRepresentation->saveXML($this->xmlRepresentation->documentElement),
51+
strval($digestMethod)
52+
);
53+
}
54+
55+
56+
/**
57+
*/
58+
public function testUnmarshalling(): void
59+
{
60+
$digestMethod = DigestMethod::fromXML($this->xmlRepresentation->documentElement);
61+
62+
$this->assertEquals(Constants::DIGEST_SHA256, $digestMethod->getAlgorithm());
63+
}
64+
}

tests/XML/ds/DigestValueTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\Test\XML\ds;
6+
7+
use DOMDocument;
8+
use PHPUnit\Framework\TestCase;
9+
use SimpleSAML\Test\XML\SerializableXMLTestTrait;
10+
use SimpleSAML\XML\DOMDocumentFactory;
11+
use SimpleSAML\XMLSecurity\XML\ds\DigestValue;
12+
use SimpleSAML\XMLSecurity\XMLSecurityDSig;
13+
14+
/**
15+
* Class \SimpleSAML\XMLSecurity\XML\ds\DigestValueTest
16+
*
17+
* @covers \SimpleSAML\XMLSecurity\XML\ds\AbstractDsElement
18+
* @covers \SimpleSAML\XMLSecurity\XML\ds\DigestValue
19+
*
20+
* @package simplesamlphp/xml-security
21+
*/
22+
final class DigestValueTest extends TestCase
23+
{
24+
use SerializableXMLTestTrait;
25+
26+
/**
27+
*/
28+
protected function setUp(): void
29+
{
30+
$this->testedClass = DigestValue::class;
31+
32+
$this->xmlRepresentation = DOMDocumentFactory::fromFile(
33+
dirname(dirname(dirname(dirname(__FILE__)))) . '/tests/resources/xml/ds_DigestValue.xml'
34+
);
35+
}
36+
37+
38+
/**
39+
*/
40+
public function testMarshalling(): void
41+
{
42+
$digestValue = new DigestValue('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI=');
43+
44+
$this->assertEquals(
45+
$this->xmlRepresentation->saveXML($this->xmlRepresentation->documentElement),
46+
strval($digestValue)
47+
);
48+
}
49+
50+
51+
/**
52+
*/
53+
public function testUnmarshalling(): void
54+
{
55+
$digestValue = DigestValue::fromXML($this->xmlRepresentation->documentElement);
56+
57+
$this->assertEquals('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI=', $digestValue->getDigest());
58+
}
59+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<ds:DigestMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/04/xmlenc#sha256">
2+
<some:Chunk>Random</some:Chunk>
3+
</ds:DigestMethod>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI=</ds:DigestValue>

0 commit comments

Comments
 (0)