Passed
Pull Request — master (#2)
by Jaime Pérez
02:11
created

XML::processTransforms()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 39
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 8
eloc 22
c 2
b 0
f 0
nc 10
nop 2
dl 0
loc 39
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\Utils;
6
7
use DOMElement;
8
use SimpleSAML\XMLSecurity\Constants as C;
9
use SimpleSAML\XMLSecurity\XML\ds\Transforms;
10
11
use function count;
12
use function is_null;
13
14
/**
15
 * Class with utility methods for XML manipulation.
16
 *
17
 * @package simplesamlphp/xml-security
18
 */
19
class XML
20
{
21
    /**
22
     * Canonicalize any given node.
23
     *
24
     * @param \DOMElement $element The DOM element that needs canonicalization.
25
     * @param string $c14nMethod The identifier of the canonicalization algorithm to use.
26
     * See \SimpleSAML\XMLSecurity\Constants.
27
     * @param array|null $xpaths An array of xpaths to filter the nodes by. Defaults to null (no filters).
28
     * @param array|null $prefixes An array of namespace prefixes to filter the nodes by. Defaults to null (no filters).
29
     *
30
     * @return string The canonical representation of the given DOM node, according to the algorithm requested.
31
     */
32
    public static function canonicalizeData(
33
        DOMElement $element,
34
        string $c14nMethod,
35
        array $xpaths = null,
36
        array $prefixes = null
37
    ): string {
38
        $exclusive = false;
39
        $withComments = false;
40
        switch ($c14nMethod) {
41
            case C::C14N_EXCLUSIVE_WITH_COMMENTS:
42
            case C::C14N_INCLUSIVE_WITH_COMMENTS:
43
                $withComments = true;
44
        }
45
        switch ($c14nMethod) {
46
            case C::C14N_EXCLUSIVE_WITH_COMMENTS:
47
            case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
48
                $exclusive = true;
49
        }
50
51
        if (
52
            is_null($xpaths)
53
            && ($element->ownerDocument !== null)
54
            && ($element->ownerDocument->documentElement !== null)
55
            && $element->isSameNode($element->ownerDocument->documentElement)
56
        ) {
57
            // check for any PI or comments as they would have been excluded
58
            $current = $element;
59
            while ($refNode = $current->previousSibling) {
60
                if (
61
                    (($refNode->nodeType === XML_COMMENT_NODE) && $withComments)
62
                    || $refNode->nodeType === XML_PI_NODE
63
                ) {
64
                    break;
65
                }
66
                $current = $refNode;
67
            }
68
            if ($refNode === null) {
69
                $element = $element->ownerDocument;
70
            }
71
        }
72
73
        return $element->C14N($exclusive, $withComments, $xpaths, $prefixes);
74
    }
75
76
77
    /**
78
     * Process all transforms specified by a given Reference element.
79
     *
80
     * @param \SimpleSAML\XMLSecurity\XML\ds\Transforms $transforms The transforms to apply.
81
     * @param \DOMElement $data The data referenced.
82
     * @param bool $includeCommentNodes Whether to allow canonicalization with comments or not.
83
     *
84
     * @return string The canonicalized data after applying all transforms specified by $ref.
85
     *
86
     * @see http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
87
     */
88
    public static function processTransforms(
89
        Transforms $transforms,
90
        DOMElement $data
91
    ): string {
92
        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
93
        $arXPath = null;
94
        $prefixList = null;
95
        foreach ($transforms->getTransform() as $transform) {
96
            $canonicalMethod = $transform->getAlgorithm();
97
            switch ($canonicalMethod) {
98
                case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
99
                case C::C14N_EXCLUSIVE_WITH_COMMENTS:
100
                    $inclusiveNamespaces = $transform->getInclusiveNamespaces();
101
                    if ($inclusiveNamespaces !== null) {
102
                        $prefixes = $inclusiveNamespaces->getPrefixes();
103
                        if (count($prefixes) > 0) {
104
                            $prefixList = $prefixes;
105
                        }
106
                    }
107
                    break;
108
                case C::XPATH_URI:
109
                    $xpath = $transform->getXPath();
110
                    if ($xpath !== null) {
111
                        $arXPath = [];
112
                        $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $xpath->getExpression() . ']';
113
                        $arXpath['namespaces'] = $xpath->getNamespaces();
114
                        // TODO: review if $nsnode->localName is equivalent to the keys in getNamespaces()
115
//                        $nslist = $xp->query('./namespace::*', $node);
116
//                        foreach ($nslist as $nsnode) {
117
//                            if ($nsnode->localName != "xml") {
118
//                                $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
119
//                            }
120
//                        }
121
                    }
122
                    break;
123
            }
124
        }
125
126
        return self::canonicalizeData($data, $canonicalMethod, $arXPath, $prefixList);
127
    }
128
}
129