IDPSSODescriptor::toUnsignedXML()   B
last analyzed

Complexity

Conditions 8
Paths 64

Size

Total Lines 29
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 14
nc 64
nop 1
dl 0
loc 29
rs 8.4444
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\XML\saml\Attribute;
12
use SimpleSAML\XML\Constants as C;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\Exception\TooManyElementsException;
15
use SimpleSAML\XML\SchemaValidatableElementInterface;
16
use SimpleSAML\XML\SchemaValidatableElementTrait;
17
use SimpleSAML\XMLSecurity\XML\ds\Signature;
18
19
use function preg_split;
20
21
/**
22
 * Class representing SAML 2 IDPSSODescriptor.
23
 *
24
 * @package simplesamlphp/saml2
25
 */
26
final class IDPSSODescriptor extends AbstractSSODescriptor implements SchemaValidatableElementInterface
27
{
28
    use SchemaValidatableElementTrait;
29
30
    /**
31
     * IDPSSODescriptor constructor.
32
     *
33
     * @param \SimpleSAML\SAML2\XML\md\SingleSignOnService[] $singleSignOnService
34
     * @param string[] $protocolSupportEnumeration
35
     * @param bool|null $wantAuthnRequestsSigned
36
     * @param \SimpleSAML\SAML2\XML\md\NameIDMappingService[] $nameIDMappingService
37
     * @param \SimpleSAML\SAML2\XML\md\AssertionIDRequestService[] $assertionIDRequestService
38
     * @param \SimpleSAML\SAML2\XML\md\AttributeProfile[] $attributeProfile
39
     * @param \SimpleSAML\SAML2\XML\saml\Attribute[] $attribute
40
     * @param string|null $ID
41
     * @param \DateTimeImmutable|null $validUntil
42
     * @param string|null $cacheDuration
43
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null $extensions
44
     * @param string|null $errorURL
45
     * @param \SimpleSAML\SAML2\XML\md\KeyDescriptor[] $keyDescriptor
46
     * @param \SimpleSAML\SAML2\XML\md\Organization|null $organization
47
     * @param \SimpleSAML\SAML2\XML\md\ContactPerson[] $contact
48
     * @param \SimpleSAML\SAML2\XML\md\ArtifactResolutionService[] $artifactResolutionService
49
     * @param \SimpleSAML\SAML2\XML\md\SingleLogoutService[] $singleLogoutService
50
     * @param \SimpleSAML\SAML2\XML\md\ManageNameIDService[] $manageNameIDService
51
     * @param \SimpleSAML\SAML2\XML\md\NameIDFormat[] $nameIDFormat
52
     */
53
    public function __construct(
54
        protected array $singleSignOnService,
55
        array $protocolSupportEnumeration,
56
        protected ?bool $wantAuthnRequestsSigned = null,
57
        protected array $nameIDMappingService = [],
58
        protected array $assertionIDRequestService = [],
59
        protected array $attributeProfile = [],
60
        protected array $attribute = [],
61
        ?string $ID = null,
62
        ?DateTimeImmutable $validUntil = null,
63
        ?string $cacheDuration = null,
64
        ?Extensions $extensions = null,
65
        ?string $errorURL = null,
66
        array $keyDescriptor = [],
67
        ?Organization $organization = null,
68
        array $contact = [],
69
        array $artifactResolutionService = [],
70
        array $singleLogoutService = [],
71
        array $manageNameIDService = [],
72
        array $nameIDFormat = [],
73
    ) {
74
        Assert::maxCount($singleSignOnService, C::UNBOUNDED_LIMIT);
75
        Assert::minCount($singleSignOnService, 1, 'At least one SingleSignOnService must be specified.');
76
        Assert::allIsInstanceOf(
77
            $singleSignOnService,
78
            SingleSignOnService::class,
79
            'All md:SingleSignOnService endpoints must be an instance of SingleSignOnService.',
80
        );
81
        Assert::maxCount($nameIDMappingService, C::UNBOUNDED_LIMIT);
82
        Assert::allIsInstanceOf(
83
            $nameIDMappingService,
84
            NameIDMappingService::class,
85
            'All md:NameIDMappingService endpoints must be an instance of NameIDMappingService.',
86
        );
87
        Assert::maxCount($assertionIDRequestService, C::UNBOUNDED_LIMIT);
88
        Assert::allIsInstanceOf(
89
            $assertionIDRequestService,
90
            AssertionIDRequestService::class,
91
            'All md:AssertionIDRequestService endpoints must be an instance of AssertionIDRequestService.',
92
        );
93
        Assert::maxCount($attributeProfile, C::UNBOUNDED_LIMIT);
94
        Assert::allIsInstanceOf($attributeProfile, AttributeProfile::class);
95
        Assert::maxCount($attribute, C::UNBOUNDED_LIMIT);
96
        Assert::allIsInstanceOf(
97
            $attribute,
98
            Attribute::class,
99
            'All md:Attribute elements must be an instance of Attribute.',
100
        );
101
102
        parent::__construct(
103
            $protocolSupportEnumeration,
104
            $ID,
105
            $validUntil,
106
            $cacheDuration,
107
            $extensions,
108
            $errorURL,
109
            $keyDescriptor,
110
            $organization,
111
            $contact,
112
            $artifactResolutionService,
113
            $singleLogoutService,
114
            $manageNameIDService,
115
            $nameIDFormat,
116
        );
117
    }
118
119
120
    /**
121
     * Collect the value of the WantAuthnRequestsSigned-property
122
     *
123
     * @return bool|null
124
     */
125
    public function wantAuthnRequestsSigned(): ?bool
126
    {
127
        return $this->wantAuthnRequestsSigned;
128
    }
129
130
131
    /**
132
     * Get the SingleSignOnService endpoints
133
     *
134
     * @return \SimpleSAML\SAML2\XML\md\SingleSignOnService[]
135
     */
136
    public function getSingleSignOnService(): array
137
    {
138
        return $this->singleSignOnService;
139
    }
140
141
142
    /**
143
     * Get the NameIDMappingService endpoints
144
     *
145
     * @return \SimpleSAML\SAML2\XML\md\NameIDMappingService[]
146
     */
147
    public function getNameIDMappingService(): array
148
    {
149
        return $this->nameIDMappingService;
150
    }
151
152
153
    /**
154
     * Collect the AssertionIDRequestService endpoints
155
     *
156
     * @return \SimpleSAML\SAML2\XML\md\AssertionIDRequestService[]
157
     */
158
    public function getAssertionIDRequestService(): array
159
    {
160
        return $this->assertionIDRequestService;
161
    }
162
163
164
    /**
165
     * Get the attribute profiles supported
166
     *
167
     * @return \SimpleSAML\SAML2\XML\md\AttributeProfile[]
168
     */
169
    public function getAttributeProfile(): array
170
    {
171
        return $this->attributeProfile;
172
    }
173
174
175
    /**
176
     * Get the attributes supported by this IdP
177
     *
178
     * @return \SimpleSAML\SAML2\XML\saml\Attribute[]
179
     */
180
    public function getSupportedAttribute(): array
181
    {
182
        return $this->attribute;
183
    }
184
185
186
    /**
187
     * Initialize an IDPSSODescriptor.
188
     *
189
     * @param \DOMElement $xml The XML element we should load.
190
     * @return static
191
     *
192
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
193
     *   if the qualified name of the supplied element is wrong
194
     * @throws \SimpleSAML\XML\Exception\MissingElementException
195
     *   if one of the mandatory child-elements is missing
196
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException
197
     *   if too many child-elements of a type are specified
198
     */
199
    public static function fromXML(DOMElement $xml): static
200
    {
201
        Assert::same($xml->localName, 'IDPSSODescriptor', InvalidDOMElementException::class);
202
        Assert::same($xml->namespaceURI, IDPSSODescriptor::NS, InvalidDOMElementException::class);
203
204
        $protocols = self::getAttribute($xml, 'protocolSupportEnumeration');
205
        $validUntil = self::getOptionalAttribute($xml, 'validUntil', null);
206
        SAMLAssert::nullOrValidDateTime($validUntil);
207
208
        $orgs = Organization::getChildrenOfClass($xml);
209
        Assert::maxCount(
210
            $orgs,
211
            1,
212
            'More than one Organization found in this descriptor',
213
            TooManyElementsException::class,
214
        );
215
216
        $extensions = Extensions::getChildrenOfClass($xml);
217
        Assert::maxCount(
218
            $extensions,
219
            1,
220
            'Only one md:Extensions element is allowed.',
221
            TooManyElementsException::class,
222
        );
223
224
        $signature = Signature::getChildrenOfClass($xml);
225
        Assert::maxCount(
226
            $signature,
227
            1,
228
            'Only one ds:Signature element is allowed.',
229
            TooManyElementsException::class,
230
        );
231
232
        $idpssod = new static(
233
            SingleSignOnService::getChildrenOfClass($xml),
234
            preg_split('/[\s]+/', trim($protocols)),
235
            self::getOptionalBooleanAttribute($xml, 'WantAuthnRequestsSigned', null),
236
            NameIDMappingService::getChildrenOfClass($xml),
237
            AssertionIDRequestService::getChildrenOfClass($xml),
238
            AttributeProfile::getChildrenOfClass($xml),
239
            Attribute::getChildrenOfClass($xml),
240
            self::getOptionalAttribute($xml, 'ID', null),
241
            $validUntil !== null ? new DateTimeImmutable($validUntil) : null,
242
            self::getOptionalAttribute($xml, 'cacheDuration', null),
243
            !empty($extensions) ? $extensions[0] : null,
244
            self::getOptionalAttribute($xml, 'errorURL', null),
245
            KeyDescriptor::getChildrenOfClass($xml),
246
            !empty($orgs) ? $orgs[0] : null,
247
            ContactPerson::getChildrenOfClass($xml),
248
            ArtifactResolutionService::getChildrenOfClass($xml),
249
            SingleLogoutService::getChildrenOfClass($xml),
250
            ManageNameIDService::getChildrenOfClass($xml),
251
            NameIDFormat::getChildrenOfClass($xml),
252
        );
253
254
        if (!empty($signature)) {
255
            $idpssod->setSignature($signature[0]);
256
            $idpssod->setXML($xml);
257
        }
258
        return $idpssod;
259
    }
260
261
262
    /**
263
     * Convert this assertion to an unsigned XML document.
264
     * This method does not sign the resulting XML document.
265
     *
266
     * @return \DOMElement The root element of the DOM tree
267
     */
268
    public function toUnsignedXML(?DOMElement $parent = null): DOMElement
269
    {
270
        $e = parent::toUnsignedXML($parent);
271
272
        if (is_bool($this->wantAuthnRequestsSigned)) {
273
            $e->setAttribute('WantAuthnRequestsSigned', $this->wantAuthnRequestsSigned ? 'true' : 'false');
274
        }
275
276
        foreach ($this->getSingleSignOnService() as $ep) {
277
            $ep->toXML($e);
278
        }
279
280
        foreach ($this->getNameIDMappingService() as $ep) {
281
            $ep->toXML($e);
282
        }
283
284
        foreach ($this->getAssertionIDRequestService() as $ep) {
285
            $ep->toXML($e);
286
        }
287
288
        foreach ($this->getAttributeProfile() as $ap) {
289
            $ap->toXML($e);
290
        }
291
292
        foreach ($this->getSupportedAttribute() as $a) {
293
            $a->toXML($e);
294
        }
295
296
        return $e;
297
    }
298
}
299