EntityDescriptor::toUnsignedXML()   A
last analyzed

Complexity

Conditions 5
Paths 16

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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