Completed
Branch rewrite-api-md (eb38e5)
by Tim
03:57
created

EntityDescriptor::fromXML()   D

Complexity

Conditions 21
Paths 41

Size

Total Lines 80
Code Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 21
eloc 64
nc 41
nop 1
dl 0
loc 80
rs 4.1666
c 1
b 0
f 0

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 SAML2\XML\md;
6
7
use DOMElement;
8
use SAML2\Constants;
9
use SAML2\DOMDocumentFactory;
10
use SAML2\Utils;
11
use Webmozart\Assert\Assert;
12
13
/**
14
 * Class representing SAML 2 EntityDescriptor element.
15
 *
16
 * @package simplesamlphp/saml2
17
 */
18
final class EntityDescriptor extends AbstractMetadataDocument
19
{
20
    /**
21
     * The entityID this EntityDescriptor represents.
22
     *
23
     * @var string
24
     */
25
    protected $entityID;
26
27
    /**
28
     * Array with all roles for this entity.
29
     *
30
     * Array of \SAML2\XML\md\RoleDescriptor objects (and subclasses of RoleDescriptor).
31
     *
32
     * @var \SAML2\XML\md\AbstractRoleDescriptor[]
33
     */
34
    protected $RoleDescriptor = [];
35
36
    /**
37
     * AffiliationDescriptor of this entity.
38
     *
39
     * @var \SAML2\XML\md\AffiliationDescriptor|null
40
     */
41
    protected $AffiliationDescriptor = null;
42
43
    /**
44
     * Organization of this entity.
45
     *
46
     * @var \SAML2\XML\md\Organization|null
47
     */
48
    protected $Organization = null;
49
50
    /**
51
     * ContactPerson elements for this entity.
52
     *
53
     * @var \SAML2\XML\md\ContactPerson[]
54
     */
55
    protected $ContactPerson = [];
56
57
    /**
58
     * AdditionalMetadataLocation elements for this entity.
59
     *
60
     * @var \SAML2\XML\md\AdditionalMetadataLocation[]
61
     */
62
    protected $AdditionalMetadataLocation = [];
63
64
65
    /**
66
     * Initialize an EntitiyDescriptor.
67
     *
68
     * @param string $entityID The entityID of the entity described by this descriptor.
69
     * @param string|null $id The ID for this document. Defaults to null.
70
     * @param int|null $validUntil Unix time of validify for this document. Defaults to null.
71
     * @param string|null $cacheDuration Maximum time this document can be cached. Defaults to null.
72
     * @param \SAML2\XML\md\Extensions|null $extensions An array of extensions.
73
     * @param \SAML2\XML\md\AbstractRoleDescriptor[]|null $roleDescriptors An array of role descriptors.
74
     * @param \SAML2\XML\md\AffiliationDescriptor|null $affiliationDescriptor An affiliation descriptor to use instead
75
     * of role descriptors.
76
     * @param \SAML2\XML\md\Organization|null $organization The organization responsible for the SAML entity.
77
     * @param \SAML2\XML\md\ContactPerson[]|null $contacts A list of contact persons for this SAML entity.
78
     * @param \SAML2\XML\md\AdditionalMetadataLocation[]|null $additionalMdLocations A list of additional metadata
79
     * locations.
80
     *
81
     * @throws \Exception
82
     */
83
    public function __construct(
84
        string $entityID,
85
        ?string $id = null,
86
        ?int $validUntil = null,
87
        ?string $cacheDuration = null,
88
        Extensions $extensions = null,
89
        array $roleDescriptors = [],
90
        ?AffiliationDescriptor $affiliationDescriptor = null,
91
        ?Organization $organization = null,
92
        array $contacts = [],
93
        array $additionalMdLocations = []
94
    ) {
95
        if (empty($roleDescriptors) && $affiliationDescriptor === null) {
96
            throw new \Exception(
97
                'Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.'
98
            );
99
        }
100
101
        Assert::false(
102
            is_null($validUntil) && is_null($cacheDuration),
103
            'You need either validUntil or cacheDuration set'
104
        );
105
106
        parent::__construct($id, $validUntil, $cacheDuration, $extensions);
107
108
        $this->entityID = $entityID;
109
        $this->setRoleDescriptor($roleDescriptors);
110
        $this->AffiliationDescriptor = $affiliationDescriptor;
111
        $this->Organization = $organization;
112
        $this->setContactPerson($contacts);
113
        $this->setAdditionalMetadataLocation($additionalMdLocations);
114
    }
115
116
117
    /**
118
     * Convert an existing XML into an EntityDescriptor object
119
     *
120
     * @param \DOMElement $xml An existing EntityDescriptor XML document.
121
     *
122
     * @return \SAML2\XML\md\EntityDescriptor An object representing the given document.
123
     * @throws \Exception If an error occurs while processing the XML document.
124
     */
125
    public static function fromXML(DOMElement $xml): object
126
    {
127
        $validUntil = self::getAttribute($xml, 'validUntil', null);
128
        $extensions = Extensions::getChildrenOfClass($xml);
129
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.');
130
131
        $roleDescriptors = [];
132
        $affiliationDescriptor = null;
133
        $organization = null;
134
        $contactPersons = [];
135
        $additionalMetadataLocation = [];
136
        foreach ($xml->childNodes as $node) {
137
            if (!($node instanceof DOMElement)) {
138
                continue;
139
            }
140
141
            if ($node->namespaceURI !== Constants::NS_MD) {
142
                continue;
143
            }
144
145
            switch ($node->localName) {
146
                case 'IDPSSODescriptor':
147
                    $roleDescriptors[] = IDPSSODescriptor::fromXML($node);
148
                    break;
149
                case 'SPSSODescriptor':
150
                    $roleDescriptors[] = new SPSSODescriptor($node);
151
                    break;
152
                case 'AuthnAuthorityDescriptor':
153
                    $roleDescriptors[] = AuthnAuthorityDescriptor::fromXML($node);
154
                    break;
155
                case 'AttributeAuthorityDescriptor':
156
                    $roleDescriptors[] = AttributeAuthorityDescriptor::fromXML($node);
157
                    break;
158
                case 'PDPDescriptor':
159
                    $roleDescriptors[] = new PDPDescriptor($node);
0 ignored issues
show
Bug introduced by
The call to SAML2\XML\md\PDPDescriptor::__construct() has too few arguments starting with protocolSupportEnumeration. ( Ignorable by Annotation )

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

159
                    $roleDescriptors[] = /** @scrutinizer ignore-call */ new PDPDescriptor($node);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
$node of type DOMElement is incompatible with the type array expected by parameter $authServiceEndpoints of SAML2\XML\md\PDPDescriptor::__construct(). ( Ignorable by Annotation )

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

159
                    $roleDescriptors[] = new PDPDescriptor(/** @scrutinizer ignore-type */ $node);
Loading history...
160
                    break;
161
                case 'AffiliationDescriptor':
162
                    if ($affiliationDescriptor !== null) {
163
                        throw new \Exception('More than one AffiliationDescriptor in the entity.');
164
                    }
165
                    $affiliationDescriptor = AffiliationDescriptor::fromXML($node);
166
                    break;
167
                case 'Organization':
168
                    if ($organization !== null) {
169
                        throw new \Exception('More than one Organization in the entity.');
170
                    }
171
                    $organization = Organization::fromXML($node);
172
                    break;
173
                case 'ContactPerson':
174
                    $contactPersons[] = ContactPerson::fromXML($node);
175
                    break;
176
                case 'AdditionalMetadataLocation':
177
                    $additionalMetadataLocation[] = AdditionalMetadataLocation::fromXML($node);
178
                    break;
179
                default:
180
                    $roleDescriptors[] = UnknownRoleDescriptor::fromXML($node);
181
            }
182
        }
183
184
        if (empty($roleDescriptors) && is_null($affiliationDescriptor)) {
185
            throw new \Exception(
186
                'Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.'
187
            );
188
        } elseif (!empty($roleDescriptors) && !is_null($affiliationDescriptor)) {
189
            throw new \Exception(
190
                'AffiliationDescriptor cannot be combined with other RoleDescriptor elements in EntityDescriptor.'
191
            );
192
        }
193
194
        return new self(
195
            self::getAttribute($xml, 'entityID'),
196
            self::getAttribute($xml, 'ID', null),
197
            $validUntil !== null ? Utils::xsDateTimeToTimestamp($validUntil) : null,
198
            self::getAttribute($xml, 'cacheDuration', null),
199
            !empty($extensions) ? $extensions[0] : null,
200
            $roleDescriptors,
201
            $affiliationDescriptor,
202
            $organization,
203
            $contactPersons,
204
            $additionalMetadataLocation
205
        );
206
    }
207
208
209
    /**
210
     * Collect the value of the entityID property.
211
     *
212
     * @return string
213
     *
214
     * @throws \InvalidArgumentException if assertions are false
215
     */
216
    public function getEntityID(): string
217
    {
218
        Assert::notEmpty($this->entityID);
219
220
        return $this->entityID;
221
    }
222
223
224
    /**
225
     * Set the value of the entityID-property
226
     * @param string $entityId
227
     * @return void
228
     */
229
    protected function setEntityID(string $entityId): void
230
    {
231
        $this->entityID = $entityId;
232
    }
233
234
235
    /**
236
     * Collect the value of the RoleDescriptor property.
237
     *
238
     * @return \SAML2\XML\md\AbstractRoleDescriptor[]
239
     */
240
    public function getRoleDescriptor(): array
241
    {
242
        return $this->RoleDescriptor;
243
    }
244
245
246
    /**
247
     * Set the value of the RoleDescriptor property.
248
     *
249
     * @param \SAML2\XML\md\AbstractRoleDescriptor[] $roleDescriptor
250
     *
251
     * @return void
252
     */
253
    protected function setRoleDescriptor(array $roleDescriptor): void
254
    {
255
        $this->RoleDescriptor = $roleDescriptor;
256
    }
257
258
259
    /**
260
     * Collect the value of the AffiliationDescriptor property.
261
     *
262
     * @return \SAML2\XML\md\AffiliationDescriptor|null
263
     */
264
    public function getAffiliationDescriptor(): ?AffiliationDescriptor
265
    {
266
        return $this->AffiliationDescriptor;
267
    }
268
269
270
    /**
271
     * Set the value of the AffliationDescriptor property.
272
     *
273
     * @param \SAML2\XML\md\AffiliationDescriptor|null $affiliationDescriptor
274
     * @return void
275
     */
276
    protected function setAffiliationDescriptor(AffiliationDescriptor $affiliationDescriptor = null): void
277
    {
278
        $this->AffiliationDescriptor = $affiliationDescriptor;
279
    }
280
281
282
    /**
283
     * Collect the value of the Organization property.
284
     *
285
     * @return \SAML2\XML\md\Organization|null
286
     */
287
    public function getOrganization(): ?Organization
288
    {
289
        return $this->Organization;
290
    }
291
292
293
    /**
294
     * Set the value of the Organization property.
295
     *
296
     * @param \SAML2\XML\md\Organization|null $organization
297
     * @return void
298
     */
299
    protected function setOrganization(Organization $organization = null): void
300
    {
301
        $this->Organization = $organization;
302
    }
303
304
305
    /**
306
     * Collect the value of the ContactPerson property.
307
     *
308
     * @return \SAML2\XML\md\ContactPerson[]
309
     */
310
    public function getContactPerson(): array
311
    {
312
        return $this->ContactPerson;
313
    }
314
315
316
    /**
317
     * Set the value of the ContactPerson property.
318
     *
319
     * @param array $contactPerson
320
     * @return void
321
     */
322
    protected function setContactPerson(array $contactPerson): void
323
    {
324
        $this->ContactPerson = $contactPerson;
325
    }
326
327
328
    /**
329
     * Collect the value of the AdditionalMetadataLocation property.
330
     *
331
     * @return \SAML2\XML\md\AdditionalMetadataLocation[]
332
     */
333
    public function getAdditionalMetadataLocation(): array
334
    {
335
        return $this->AdditionalMetadataLocation;
336
    }
337
338
339
    /**
340
     * Set the value of the AdditionalMetadataLocation property.
341
     *
342
     * @param array $additionalMetadataLocation
343
     * @return void
344
     */
345
    protected function setAdditionalMetadataLocation(array $additionalMetadataLocation): void
346
    {
347
        $this->AdditionalMetadataLocation = $additionalMetadataLocation;
348
    }
349
350
351
    /**
352
     * Create this EntityDescriptor.
353
     *
354
     * @param \DOMElement|null $parent The EntitiesDescriptor we should append this EntityDescriptor to.
355
     * @return \DOMElement
356
     *
357
     * @throws \InvalidArgumentException if assertions are false
358
     */
359
    public function toXML(DOMElement $parent = null): DOMElement
360
    {
361
        Assert::notEmpty($this->entityID, 'Cannot convert EntityDescriptor to XML without an EntityID set.');
362
363
        if ($parent === null) {
364
            $doc = DOMDocumentFactory::create();
365
            $e = $doc->createElementNS(Constants::NS_MD, 'md:EntityDescriptor');
366
            $doc->appendChild($e);
367
        } else {
368
            $e = $parent->ownerDocument->createElementNS(Constants::NS_MD, 'md:EntityDescriptor');
369
            $parent->appendChild($e);
370
        }
371
372
        $e->setAttribute('entityID', $this->entityID);
373
374
        if ($this->ID !== null) {
375
            $e->setAttribute('ID', $this->ID);
376
        }
377
378
        if ($this->validUntil !== null) {
379
            $e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
380
        }
381
382
        if ($this->cacheDuration !== null) {
383
            $e->setAttribute('cacheDuration', $this->cacheDuration);
384
        }
385
386
        if (!empty($this->Extensions)) {
387
            $this->Extensions->toXML($e);
388
        }
389
390
        foreach ($this->RoleDescriptor as $n) {
391
            $n->toXML($e);
392
        }
393
394
        if ($this->AffiliationDescriptor !== null) {
395
            $this->AffiliationDescriptor->toXML($e);
396
        }
397
398
        if ($this->Organization !== null) {
399
            $this->Organization->toXML($e);
400
        }
401
402
        foreach ($this->ContactPerson as $cp) {
403
            $cp->toXML($e);
404
        }
405
406
        foreach ($this->AdditionalMetadataLocation as $n) {
407
            $n->toXML($e);
408
        }
409
410
        /** @var \DOMElement $child */
411
        $child = $e->firstChild;
412
        $this->signElement($e, $child);
413
414
        return $e;
415
    }
416
}
417