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