55namespace SimpleSAML \XMLSecurity \XML \ds ;
66
77use DOMElement ;
8- use SimpleSAML \Assert \ Assert ;
9- use SimpleSAML \XML \Chunk ;
10- use SimpleSAML \ XML \ Exception \ InvalidDOMElementException ;
8+ use SimpleSAML \XMLSecurity \ Constants as C ;
9+ use SimpleSAML \XMLSecurity \ XML \ec \ InclusiveNamespaces ;
10+ use Webmozart \ Assert \ Assert ;
1111
1212/**
13- * Class representing a ds:Transform element .
13+ * Class representing transforms .
1414 *
1515 * @package simplesamlphp/xml-security
1616 */
17- final class Transform extends AbstractDsElement
17+ class Transform extends AbstractDsElement
1818{
19- /** @var string */
20- protected string $ Algorithm ;
19+ /**
20+ * The algorithm used for this transform.
21+ *
22+ * @var string
23+ */
24+ protected string $ algorithm ;
25+
26+ /**
27+ * An XPath object.
28+ *
29+ * @var XPath|null
30+ */
31+ protected ?XPath $ xpath = null ;
2132
22- /** @var \SimpleSAML\XML\Chunk[] */
23- protected array $ elements = [];
33+ /**
34+ * An InclusiveNamespaces object.
35+ *
36+ * @var InclusiveNamespaces|null
37+ */
38+ protected ?InclusiveNamespaces $ inclusiveNamespaces = null ;
2439
2540
2641 /**
27- * Initialize a ds: Transform
42+ * Initialize the Transform element.
2843 *
29- * @param string $Algorithm
30- * @param \SimpleSAML\XML\Chunk[] $elements
44+ * @param string $algorithm
45+ * @param XPath|null $xpath
46+ * @param InclusiveNamespaces|null $prefixes
3147 */
3248 public function __construct (
33- string $ Algorithm ,
34- array $ elements = []
49+ string $ algorithm ,
50+ ?XPath $ xpath = null ,
51+ ?InclusiveNamespaces $ inclusiveNamespaces = null
3552 ) {
36- $ this ->setElements ($ elements );
37- $ this ->setAlgorithm ($ Algorithm );
53+ $ this ->setAlgorithm ($ algorithm );
54+ $ this ->setXPath ($ xpath );
55+ $ this ->setInclusiveNamespaces ($ inclusiveNamespaces );
3856 }
3957
4058
4159 /**
60+ * Get the algorithm associated with this transform.
61+ *
4262 * @return string
4363 */
4464 public function getAlgorithm (): string
4565 {
46- return $ this ->Algorithm ;
66+ return $ this ->algorithm ;
4767 }
4868
4969
5070 /**
51- * @param string $Algorithm
52- * @throws \SimpleSAML\Assert\AssertionFailedException
71+ * Set the value of the algorithm property.
72+ *
73+ * @param string $algorithm
5374 */
54- protected function setAlgorithm (string $ Algorithm ): void
75+ private function setAlgorithm (string $ algorithm ): void
5576 {
56- Assert::notEmpty ($ Algorithm , 'Cannot set an empty algorithm in ' . static ::NS_PREFIX . ':Transform. ' );
57- $ this ->Algorithm = $ Algorithm ;
77+ $ this ->algorithm = $ algorithm ;
5878 }
5979
6080
6181 /**
62- * Collect the elements
82+ * Get the XPath associated with this transform.
6383 *
64- * @return \SimpleSAML\XML\Chunk[]
84+ * @return XPath|null
6585 */
66- public function getElements (): array
86+ public function getXPath (): ? XPath
6787 {
68- return $ this ->elements ;
88+ return $ this ->xpath ;
6989 }
7090
7191
7292 /**
73- * Set the value of the elements-property
93+ * Set and validate the XPath object.
7494 *
75- * @param \SimpleSAML\XML\Chunk[] $elements
76- * @throws \SimpleSAML\Assert\AssertionFailedException if the supplied array contains anything other than Chunk objects
95+ * @param XPath|null $XPath
7796 */
78- private function setElements ( array $ elements ): void
97+ private function setXPath (? XPath $ xpath ): void
7998 {
80- Assert::allIsInstanceOf ($ elements , Chunk::class);
81-
82- $ this ->elements = $ elements ;
99+ if ($ xpath === null ) {
100+ return ;
101+ }
102+ Assert::eq (
103+ $ this ->algorithm ,
104+ C::XPATH_URI ,
105+ 'Transform algorithm " ' . C::XPATH_URI . '" required if XPath provided. '
106+ );
107+ $ this ->xpath = $ xpath ;
83108 }
84109
85110
86111 /**
87- * Convert XML into a Transform element
88- *
89- * @param \DOMElement $xml The XML element we should load
90- * @return self
112+ * Get the InclusiveNamespaces associated with this transform.
91113 *
92- * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
93- * If the qualified name of the supplied element is wrong
114+ * @return InclusiveNamespaces|null
94115 */
95- public static function fromXML ( DOMElement $ xml ): object
116+ public function getInclusiveNamespaces ( ): ? InclusiveNamespaces
96117 {
97- Assert::same ($ xml ->localName , 'Transform ' , InvalidDOMElementException::class);
98- Assert::same ($ xml ->namespaceURI , Transform::NS , InvalidDOMElementException::class);
99-
100- $ Algorithm = self ::getAttribute ($ xml , 'Algorithm ' );
118+ return $ this ->inclusiveNamespaces ;
119+ }
101120
102- $ elements = [];
103- foreach ($ xml ->childNodes as $ element ) {
104- if (!($ element instanceof DOMElement)) {
105- continue ;
106- }
107121
108- $ elements [] = new Chunk ($ element );
122+ /**
123+ * Set and validate the InclusiveNamespaces object.
124+ *
125+ * @param InclusiveNamespaces|null $inclusiveNamespaces
126+ */
127+ private function setInclusiveNamespaces (?InclusiveNamespaces $ inclusiveNamespaces )
128+ {
129+ if ($ inclusiveNamespaces === null ) {
130+ return ;
109131 }
132+ Assert::oneOf (
133+ $ this ->algorithm ,
134+ [
135+ C::C14N_INCLUSIVE_WITH_COMMENTS ,
136+ C::C14N_EXCLUSIVE_WITHOUT_COMMENTS
137+ ],
138+ 'Transform algorithm " ' . C::C14N_EXCLUSIVE_WITH_COMMENTS . '" or " ' .
139+ C::C14N_EXCLUSIVE_WITHOUT_COMMENTS . '" required if InclusiveNamespaces provided. '
140+ );
141+ $ this ->inclusiveNamespaces = $ inclusiveNamespaces ;
142+ }
110143
111- return new self ($ Algorithm , $ elements );
144+
145+ /**
146+ * Convert XML into a Transform element.
147+ *
148+ * @param \DOMElement $xml The XML element we should load.
149+ * @return self
150+ */
151+ public static function fromXML (DOMElement $ xml ): object
152+ {
153+ $ alg = self ::getAttribute ($ xml , 'Algorithm ' );
154+ $ xpath = XPath::getChildrenOfClass ($ xml );
155+ Assert::maxCount ($ xpath , 1 , 'Only one XPath element supported per Transform. ' );
156+ $ prefixes = InclusiveNamespaces::getChildrenOfClass ($ xml );
157+ Assert::maxCount (
158+ $ prefixes ,
159+ 1 ,
160+ 'Only one InclusiveNamespaces element supported per Transform. '
161+ );
162+
163+ return new self ($ alg , array_pop ($ xpath ), array_pop ($ prefixes ));
112164 }
113165
114166
@@ -121,10 +173,20 @@ public static function fromXML(DOMElement $xml): object
121173 public function toXML (DOMElement $ parent = null ): DOMElement
122174 {
123175 $ e = $ this ->instantiateParentElement ($ parent );
124- $ e ->setAttribute ('Algorithm ' , $ this ->Algorithm );
125176
126- foreach ($ this ->elements as $ element ) {
127- $ e ->appendChild ($ e ->ownerDocument ->importNode ($ element ->getXML (), true ));
177+ $ e ->setAttribute ('Algorithm ' , $ this ->algorithm );
178+
179+ switch ($ this ->algorithm ) {
180+ case C::XPATH_URI :
181+ if ($ this ->xpath !== null ) {
182+ $ this ->xpath ->toXML ($ e );
183+ }
184+ break ;
185+ case C::C14N_EXCLUSIVE_WITH_COMMENTS :
186+ case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS :
187+ if ($ this ->inclusiveNamespaces !== null ) {
188+ $ this ->inclusiveNamespaces ->toXML ($ e );
189+ }
128190 }
129191
130192 return $ e ;
0 commit comments