Passed
Push — master ( d3e6a5...90893b )
by Tim
02:27
created

EntityDescriptor::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 27
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 1
nop 11
dl 0
loc 27
rs 9.9
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\Constants as C;
10
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
11
use SimpleSAML\XML\Exception\InvalidDOMElementException;
12
use SimpleSAML\XML\Exception\SchemaViolationException;
13
use SimpleSAML\XML\Exception\TooManyElementsException;
14
use SimpleSAML\XML\Utils as XMLUtils;
15
use SimpleSAML\XMLSecurity\XML\ds\Signature;
16
17
use function is_null;
18
19
/**
20
 * Class representing SAML 2 EntityDescriptor element.
21
 *
22
 * @package simplesamlphp/saml2
23
 */
24
final class EntityDescriptor extends AbstractMetadataDocument
25
{
26
    /**
27
     * The entityID this EntityDescriptor represents.
28
     *
29
     * @var string
30
     */
31
    protected string $entityID;
32
33
    /**
34
     * Array with all roles for this entity.
35
     *
36
     * Array of \SimpleSAML\SAML2\XML\md\RoleDescriptor objects (and subclasses of RoleDescriptor).
37
     *
38
     * @var \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor[]
39
     */
40
    protected array $RoleDescriptor = [];
41
42
    /**
43
     * AffiliationDescriptor of this entity.
44
     *
45
     * @var \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null
46
     */
47
    protected ?AffiliationDescriptor $AffiliationDescriptor = null;
48
49
    /**
50
     * Organization of this entity.
51
     *
52
     * @var \SimpleSAML\SAML2\XML\md\Organization|null
53
     */
54
    protected ?Organization $Organization = null;
55
56
    /**
57
     * ContactPerson elements for this entity.
58
     *
59
     * @var \SimpleSAML\SAML2\XML\md\ContactPerson[]
60
     */
61
    protected array $ContactPerson = [];
62
63
    /**
64
     * AdditionalMetadataLocation elements for this entity.
65
     *
66
     * @var \SimpleSAML\SAML2\XML\md\AdditionalMetadataLocation[]
67
     */
68
    protected array $AdditionalMetadataLocation = [];
69
70
71
    /**
72
     * Initialize an EntitiyDescriptor.
73
     *
74
     * @param string $entityID The entityID of the entity described by this descriptor.
75
     * @param string|null $id The ID for this document. Defaults to null.
76
     * @param int|null $validUntil Unix time of validify for this document. Defaults to null.
77
     * @param string|null $cacheDuration Maximum time this document can be cached. Defaults to null.
78
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null $extensions An array of extensions.
79
     * @param \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor[] $roleDescriptors An array of role descriptors.
80
     * @param \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null $affiliationDescriptor An affiliation descriptor to
81
     *   use instead of role descriptors.
82
     * @param \SimpleSAML\SAML2\XML\md\Organization|null $organization The organization responsible for the SAML entity.
83
     * @param \SimpleSAML\SAML2\XML\md\ContactPerson[] $contacts A list of contact persons for this SAML entity.
84
     * @param \SimpleSAML\SAML2\XML\md\AdditionalMetadataLocation[] $additionalMdLocations A list of
85
     *   additional metadata locations.
86
     * @param \DOMAttr[] $namespacedAttributes
87
     *
88
     * @throws \Exception
89
     */
90
    public function __construct(
91
        string $entityID,
92
        ?string $id = null,
93
        ?int $validUntil = null,
94
        ?string $cacheDuration = null,
95
        Extensions $extensions = null,
96
        array $roleDescriptors = [],
97
        ?AffiliationDescriptor $affiliationDescriptor = null,
98
        ?Organization $organization = null,
99
        array $contacts = [],
100
        array $additionalMdLocations = [],
101
        array $namespacedAttributes = []
102
    ) {
103
        Assert::false(
104
            (empty($roleDescriptors) && $affiliationDescriptor === null),
105
            'Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.',
106
            ProtocolViolationException::class,
107
        );
108
109
        parent::__construct($id, $validUntil, $cacheDuration, $extensions, $namespacedAttributes);
110
111
        $this->setEntityID($entityID);
112
        $this->setRoleDescriptors($roleDescriptors);
113
        $this->setAffiliationDescriptor($affiliationDescriptor);
114
        $this->setOrganization($organization);
115
        $this->setContactPersons($contacts);
116
        $this->setAdditionalMetadataLocations($additionalMdLocations);
117
    }
118
119
120
    /**
121
     * Convert an existing XML into an EntityDescriptor object
122
     *
123
     * @param \DOMElement $xml An existing EntityDescriptor XML document.
124
     * @return \SimpleSAML\SAML2\XML\md\EntityDescriptor An object representing the given document.
125
     *
126
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
127
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
128
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
129
     */
130
    public static function fromXML(DOMElement $xml): static
131
    {
132
        Assert::same($xml->localName, 'EntityDescriptor', InvalidDOMElementException::class);
133
        Assert::same($xml->namespaceURI, EntityDescriptor::NS, InvalidDOMElementException::class);
134
135
        $validUntil = self::getAttribute($xml, 'validUntil', null);
136
        $extensions = Extensions::getChildrenOfClass($xml);
137
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
138
139
        $signature = Signature::getChildrenOfClass($xml);
140
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
141
142
        $entityID = self::getAttribute($xml, 'entityID');
143
        $roleDescriptors = [];
144
        $affiliationDescriptor = null;
145
        $organization = null;
146
        $contactPersons = [];
147
        $additionalMetadataLocation = [];
148
        foreach ($xml->childNodes as $node) {
149
            if (
150
                !($node instanceof DOMElement)
151
                || ($node->namespaceURI !== C::NS_MD)
152
            ) {
153
                continue;
154
            }
155
156
            switch ($node->localName) {
157
                case 'Extensions':
158
                    continue 2;
159
                case 'IDPSSODescriptor':
160
                    $roleDescriptors[] = IDPSSODescriptor::fromXML($node);
161
                    break;
162
                case 'SPSSODescriptor':
163
                    $roleDescriptors[] = SPSSODescriptor::fromXML($node);
164
                    break;
165
                case 'AuthnAuthorityDescriptor':
166
                    $roleDescriptors[] = AuthnAuthorityDescriptor::fromXML($node);
167
                    break;
168
                case 'AttributeAuthorityDescriptor':
169
                    $roleDescriptors[] = AttributeAuthorityDescriptor::fromXML($node);
170
                    break;
171
                case 'PDPDescriptor':
172
                    $roleDescriptors[] = PDPDescriptor::fromXML($node);
173
                    break;
174
                case 'AffiliationDescriptor':
175
                    if ($affiliationDescriptor !== null) {
176
                        throw new TooManyElementsException('More than one AffiliationDescriptor in the entity.');
177
                    }
178
                    $affiliationDescriptor = AffiliationDescriptor::fromXML($node);
179
                    break;
180
                case 'Organization':
181
                    if ($organization !== null) {
182
                        throw new TooManyElementsException('More than one Organization in the entity.');
183
                    }
184
                    $organization = Organization::fromXML($node);
185
                    break;
186
                case 'ContactPerson':
187
                    $contactPersons[] = ContactPerson::fromXML($node);
188
                    break;
189
                case 'AdditionalMetadataLocation':
190
                    $additionalMetadataLocation[] = AdditionalMetadataLocation::fromXML($node);
191
                    break;
192
                default:
193
                    $roleDescriptors[] = UnknownRoleDescriptor::fromXML($node);
194
            }
195
        }
196
197
        Assert::false(
198
            empty($roleDescriptors) && is_null($affiliationDescriptor),
199
            'Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.',
200
            ProtocolViolationException::class,
201
        );
202
        Assert::false(
203
            !empty($roleDescriptors) && !is_null($affiliationDescriptor),
204
            'AffiliationDescriptor cannot be combined with other RoleDescriptor elements in EntityDescriptor.',
205
            ProtocolViolationException::class,
206
        );
207
208
        $entity = new static(
209
            $entityID,
210
            self::getAttribute($xml, 'ID', null),
211
            $validUntil !== null ? XMLUtils::xsDateTimeToTimestamp($validUntil) : null,
212
            self::getAttribute($xml, 'cacheDuration', null),
213
            !empty($extensions) ? $extensions[0] : null,
214
            $roleDescriptors,
215
            $affiliationDescriptor,
216
            $organization,
217
            $contactPersons,
218
            $additionalMetadataLocation,
219
            self::getAttributesNSFromXML($xml)
220
        );
221
222
        if (!empty($signature)) {
223
            $entity->setSignature($signature[0]);
224
            $entity->setXML($xml);
225
        }
226
227
        return $entity;
228
    }
229
230
231
    /**
232
     * Collect the value of the entityID property.
233
     *
234
     * @return string
235
     * @throws \SimpleSAML\Assert\AssertionFailedException
236
     */
237
    public function getEntityID(): string
238
    {
239
        return $this->entityID;
240
    }
241
242
243
    /**
244
     * Set the value of the entityID-property
245
     * @param string $entityId
246
     */
247
    protected function setEntityID(string $entityId): void
248
    {
249
        Assert::validURI($entityId, SchemaViolationException::class); // Covers the empty string
250
        Assert::maxLength(
251
            $entityId,
252
            C::ENTITYID_MAX_LENGTH,
253
            sprintf('The entityID attribute cannot be longer than %d characters.', C::ENTITYID_MAX_LENGTH),
254
            ProtocolViolationException::class
255
        );
256
        $this->entityID = $entityId;
257
    }
258
259
260
    /**
261
     * Collect the value of the RoleDescriptor property.
262
     *
263
     * @return \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor[]
264
     */
265
    public function getRoleDescriptors(): array
266
    {
267
        return $this->RoleDescriptor;
268
    }
269
270
271
    /**
272
     * Set the value of the RoleDescriptor property.
273
     *
274
     * @param \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor[] $roleDescriptors
275
     * @throws \SimpleSAML\Assert\AssertionFailedException
276
     */
277
    protected function setRoleDescriptors(array $roleDescriptors): void
278
    {
279
        Assert::allIsInstanceOf(
280
            $roleDescriptors,
281
            AbstractRoleDescriptor::class,
282
            'All role descriptors must extend AbstractRoleDescriptor.'
283
        );
284
        $this->RoleDescriptor = $roleDescriptors;
285
    }
286
287
288
    /**
289
     * Collect the value of the AffiliationDescriptor property.
290
     *
291
     * @return \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null
292
     */
293
    public function getAffiliationDescriptor(): ?AffiliationDescriptor
294
    {
295
        return $this->AffiliationDescriptor;
296
    }
297
298
299
    /**
300
     * Set the value of the AffliationDescriptor property.
301
     *
302
     * @param \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null $affiliationDescriptor
303
     */
304
    protected function setAffiliationDescriptor(?AffiliationDescriptor $affiliationDescriptor = null): void
305
    {
306
        $this->AffiliationDescriptor = $affiliationDescriptor;
307
    }
308
309
310
    /**
311
     * Collect the value of the Organization property.
312
     *
313
     * @return \SimpleSAML\SAML2\XML\md\Organization|null
314
     */
315
    public function getOrganization(): ?Organization
316
    {
317
        return $this->Organization;
318
    }
319
320
321
    /**
322
     * Set the value of the Organization property.
323
     *
324
     * @param \SimpleSAML\SAML2\XML\md\Organization|null $organization
325
     */
326
    protected function setOrganization(?Organization $organization = null): void
327
    {
328
        $this->Organization = $organization;
329
    }
330
331
332
    /**
333
     * Collect the value of the ContactPerson property.
334
     *
335
     * @return \SimpleSAML\SAML2\XML\md\ContactPerson[]
336
     */
337
    public function getContactPersons(): array
338
    {
339
        return $this->ContactPerson;
340
    }
341
342
343
    /**
344
     * Set the value of the ContactPerson property.
345
     *
346
     * @param array $contactPerson
347
     * @throws \SimpleSAML\Assert\AssertionFailedException
348
     */
349
    protected function setContactPersons(array $contactPerson): void
350
    {
351
        Assert::allIsInstanceOf(
352
            $contactPerson,
353
            ContactPerson::class,
354
            'All md:ContactPerson elements must be an instance of ContactPerson.'
355
        );
356
        $this->ContactPerson = $contactPerson;
357
    }
358
359
360
    /**
361
     * Collect the value of the AdditionalMetadataLocation property.
362
     *
363
     * @return \SimpleSAML\SAML2\XML\md\AdditionalMetadataLocation[]
364
     */
365
    public function getAdditionalMetadataLocations(): array
366
    {
367
        return $this->AdditionalMetadataLocation;
368
    }
369
370
371
    /**
372
     * Set the value of the AdditionalMetadataLocation property.
373
     *
374
     * @param array $additionalMetadataLocation
375
     * @throws \SimpleSAML\Assert\AssertionFailedException
376
     */
377
    protected function setAdditionalMetadataLocations(array $additionalMetadataLocation): void
378
    {
379
        Assert::allIsInstanceOf(
380
            $additionalMetadataLocation,
381
            AdditionalMetadataLocation::class,
382
            'All md:AdditionalMetadataLocation elements must be an instance of AdditionalMetadataLocation'
383
        );
384
        $this->AdditionalMetadataLocation = $additionalMetadataLocation;
385
    }
386
387
388
    /**
389
     * Convert this assertion to an unsigned XML document.
390
     * This method does not sign the resulting XML document.
391
     *
392
     * @return \DOMElement The root element of the DOM tree
393
     */
394
    public function toUnsignedXML(?DOMElement $parent = null): DOMElement
395
    {
396
        $e = parent::toUnsignedXML($parent);
397
        $e->setAttribute('entityID', $this->entityID);
398
399
        foreach ($this->getAttributesNS() as $attr) {
400
            $e->setAttributeNS($attr['namespaceURI'], $attr['qualifiedName'], $attr['value']);
401
        }
402
403
        foreach ($this->getRoleDescriptors() as $n) {
404
            $n->toXML($e);
405
        }
406
407
        $this->getAffiliationDescriptor()?->toXML($e);
408
        $this->getOrganization()?->toXML($e);
409
410
        foreach ($this->getContactPersons() as $cp) {
411
            $cp->toXML($e);
412
        }
413
414
        foreach ($this->getAdditionalMetadataLocations() as $n) {
415
            $n->toXML($e);
416
        }
417
418
        return $e;
419
    }
420
}
421