Passed
Pull Request — master (#374)
by Tim
03:49 queued 01:20
created

IDPSSODescriptor::toUnsignedXML()   B

Complexity

Conditions 7
Paths 64

Size

Total Lines 32
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

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