Passed
Pull Request — master (#27)
by Tim
02:32
created

XML   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 43
c 3
b 1
f 0
dl 0
loc 104
rs 10
wmc 18

2 Methods

Rating   Name   Duplication   Size   Complexity  
B processTransforms() 0 39 8
B canonicalizeData() 0 38 10
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
        $withComments = match ($c14nMethod) {
39
            C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_INCLUSIVE_WITH_COMMENTS => true,
40
            default => false,
41
        };
42
        $exclusive = match ($c14nMethod) {
43
            C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS => true,
44
            default => false,
45
        };
46
47
        if (
48
            is_null($xpaths)
49
            && ($element->ownerDocument !== null)
50
            && ($element->ownerDocument->documentElement !== null)
51
            && $element->isSameNode($element->ownerDocument->documentElement)
52
        ) {
53
            // check for any PI or comments as they would have been excluded
54
            $current = $element;
55
            while ($refNode = $current->previousSibling) {
56
                if (
57
                    (($refNode->nodeType === XML_COMMENT_NODE) && $withComments)
58
                    || $refNode->nodeType === XML_PI_NODE
59
                ) {
60
                    break;
61
                }
62
                $current = $refNode;
63
            }
64
            if ($refNode === null) {
65
                $element = $element->ownerDocument;
66
            }
67
        }
68
69
        return $element->C14N($exclusive, $withComments, $xpaths, $prefixes);
70
    }
71
72
73
    /**
74
     * Process all transforms specified by a given Reference element.
75
     *
76
     * @param \SimpleSAML\XMLSecurity\XML\ds\Transforms $transforms The transforms to apply.
77
     * @param \DOMElement $data The data referenced.
78
     * @param bool $includeCommentNodes Whether to allow canonicalization with comments or not.
79
     *
80
     * @return string The canonicalized data after applying all transforms specified by $ref.
81
     *
82
     * @see http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
83
     */
84
    public static function processTransforms(
85
        Transforms $transforms,
86
        DOMElement $data,
87
    ): string {
88
        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
89
        $arXPath = null;
90
        $prefixList = null;
91
        foreach ($transforms->getTransform() as $transform) {
92
            $canonicalMethod = $transform->getAlgorithm();
93
            switch ($canonicalMethod) {
94
                case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
95
                case C::C14N_EXCLUSIVE_WITH_COMMENTS:
96
                    $inclusiveNamespaces = $transform->getInclusiveNamespaces();
97
                    if ($inclusiveNamespaces !== null) {
98
                        $prefixes = $inclusiveNamespaces->getPrefixes();
99
                        if (count($prefixes) > 0) {
100
                            $prefixList = $prefixes;
101
                        }
102
                    }
103
                    break;
104
                case C::XPATH_URI:
105
                    $xpath = $transform->getXPath();
106
                    if ($xpath !== null) {
107
                        $arXPath = [];
108
                        $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $xpath->getExpression() . ']';
109
                        $arXpath['namespaces'] = $xpath->getNamespaces();
110
                        // TODO: review if $nsnode->localName is equivalent to the keys in getNamespaces()
111
//                        $nslist = $xp->query('./namespace::*', $node);
112
//                        foreach ($nslist as $nsnode) {
113
//                            if ($nsnode->localName != "xml") {
114
//                                $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
115
//                            }
116
//                        }
117
                    }
118
                    break;
119
            }
120
        }
121
122
        return self::canonicalizeData($data, $canonicalMethod, $arXPath, $prefixList);
123
    }
124
}
125