Passed
Pull Request — master (#306)
by Tim
02:37
created

AbstractRoleDescriptor::setKeyDescriptors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\md;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\SAML2\Compat\ContainerSingleton;
10
use SimpleSAML\SAML2\Constants as C;
11
use SimpleSAML\SAML2\Utils;
12
use SimpleSAML\SAML2\XML\ExtensionPointInterface;
13
use SimpleSAML\SAML2\XML\ExtensionPointTrait;
14
use SimpleSAML\XML\Chunk;
15
use SimpleSAML\XML\Exception\InvalidDOMElementException;
16
use SimpleSAML\XML\Exception\SchemaViolationException;
17
use SimpleSAML\XML\Exception\TooManyElementsException;
18
use SimpleSAML\XML\Utils as XMLUtils;
19
use SimpleSAML\XMLSecurity\Backend\EncryptionBackend;
20
use SimpleSAML\XMLSecurity\XML\EncryptableElementInterface;
21
use SimpleSAML\XMLSecurity\XML\EncryptableElementTrait;
22
23
use function array_pop;
24
use function count;
25
use function explode;
26
27
/**
28
 * SAML Metadata RoleDescriptor element.
29
 *
30
 * @package simplesamlphp/saml2
31
 */
32
abstract class AbstractRoleDescriptor extends AbstractRoleDescriptorType implements ExtensionPointInterface
33
{
34
    use ExtensionPointTrait;
35
36
    /** @var string */
37
    public const LOCALNAME = 'RoleDescriptor';
38
39
    /** @var string */
40
    protected string $type;
41
42
43
    /**
44
     * Initialize a saml:RoleDescriptor from scratch
45
     *
46
     * @param string $type
47
     * @param string[] $protocolSupportEnumeration A set of URI specifying the protocols supported.
48
     * @param string|null $ID The ID for this document. Defaults to null.
49
     * @param int|null $validUntil Unix time of validity for this document. Defaults to null.
50
     * @param string|null $cacheDuration Maximum time this document can be cached. Defaults to null.
51
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null $extensions An Extensions object. Defaults to null.
52
     * @param string|null $errorURL An URI where to redirect users for support. Defaults to null.
53
     * @param \SimpleSAML\SAML2\XML\md\KeyDescriptor[] $keyDescriptors
54
     *   An array of KeyDescriptor elements. Defaults to an empty array.
55
     * @param \SimpleSAML\SAML2\XML\md\Organization|null $organization
56
     *   The organization running this entity. Defaults to null.
57
     * @param \SimpleSAML\SAML2\XML\md\ContactPerson[] $contacts
58
     *   An array of contacts for this entity. Defaults to an empty array.
59
     * @param \DOMAttr[] $namespacedAttributes
60
     */
61
    protected function __construct(
62
        string $type,
63
        array $protocolSupportEnumeration,
64
        ?string $ID = null,
65
        ?int $validUntil = null,
66
        ?string $cacheDuration = null,
67
        ?Extensions $extensions = null,
68
        ?string $errorURL = null,
69
        array $keyDescriptors = [],
70
        ?Organization $organization = null,
71
        array $contacts = [],
72
        array $namespacedAttributes = []
73
    ) {
74
        parent::__construct(
75
            $protocolSupportEnumeration,
76
            $ID,
77
            $validUntil,
78
            $cacheDuration,
79
            $extensions,
80
            $errorURL,
81
            $keyDescriptors,
82
            $organization,
83
            $contacts,
84
            $namespacedAttributes
85
        );
86
87
        $this->type = $type;
88
    }
89
90
91
    /**
92
     * @inheritDoc
93
     */
94
    public function getXsiType(): string
95
    {
96
        return $this->type;
97
    }
98
99
100
    /**
101
     * Convert XML into an RoleDescriptor
102
     *
103
     * @param \DOMElement $xml The XML element we should load
104
     * @return \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor
105
     *
106
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
107
     */
108
    public static function fromXML(DOMElement $xml): static
109
    {
110
        Assert::same($xml->localName, 'RoleDescriptor', InvalidDOMElementException::class);
111
        Assert::same($xml->namespaceURI, C::NS_MD, InvalidDOMElementException::class);
112
        Assert::true(
113
            $xml->hasAttributeNS(C::NS_XSI, 'type'),
114
            'Missing required xsi:type in <saml:RoleDescriptor> element.',
115
            SchemaViolationException::class
116
        );
117
118
        $type = $xml->getAttributeNS(C::NS_XSI, 'type');
119
        Assert::validQName($type, SchemaViolationException::class);
120
121
        // first, try to resolve the type to a full namespaced version
122
        $qname = explode(':', $type, 2);
123
        if (count($qname) === 2) {
124
            list($prefix, $element) = $qname;
125
        } else {
126
            $prefix = null;
127
            list($element) = $qname;
128
        }
129
        $ns = $xml->lookupNamespaceUri($prefix);
130
        $type = ($ns === null ) ? $element : implode(':', [$ns, $element]);
131
132
        // now check if we have a handler registered for it
133
        $handler = Utils::getContainer()->getExtensionHandler($type);
134
        if ($handler === null) {
135
            // we don't have a handler, proceed with unknown identifier
136
            $protocols = self::getAttribute($xml, 'protocolSupportEnumeration');
137
138
            $validUntil = self::getAttribute($xml, 'validUntil', null);
139
            $orgs = Organization::getChildrenOfClass($xml);
140
            Assert::maxCount($orgs, 1, 'More than one Organization found in this descriptor', TooManyElementsException::class);
141
142
            $extensions = Extensions::getChildrenOfClass($xml);
143
            Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
144
145
            return new UnknownRoleDescriptor(
146
                new Chunk($xml),
147
                $type,
148
                preg_split('/[\s]+/', trim($protocols)),
149
                self::getAttribute($xml, 'ID', null),
150
                $validUntil !== null ? XMLUtils::xsDateTimeToTimestamp($validUntil) : null,
151
                self::getAttribute($xml, 'cacheDuration', null),
152
                array_pop($extensions),
153
                self::getAttribute($xml, 'errorURL', null),
154
                KeyDescriptor::getChildrenOfClass($xml),
155
                array_pop($orgs),
156
                ContactPerson::getChildrenOfClass($xml),
157
            );
158
        }
159
160
        Assert::subclassOf(
161
            $handler,
162
            AbstractRoleDescriptor::class,
163
            'Elements implementing RoleDescriptor must extend \SimpleSAML\SAML2\XML\saml\AbstractRoleDescriptor.',
164
        );
165
166
        return $handler::fromXML($xml);
167
    }
168
169
170
    /**
171
     * Convert this RoleDescriptor to XML.
172
     *
173
     * @param \DOMElement|null $parent The element we are converting to XML.
174
     * @return \DOMElement The XML element after adding the data corresponding to this RoleDescriptor.
175
     */
176
    public function toUnsignedXML(?DOMElement $parent = null): DOMElement
177
    {
178
        $e = parent::toUnsignedXML($parent);
179
180
        $xsiType = $e->ownerDocument->createAttributeNS(C::NS_XSI, 'xsi:type');
0 ignored issues
show
Bug introduced by
The method createAttributeNS() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

180
        /** @scrutinizer ignore-call */ 
181
        $xsiType = $e->ownerDocument->createAttributeNS(C::NS_XSI, 'xsi:type');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
181
        $xsiType->value = $this->getXsiType();
182
        $e->setAttributeNodeNS($xsiType);
183
184
        $e->setAttribute('xmlns:' . static::getXsiTypePrefix(), static::getXsiTypeNamespaceURI());
185
186
        return $e;
187
    }
188
}
189