Passed
Pull Request — master (#285)
by Tim
02:20
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
        return $entity;
226
    }
227
228
229
    /**
230
     * Collect the value of the entityID property.
231
     *
232
     * @return string
233
     * @throws \SimpleSAML\Assert\AssertionFailedException
234
     */
235
    public function getEntityID(): string
236
    {
237
        Assert::notEmpty($this->entityID);
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::notEmpty($entityId, 'The entityID attribute cannot be empty.');
250
        Assert::maxLength($entityId, C::ENTITYID_MAX_LENGTH, 'The entityID attribute cannot be longer than 1024 characters.');
251
        $this->entityID = $entityId;
252
    }
253
254
255
    /**
256
     * Collect the value of the RoleDescriptor property.
257
     *
258
     * @return \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor[]
259
     */
260
    public function getRoleDescriptors(): array
261
    {
262
        return $this->RoleDescriptor;
263
    }
264
265
266
    /**
267
     * Set the value of the RoleDescriptor property.
268
     *
269
     * @param \SimpleSAML\SAML2\XML\md\AbstractRoleDescriptor[] $roleDescriptors
270
     * @throws \SimpleSAML\Assert\AssertionFailedException
271
     */
272
    protected function setRoleDescriptors(array $roleDescriptors): void
273
    {
274
        Assert::allIsInstanceOf(
275
            $roleDescriptors,
276
            AbstractRoleDescriptor::class,
277
            'All role descriptors must extend AbstractRoleDescriptor.'
278
        );
279
        $this->RoleDescriptor = $roleDescriptors;
280
    }
281
282
283
    /**
284
     * Collect the value of the AffiliationDescriptor property.
285
     *
286
     * @return \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null
287
     */
288
    public function getAffiliationDescriptor(): ?AffiliationDescriptor
289
    {
290
        return $this->AffiliationDescriptor;
291
    }
292
293
294
    /**
295
     * Set the value of the AffliationDescriptor property.
296
     *
297
     * @param \SimpleSAML\SAML2\XML\md\AffiliationDescriptor|null $affiliationDescriptor
298
     */
299
    protected function setAffiliationDescriptor(?AffiliationDescriptor $affiliationDescriptor = null): void
300
    {
301
        $this->AffiliationDescriptor = $affiliationDescriptor;
302
    }
303
304
305
    /**
306
     * Collect the value of the Organization property.
307
     *
308
     * @return \SimpleSAML\SAML2\XML\md\Organization|null
309
     */
310
    public function getOrganization(): ?Organization
311
    {
312
        return $this->Organization;
313
    }
314
315
316
    /**
317
     * Set the value of the Organization property.
318
     *
319
     * @param \SimpleSAML\SAML2\XML\md\Organization|null $organization
320
     */
321
    protected function setOrganization(?Organization $organization = null): void
322
    {
323
        $this->Organization = $organization;
324
    }
325
326
327
    /**
328
     * Collect the value of the ContactPerson property.
329
     *
330
     * @return \SimpleSAML\SAML2\XML\md\ContactPerson[]
331
     */
332
    public function getContactPersons(): array
333
    {
334
        return $this->ContactPerson;
335
    }
336
337
338
    /**
339
     * Set the value of the ContactPerson property.
340
     *
341
     * @param array $contactPerson
342
     * @throws \SimpleSAML\Assert\AssertionFailedException
343
     */
344
    protected function setContactPersons(array $contactPerson): void
345
    {
346
        Assert::allIsInstanceOf(
347
            $contactPerson,
348
            ContactPerson::class,
349
            'All md:ContactPerson elements must be an instance of ContactPerson.'
350
        );
351
        $this->ContactPerson = $contactPerson;
352
    }
353
354
355
    /**
356
     * Collect the value of the AdditionalMetadataLocation property.
357
     *
358
     * @return \SimpleSAML\SAML2\XML\md\AdditionalMetadataLocation[]
359
     */
360
    public function getAdditionalMetadataLocations(): array
361
    {
362
        return $this->AdditionalMetadataLocation;
363
    }
364
365
366
    /**
367
     * Set the value of the AdditionalMetadataLocation property.
368
     *
369
     * @param array $additionalMetadataLocation
370
     * @throws \SimpleSAML\Assert\AssertionFailedException
371
     */
372
    protected function setAdditionalMetadataLocations(array $additionalMetadataLocation): void
373
    {
374
        Assert::allIsInstanceOf(
375
            $additionalMetadataLocation,
376
            AdditionalMetadataLocation::class,
377
            'All md:AdditionalMetadataLocation elements must be an instance of AdditionalMetadataLocation'
378
        );
379
        $this->AdditionalMetadataLocation = $additionalMetadataLocation;
380
    }
381
382
383
    /**
384
     * Create this EntityDescriptor.
385
     *
386
     * @param \DOMElement|null $parent The EntitiesDescriptor we should append this EntityDescriptor to.
387
     * @return \DOMElement
388
     * @throws \Exception
389
     */
390
    public function toXML(DOMElement $parent = null): DOMElement
391
    {
392
        $e = parent::toXML($parent);
393
        $e->setAttribute('entityID', $this->entityID);
394
395
        foreach ($this->getAttributesNS() as $attr) {
396
            $e->setAttributeNS($attr['namespaceURI'], $attr['qualifiedName'], $attr['value']);
397
        }
398
399
        foreach ($this->RoleDescriptor as $n) {
400
            $n->toXML($e);
401
        }
402
403
        if ($this->AffiliationDescriptor !== null) {
404
            $this->AffiliationDescriptor->toXML($e);
405
        }
406
407
        if ($this->Organization !== null) {
408
            $this->Organization->toXML($e);
409
        }
410
411
        foreach ($this->ContactPerson as $cp) {
412
            $cp->toXML($e);
413
        }
414
415
        foreach ($this->AdditionalMetadataLocation as $n) {
416
            $n->toXML($e);
417
        }
418
419
        return $this->signElement($e);
420
    }
421
}
422