EntityDescriptor::fromXML()   D
last analyzed

Complexity

Conditions 21
Paths 28

Size

Total Lines 100
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 79
c 0
b 0
f 0
nc 28
nop 1
dl 0
loc 100
rs 4.1666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\md;
6
7
use DateTimeImmutable;
8
use DOMElement;
9
use SimpleSAML\Assert\Assert;
10
use SimpleSAML\SAML2\Assert\Assert as SAMLAssert;
11
use SimpleSAML\SAML2\Constants as C;
12
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\Exception\TooManyElementsException;
15
use SimpleSAML\XML\ExtendableAttributesTrait;
16
use SimpleSAML\XML\SchemaValidatableElementInterface;
17
use SimpleSAML\XML\SchemaValidatableElementTrait;
18
use SimpleSAML\XML\XsNamespace as NS;
19
use SimpleSAML\XMLSecurity\XML\ds\Signature;
20
21
use function is_null;
22
23
/**
24
 * Class representing SAML 2 EntityDescriptor element.
25
 *
26
 * @package simplesamlphp/saml2
27
 */
28
final class EntityDescriptor extends AbstractMetadataDocument implements SchemaValidatableElementInterface
29
{
30
    use ExtendableAttributesTrait;
31
    use SchemaValidatableElementTrait;
32
33
34
    /** The namespace-attribute for the xs:anyAttribute element */
35
    public const XS_ANY_ATTR_NAMESPACE = NS::OTHER;
36
37
38
    /**
39
     * Initialize an EntitiyDescriptor.
40
     *
41
     * @param string $entityId The entityID of the entity described by this descriptor.
42
     * @param string|null $id The ID for this document. Defaults to null.
43
     * @param \DateTimeImmutable|null $validUntil Unix time of validify for this document. Defaults to null.
44
     * @param string|null $cacheDuration Maximum time this document can be cached. Defaults to null.
45
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null $extensions An array of extensions.
46
     * @param \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptorType[] $roleDescriptor An array of role descriptors.
47
     * @param \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null $affiliationDescriptor An affiliation descriptor to
48
     *   use instead of role descriptors.
49
     * @param \SimpleSAML\SAML2\XML\md\Organization|null $organization The organization responsible for the SAML entity.
50
     * @param \SimpleSAML\SAML2\XML\md\ContactPerson[] $contactPerson A list of contact persons for this SAML entity.
51
     * @param \SimpleSAML\SAML2\XML\md\AdditionalMetadataLocation[] $additionalMetadataLocation A list of
52
     *   additional metadata locations.
53
     * @param list<\SimpleSAML\XML\Attribute> $namespacedAttribute
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\XML\md\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
54
     *
55
     * @throws \Exception
56
     */
57
    public function __construct(
58
        protected string $entityId,
59
        ?string $id = null,
60
        ?DateTimeImmutable $validUntil = null,
61
        ?string $cacheDuration = null,
62
        ?Extensions $extensions = null,
63
        protected array $roleDescriptor = [],
64
        protected ?AffiliationDescriptor $affiliationDescriptor = null,
65
        protected ?Organization $organization = null,
66
        protected array $contactPerson = [],
67
        protected array $additionalMetadataLocation = [],
68
        array $namespacedAttribute = [],
69
    ) {
70
        Assert::false(
71
            (empty($roleDescriptor) && $affiliationDescriptor === null),
72
            'Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.',
73
            ProtocolViolationException::class,
74
        );
75
        SAMLAssert::validEntityID($entityId);
76
        Assert::maxCount($roleDescriptor, C::UNBOUNDED_LIMIT);
77
        Assert::allIsInstanceOf(
78
            $roleDescriptor,
79
            AbstractRoleDescriptorType::class,
80
            'All role descriptors must extend AbstractRoleDescriptor.',
81
        );
82
        Assert::maxCount($contactPerson, C::UNBOUNDED_LIMIT);
83
        Assert::allIsInstanceOf(
84
            $contactPerson,
85
            ContactPerson::class,
86
            'All md:ContactPerson elements must be an instance of ContactPerson.',
87
        );
88
        Assert::maxCount($additionalMetadataLocation, C::UNBOUNDED_LIMIT);
89
        Assert::allIsInstanceOf(
90
            $additionalMetadataLocation,
91
            AdditionalMetadataLocation::class,
92
            'All md:AdditionalMetadataLocation elements must be an instance of AdditionalMetadataLocation',
93
        );
94
95
        parent::__construct($id, $validUntil, $cacheDuration, $extensions);
96
97
        $this->setAttributesNS($namespacedAttribute);
98
    }
99
100
101
    /**
102
     * Convert an existing XML into an EntityDescriptor object
103
     *
104
     * @param \DOMElement $xml An existing EntityDescriptor XML document.
105
     * @return static
106
     *
107
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
108
     *   if the qualified name of the supplied element is wrong
109
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
110
     *   if the supplied element is missing one of the mandatory attributes
111
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException
112
     *   if too many child-elements of a type are specified
113
     */
114
    public static function fromXML(DOMElement $xml): static
115
    {
116
        Assert::same($xml->localName, 'EntityDescriptor', InvalidDOMElementException::class);
117
        Assert::same($xml->namespaceURI, EntityDescriptor::NS, InvalidDOMElementException::class);
118
119
        $validUntil = self::getOptionalAttribute($xml, 'validUntil', null);
120
        SAMLAssert::nullOrValidDateTime($validUntil);
121
122
        $extensions = Extensions::getChildrenOfClass($xml);
123
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
124
125
        $signature = Signature::getChildrenOfClass($xml);
126
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
127
128
        $entityID = self::getAttribute($xml, 'entityID');
129
        $roleDescriptors = [];
130
        $affiliationDescriptor = null;
131
        $organization = null;
132
        $contactPersons = [];
133
        $additionalMetadataLocation = [];
134
        foreach ($xml->childNodes as $node) {
135
            if (
136
                !($node instanceof DOMElement)
137
                || ($node->namespaceURI !== C::NS_MD)
138
            ) {
139
                continue;
140
            }
141
142
            switch ($node->localName) {
143
                case 'Extensions':
144
                    continue 2;
145
                case 'IDPSSODescriptor':
146
                    $roleDescriptors[] = IDPSSODescriptor::fromXML($node);
147
                    break;
148
                case 'SPSSODescriptor':
149
                    $roleDescriptors[] = SPSSODescriptor::fromXML($node);
150
                    break;
151
                case 'AuthnAuthorityDescriptor':
152
                    $roleDescriptors[] = AuthnAuthorityDescriptor::fromXML($node);
153
                    break;
154
                case 'AttributeAuthorityDescriptor':
155
                    $roleDescriptors[] = AttributeAuthorityDescriptor::fromXML($node);
156
                    break;
157
                case 'PDPDescriptor':
158
                    $roleDescriptors[] = PDPDescriptor::fromXML($node);
159
                    break;
160
                case 'AffiliationDescriptor':
161
                    if ($affiliationDescriptor !== null) {
162
                        throw new TooManyElementsException('More than one AffiliationDescriptor in the entity.');
163
                    }
164
                    $affiliationDescriptor = AffiliationDescriptor::fromXML($node);
165
                    break;
166
                case 'Organization':
167
                    if ($organization !== null) {
168
                        throw new TooManyElementsException('More than one Organization in the entity.');
169
                    }
170
                    $organization = Organization::fromXML($node);
171
                    break;
172
                case 'ContactPerson':
173
                    $contactPersons[] = ContactPerson::fromXML($node);
174
                    break;
175
                case 'AdditionalMetadataLocation':
176
                    $additionalMetadataLocation[] = AdditionalMetadataLocation::fromXML($node);
177
                    break;
178
                default:
179
                    $roleDescriptors[] = UnknownRoleDescriptor::fromXML($node);
180
            }
181
        }
182
183
        Assert::false(
184
            empty($roleDescriptors) && is_null($affiliationDescriptor),
185
            'Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.',
186
            ProtocolViolationException::class,
187
        );
188
        Assert::false(
189
            !empty($roleDescriptors) && !is_null($affiliationDescriptor),
190
            'AffiliationDescriptor cannot be combined with other RoleDescriptor elements in EntityDescriptor.',
191
            ProtocolViolationException::class,
192
        );
193
194
        $entity = new static(
195
            $entityID,
196
            self::getOptionalAttribute($xml, 'ID', null),
197
            $validUntil !== null ? new DateTimeImmutable($validUntil) : null,
198
            self::getOptionalAttribute($xml, 'cacheDuration', null),
199
            !empty($extensions) ? $extensions[0] : null,
200
            $roleDescriptors,
201
            $affiliationDescriptor,
202
            $organization,
203
            $contactPersons,
204
            $additionalMetadataLocation,
205
            self::getAttributesNSFromXML($xml),
206
        );
207
208
        if (!empty($signature)) {
209
            $entity->setSignature($signature[0]);
210
            $entity->setXML($xml);
211
        }
212
213
        return $entity;
214
    }
215
216
217
    /**
218
     * Collect the value of the entityID property.
219
     *
220
     * @return string
221
     * @throws \SimpleSAML\Assert\AssertionFailedException
222
     */
223
    public function getEntityId(): string
224
    {
225
        return $this->entityId;
226
    }
227
228
229
    /**
230
     * Collect the value of the RoleDescriptor property.
231
     *
232
     * @return \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptorType[]
233
     */
234
    public function getRoleDescriptor(): array
235
    {
236
        return $this->roleDescriptor;
237
    }
238
239
240
    /**
241
     * Collect the value of the AffiliationDescriptor property.
242
     *
243
     * @return \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null
244
     */
245
    public function getAffiliationDescriptor(): ?AffiliationDescriptor
246
    {
247
        return $this->affiliationDescriptor;
248
    }
249
250
251
    /**
252
     * Collect the value of the Organization property.
253
     *
254
     * @return \SimpleSAML\SAML2\XML\md\Organization|null
255
     */
256
    public function getOrganization(): ?Organization
257
    {
258
        return $this->organization;
259
    }
260
261
262
    /**
263
     * Collect the value of the ContactPerson property.
264
     *
265
     * @return \SimpleSAML\SAML2\XML\md\ContactPerson[]
266
     */
267
    public function getContactPerson(): array
268
    {
269
        return $this->contactPerson;
270
    }
271
272
273
    /**
274
     * Collect the value of the AdditionalMetadataLocation property.
275
     *
276
     * @return \SimpleSAML\SAML2\XML\md\AdditionalMetadataLocation[]
277
     */
278
    public function getAdditionalMetadataLocation(): array
279
    {
280
        return $this->additionalMetadataLocation;
281
    }
282
283
284
    /**
285
     * Convert this assertion to an unsigned XML document.
286
     * This method does not sign the resulting XML document.
287
     *
288
     * @return \DOMElement The root element of the DOM tree
289
     */
290
    public function toUnsignedXML(?DOMElement $parent = null): DOMElement
291
    {
292
        $e = parent::toUnsignedXML($parent);
293
        $e->setAttribute('entityID', $this->getEntityId());
294
295
        foreach ($this->getAttributesNS() as $attr) {
296
            $attr->toXML($e);
297
        }
298
299
        foreach ($this->getRoleDescriptor() as $n) {
300
            $n->toXML($e);
301
        }
302
303
        $this->getAffiliationDescriptor()?->toXML($e);
304
        $this->getOrganization()?->toXML($e);
305
306
        foreach ($this->getContactPerson() as $cp) {
307
            $cp->toXML($e);
308
        }
309
310
        foreach ($this->getAdditionalMetadataLocation() as $n) {
311
            $n->toXML($e);
312
        }
313
314
        return $e;
315
    }
316
}
317