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