Skip to content

Commit 24043e7

Browse files
committed
Restore backwards compatibility
1 parent 53caaef commit 24043e7

File tree

4 files changed

+455
-0
lines changed

4 files changed

+455
-0
lines changed

src/SAML2/DOMDocumentFactory.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SAML2;
6+
7+
use SimpleSAML\XML\DOMDocumentFactory as BaseDOMDocumentFactory;
8+
9+
/**
10+
* @package SimpleSAMLphp
11+
* @deprecated Use \SimpleSAML\XML\DOMDocumentFactory instead (simplesamlphp/xml-common)
12+
*/
13+
class DOMDocumentFactory extends BaseDOMDocumentFactory
14+
{
15+
/**
16+
* Constructor for DOMDocumentFactory.
17+
* This class should never be instantiated
18+
*/
19+
private function __construct()
20+
{
21+
}
22+
23+
24+
/**
25+
* @param string $xml
26+
*
27+
* @return \DOMDocument
28+
*/
29+
public static function fromString(string $xml): DOMDocument
30+
{
31+
return BaseDOMDocumentFactory::fromString($xml);
32+
}
33+
34+
35+
/**
36+
* @param string $file
37+
*
38+
* @return \DOMDocument
39+
*/
40+
public static function fromFile(string $file): DOMDocument
41+
{
42+
return BaseDOMDocumentFactory::fromFile($file);
43+
}
44+
45+
46+
/**
47+
* @return \DOMDocument
48+
*/
49+
public static function create() : DOMDocument
50+
{
51+
return BaseDOMDocumentFactory::create('1.0', 'UTF-8');
52+
}
53+
}

src/SAML2/XML/Chunk.php

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SAML2\XML;
6+
7+
use DOMElement;
8+
use SimpleSAML\XML\Assert\Assert;
9+
use SimpleSAML\XML\DOMDocumentFactory;
10+
use SimpleSAML\XML\SerializableElementTrait;
11+
use SimpleSAML\XMLSchema\Exception\MissingAttributeException;
12+
use SimpleSAML\XMLSchema\Exception\SchemaViolationException;
13+
use SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface;
14+
use SimpleSAML\XMLSchema\Type\StringValue;
15+
16+
/**
17+
* Serializable class used to hold an XML element.
18+
*
19+
* @package simplesamlphp/xml-common
20+
* @deprecated Use \SimpleSAML\XML\Chunk instead (simplesamlphp/xml-common)
21+
*/
22+
final class Chunk implements
23+
SerializableElementInterface,
24+
ElementInterface
25+
{
26+
use SerializableElementTrait;
27+
28+
29+
/**
30+
* Whether the element may be normalized
31+
*
32+
* @var bool $normalization
33+
*/
34+
protected bool $normalization = true;
35+
36+
/**
37+
* The localName of the element.
38+
*
39+
* @var string
40+
*/
41+
protected string $localName;
42+
43+
/**
44+
* The namespaceURI of this element.
45+
*
46+
* @var string|null
47+
*/
48+
protected ?string $namespaceURI;
49+
50+
/**
51+
* The prefix of this element.
52+
*
53+
* @var string
54+
*/
55+
protected string $prefix;
56+
57+
58+
/**
59+
* Create an XML Chunk from a copy of the given \DOMElement.
60+
*
61+
* @param \DOMElement $xml The element we should copy.
62+
*/
63+
public function __construct(
64+
protected DOMElement $xml,
65+
) {
66+
$this->setLocalName($xml->localName);
67+
$this->setNamespaceURI($xml->namespaceURI);
68+
$this->setPrefix($xml->prefix);
69+
}
70+
71+
72+
/**
73+
* Get this \DOMElement.
74+
*
75+
* @return \DOMElement This element.
76+
*/
77+
public function getXML() : DOMElement
78+
{
79+
return $this->xml;
80+
}
81+
82+
83+
/**
84+
* Append this XML element to a different XML element.
85+
*
86+
* @param \DOMElement $parent The element we should append this element to.
87+
* @return \DOMElement The new element.
88+
*/
89+
public function toXML(DOMElement $parent) : DOMElement
90+
{
91+
return Utils::copyElement($this->xml, $parent);
92+
}
93+
94+
95+
/**
96+
* Collect the value of the localName-property
97+
*
98+
* @return string
99+
*/
100+
public function getLocalName() : string
101+
{
102+
return $this->localName;
103+
}
104+
105+
106+
/**
107+
* Set the value of the localName-property
108+
*
109+
* @param string $localName
110+
* @return void
111+
*/
112+
public function setLocalName(string $localName) : void
113+
{
114+
$this->localName = $localName;
115+
}
116+
117+
118+
/**
119+
* Collect the value of the namespaceURI-property
120+
*
121+
* @return string|null
122+
*/
123+
public function getNamespaceURI() : ?string
124+
{
125+
return $this->namespaceURI;
126+
}
127+
128+
129+
/**
130+
* Set the value of the namespaceURI-property
131+
*
132+
* @param string|null $namespaceURI
133+
* @return void
134+
*/
135+
public function setNamespaceURI(?string $namespaceURI = null) : void
136+
{
137+
$this->namespaceURI = $namespaceURI;
138+
}
139+
140+
141+
/**
142+
* Serialize this XML chunk.
143+
*
144+
* @return string The serialized chunk.
145+
*/
146+
public function serialize() : string
147+
{
148+
return serialize($this->xml->ownerDocument->saveXML($this->xml));
149+
}
150+
151+
152+
/**
153+
* Un-serialize this XML chunk.
154+
*
155+
* @param string $serialized The serialized chunk.
156+
* @return void
157+
*
158+
* Type hint not possible due to upstream method signature
159+
*/
160+
public function unserialize($serialized) : void
161+
{
162+
$doc = DOMDocumentFactory::fromString(unserialize($serialized));
163+
$this->xml = $doc->documentElement;
164+
$this->setLocalName($this->xml->localName);
165+
$this->setNamespaceURI($this->xml->namespaceURI);
166+
}
167+
168+
169+
170+
/**
171+
* Serialize this XML chunk.
172+
*
173+
* This method will be invoked by any calls to serialize().
174+
*
175+
* @return array The serialized representation of this XML object.
176+
*/
177+
public function __serialize(): array
178+
{
179+
$xml = $this->getXML();
180+
/** @psalm-var \DOMDocument $xml->ownerDocument */
181+
return [$xml->ownerDocument->saveXML($xml)];
182+
}
183+
184+
185+
/**
186+
* Unserialize an XML object and load it..
187+
*
188+
* This method will be invoked by any calls to unserialize(), allowing us to restore any data that might not
189+
* be serializable in its original form (e.g.: DOM objects).
190+
*
191+
* @param array $vars The XML object that we want to restore.
192+
*/
193+
public function __unserialize(array $serialized): void
194+
{
195+
$xml = new self(
196+
DOMDocumentFactory::fromString(array_pop($serialized))->documentElement
197+
);
198+
199+
$vars = get_object_vars($xml);
200+
foreach ($vars as $k => $v) {
201+
$this->$k = $v;
202+
}
203+
}
204+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SAML2;
6+
7+
use SAML2\DOMDocumentFactory;
8+
use SAML2\Exception\UnparseableXmlException;
9+
use SAML2\Exception\InvalidArgumentException;
10+
use SAML2\Exception\RuntimeException;
11+
12+
class DOMDocumentFactoryTest extends \PHPUnit\Framework\TestCase
13+
{
14+
/**
15+
* @group domdocument
16+
* @return void
17+
*/
18+
public function testNotXmlStringRaisesAnException() : void
19+
{
20+
$this->expectException(UnparseableXmlException::class);
21+
DOMDocumentFactory::fromString('this is not xml');
22+
}
23+
24+
25+
/**
26+
* @group domdocument
27+
* @return void
28+
*/
29+
public function testXmlStringIsCorrectlyLoaded() : void
30+
{
31+
$xml = '<root/>';
32+
33+
$document = DOMDocumentFactory::fromString($xml);
34+
35+
$this->assertXmlStringEqualsXmlString($xml, $document->saveXML());
36+
}
37+
38+
39+
/**
40+
* @return void
41+
*/
42+
public function testFileThatDoesNotExistIsNotAccepted() : void
43+
{
44+
$this->expectException(InvalidArgumentException::class);
45+
$filename = 'DoesNotExist.ext';
46+
DOMDocumentFactory::fromFile($filename);
47+
}
48+
49+
50+
/**
51+
* @group domdocument
52+
* @return void
53+
*/
54+
public function testFileThatDoesNotContainXMLCannotBeLoaded() : void
55+
{
56+
$this->expectException(RuntimeException::class);
57+
$file = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'domdocument_invalid_xml.xml';
58+
DOMDocumentFactory::fromFile($file);
59+
}
60+
61+
62+
/**
63+
* @group domdocument
64+
* @return void
65+
*/
66+
public function testFileWithValidXMLCanBeLoaded() : void
67+
{
68+
$file = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'domdocument_valid_xml.xml';
69+
70+
$document = DOMDocumentFactory::fromFile($file);
71+
72+
$this->assertXmlStringEqualsXmlFile($file, $document->saveXML());
73+
}
74+
75+
76+
/**
77+
* @group domdocument
78+
* @return void
79+
*/
80+
public function testFileThatContainsDocTypeIsNotAccepted() : void
81+
{
82+
$this->expectException(RuntimeException::class, 'Dangerous XML detected, DOCTYPE nodes are not allowed in the XML body');
83+
$file = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'domdocument_doctype.xml';
84+
$this->expectException(Exception\RuntimeException::class, 'Dangerous XML detected, DOCTYPE nodes are not allowed in the XML body');
85+
DOMDocumentFactory::fromFile($file);
86+
}
87+
88+
89+
/**
90+
* @group domdocument
91+
* @return void
92+
*/
93+
public function testStringThatContainsDocTypeIsNotAccepted() : void
94+
{
95+
$this->expectException(RuntimeException::class, 'Dangerous XML detected, DOCTYPE nodes are not allowed in the XML body');
96+
$xml = '<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///dev/random" >]><foo />';
97+
$this->expectException(Exception\RuntimeException::class, 'Dangerous XML detected, DOCTYPE nodes are not allowed in the XML body');
98+
DOMDocumentFactory::fromString($xml);
99+
}
100+
101+
102+
/**
103+
* @group domdocument
104+
* @return void
105+
*/
106+
public function testStringThatContainsDocTypeIsNotAccepted2(): void
107+
{
108+
$xml = '<?xml version="1.0" encoding="ISO-8859-1"?>
109+
<!DOCTYPE foo [<!ENTITY % exfiltrate SYSTEM "file://dev/random">%exfiltrate;]>
110+
<foo>y</foo>';
111+
$this->expectException(RuntimeException::class);
112+
$this->expectExceptionMessage(
113+
'Dangerous XML detected, DOCTYPE nodes are not allowed in the XML body'
114+
);
115+
DOMDocumentFactory::fromString($xml);
116+
}
117+
118+
/**
119+
* @group domdocument
120+
* @return void
121+
*/
122+
public function testEmptyFileIsNotValid() : void
123+
{
124+
$this->expectException(RuntimeException::class, 'does not have content');
125+
$file = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'domdocument_empty.xml';
126+
$this->expectException(Exception\RuntimeException::class, 'does not have content');
127+
DOMDocumentFactory::fromFile($file);
128+
}
129+
130+
131+
/**
132+
* @group domdocument
133+
* @return void
134+
*/
135+
public function testEmptyStringIsNotValid() : void
136+
{
137+
$this->expectException(InvalidArgumentException::class, 'Invalid Argument type: "non-empty string" expected, "string" given');
138+
DOMDocumentFactory::fromString("");
139+
}
140+
}

0 commit comments

Comments
 (0)