Passed
Push — master ( 7a371e...4a8d98 )
by Tim
02:17
created

EntityDescriptor::getContactPerson()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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