Passed
Push — master ( eb6d7f...017f7a )
by Tim
02:40
created

SPSSODescriptor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 50
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 24
nc 1
nop 17
dl 0
loc 50
rs 9.536
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\XML\Exception\InvalidDOMElementException;
10
use SimpleSAML\XML\Exception\TooManyElementsException;
11
use SimpleSAML\XML\Utils as XMLUtils;
12
use SimpleSAML\XMLSecurity\XML\ds\Signature;
13
14
use function array_filter;
15
use function is_bool;
16
use function preg_split;
17
18
/**
19
 * Class representing SAML 2 SPSSODescriptor.
20
 *
21
 * @package simplesamlphp/saml2
22
 */
23
final class SPSSODescriptor extends AbstractSSODescriptor
24
{
25
    /**
26
     * Whether this SP signs authentication requests.
27
     *
28
     * @var bool|null
29
     */
30
    protected ?bool $authnRequestsSigned = null;
31
32
    /**
33
     * Whether this SP wants the Assertion elements to be signed.
34
     *
35
     * @var bool|null
36
     */
37
    protected ?bool $wantAssertionsSigned = null;
38
39
    /**
40
     * List of AssertionConsumerService endpoints for this SP.
41
     *
42
     * Array with IndexedEndpointType objects.
43
     *
44
     * @var \SimpleSAML\SAML2\XML\md\AssertionConsumerService[]
45
     */
46
    protected array $assertionConsumerService = [];
47
48
    /**
49
     * List of AttributeConsumingService descriptors for this SP.
50
     *
51
     * Array with \SimpleSAML\SAML2\XML\md\AttributeConsumingService objects.
52
     *
53
     * @var \SimpleSAML\SAML2\XML\md\AttributeConsumingService[]
54
     */
55
    protected array $attributeConsumingService = [];
56
57
58
59
    /**
60
     * SPSSODescriptor constructor.
61
     *
62
     * @param \SimpleSAML\SAML2\XML\md\AssertionConsumerService[] $assertionConsumerService
63
     * @param string[] $protocolSupportEnumeration
64
     * @param bool|null $authnRequestsSigned
65
     * @param bool|null $wantAssertionsSigned
66
     * @param \SimpleSAML\SAML2\XML\md\AttributeConsumingService[] $attributeConsumingService
67
     * @param string|null $ID
68
     * @param int|null $validUntil
69
     * @param string|null $cacheDuration
70
     * @param \SimpleSAML\SAML2\XML\md\Extensions|null $extensions
71
     * @param string|null $errorURL
72
     * @param \SimpleSAML\SAML2\XML\md\KeyDescriptor[] $keyDescriptors
73
     * @param \SimpleSAML\SAML2\XML\md\Organization|null $organization
74
     * @param \SimpleSAML\SAML2\XML\md\ContactPerson[] $contacts
75
     * @param \SimpleSAML\SAML2\XML\md\ArtifactResolutionService[] $artifactResolutionService
76
     * @param \SimpleSAML\SAML2\XML\md\SingleLogoutService[] $singleLogoutService
77
     * @param \SimpleSAML\SAML2\XML\md\ManageNameIDService[] $manageNameIDService
78
     * @param \SimpleSAML\SAML2\XML\md\NameIDFormat[] $nameIDFormat
79
     */
80
    public function __construct(
81
        array $assertionConsumerService,
82
        array $protocolSupportEnumeration,
83
        ?bool $authnRequestsSigned = null,
84
        ?bool $wantAssertionsSigned = null,
85
        array $attributeConsumingService = [],
86
        ?string $ID = null,
87
        ?int $validUntil = null,
88
        ?string $cacheDuration = null,
89
        ?Extensions $extensions = null,
90
        ?string $errorURL = null,
91
        array $keyDescriptors = [],
92
        ?Organization $organization = null,
93
        array $contacts = [],
94
        array $artifactResolutionService = [],
95
        array $singleLogoutService = [],
96
        array $manageNameIDService = [],
97
        array $nameIDFormat = []
98
    ) {
99
        parent::__construct(
100
            $protocolSupportEnumeration,
101
            $ID,
102
            $validUntil,
103
            $cacheDuration,
104
            $extensions,
105
            $errorURL,
106
            $keyDescriptors,
107
            $organization,
108
            $contacts,
109
            $artifactResolutionService,
110
            $singleLogoutService,
111
            $manageNameIDService,
112
            $nameIDFormat
113
        );
114
115
        $this->setAssertionConsumerService($assertionConsumerService);
116
        $this->setAuthnRequestsSigned($authnRequestsSigned);
117
        $this->setWantAssertionsSigned($wantAssertionsSigned);
118
        $this->setAttributeConsumingService($attributeConsumingService);
119
120
        // test that only one ACS is marked as default
121
        Assert::maxCount(
122
            array_filter(
123
                $this->getAttributeConsumingService(),
124
                function (AttributeConsumingService $acs) {
125
                    return $acs->getIsDefault() === true;
126
                }
127
            ),
128
            1,
129
            'Only one md:AttributeConsumingService can be set as default.'
130
        );
131
    }
132
133
134
    /**
135
     * Collect the value of the AuthnRequestsSigned-property
136
     *
137
     * @return bool|null
138
     */
139
    public function getAuthnRequestsSigned(): ?bool
140
    {
141
        return $this->authnRequestsSigned;
142
    }
143
144
145
    /**
146
     * Set the value of the AuthnRequestsSigned-property
147
     *
148
     * @param bool|null $flag
149
     */
150
    private function setAuthnRequestsSigned(?bool $flag): void
151
    {
152
        $this->authnRequestsSigned = $flag;
153
    }
154
155
156
    /**
157
     * Collect the value of the WantAssertionsSigned-property
158
     *
159
     * @return bool|null
160
     */
161
    public function getWantAssertionsSigned(): ?bool
162
    {
163
        return $this->wantAssertionsSigned;
164
    }
165
166
167
    /**
168
     * Set the value of the WantAssertionsSigned-property
169
     *
170
     * @param bool|null $flag
171
     */
172
    private function setWantAssertionsSigned(?bool $flag): void
173
    {
174
        $this->wantAssertionsSigned = $flag;
175
    }
176
177
178
    /**
179
     * Collect the value of the AssertionConsumerService-property
180
     *
181
     * @return \SimpleSAML\SAML2\XML\md\AssertionConsumerService[]
182
     */
183
    public function getAssertionConsumerService(): array
184
    {
185
        return $this->assertionConsumerService;
186
    }
187
188
189
    /**
190
     * Set the value of the AssertionConsumerService-property
191
     *
192
     * @param \SimpleSAML\SAML2\XML\md\AssertionConsumerService[] $acs
193
     * @throws \SimpleSAML\Assert\AssertionFailedException
194
     */
195
    private function setAssertionConsumerService(array $acs): void
196
    {
197
        Assert::minCount($acs, 1, 'At least one AssertionConsumerService must be specified.');
198
        Assert::allIsInstanceOf(
199
            $acs,
200
            AssertionConsumerService::class,
201
            'All md:AssertionConsumerService endpoints must be an instance of AssertionConsumerService.'
202
        );
203
        $this->assertionConsumerService = $acs;
204
    }
205
206
207
    /**
208
     * Collect the value of the AttributeConsumingService-property
209
     *
210
     * @return \SimpleSAML\SAML2\XML\md\AttributeConsumingService[]
211
     */
212
    public function getAttributeConsumingService(): array
213
    {
214
        return $this->attributeConsumingService;
215
    }
216
217
218
    /**
219
     * Set the value of the AttributeConsumingService-property
220
     *
221
     * @param \SimpleSAML\SAML2\XML\md\AttributeConsumingService[] $acs
222
     * @throws \SimpleSAML\Assert\AssertionFailedException
223
     */
224
    private function setAttributeConsumingService(array $acs): void
225
    {
226
        Assert::allIsInstanceOf(
227
            $acs,
228
            AttributeConsumingService::class,
229
            'All md:AttributeConsumingService endpoints must be an instance of AttributeConsumingService.'
230
        );
231
        $this->attributeConsumingService = $acs;
232
    }
233
234
235
    /**
236
     * Convert XML into a SPSSODescriptor
237
     *
238
     * @param \DOMElement $xml The XML element we should load
239
     *
240
     * @return self
241
     *
242
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
243
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
244
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
245
     */
246
    public static function fromXML(DOMElement $xml): static
247
    {
248
        Assert::same($xml->localName, 'SPSSODescriptor', InvalidDOMElementException::class);
249
        Assert::same($xml->namespaceURI, SPSSODescriptor::NS, InvalidDOMElementException::class);
250
251
        $protocols = self::getAttribute($xml, 'protocolSupportEnumeration');
252
        $validUntil = self::getAttribute($xml, 'validUntil', null);
253
        $orgs = Organization::getChildrenOfClass($xml);
254
        Assert::maxCount($orgs, 1, 'More than one Organization found in this descriptor', TooManyElementsException::class);
255
256
        $extensions = Extensions::getChildrenOfClass($xml);
257
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.', TooManyElementsException::class);
258
259
        $signature = Signature::getChildrenOfClass($xml);
260
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
261
262
        $spssod = new static(
263
            AssertionConsumerService::getChildrenOfClass($xml),
264
            preg_split('/[\s]+/', trim($protocols)),
265
            self::getBooleanAttribute($xml, 'AuthnRequestsSigned', null),
266
            self::getBooleanAttribute($xml, 'WantAssertionsSigned', null),
267
            AttributeConsumingService::getChildrenOfClass($xml),
268
            self::getAttribute($xml, 'ID', null),
269
            $validUntil !== null ? XMLUtils::xsDateTimeToTimestamp($validUntil) : null,
270
            self::getAttribute($xml, 'cacheDuration', null),
271
            !empty($extensions) ? $extensions[0] : null,
272
            self::getAttribute($xml, 'errorURL', null),
273
            KeyDescriptor::getChildrenOfClass($xml),
274
            !empty($orgs) ? $orgs[0] : null,
275
            ContactPerson::getChildrenOfClass($xml),
276
            ArtifactResolutionService::getChildrenOfClass($xml),
277
            SingleLogoutService::getChildrenOfClass($xml),
278
            ManageNameIDService::getChildrenOfClass($xml),
279
            NameIDFormat::getChildrenOfClass($xml)
280
        );
281
        if (!empty($signature)) {
282
            $spssod->setSignature($signature[0]);
283
        }
284
        return $spssod;
285
    }
286
287
288
    /**
289
     * Convert this assertion to an unsigned XML document.
290
     * This method does not sign the resulting XML document.
291
     *
292
     * @return \DOMElement The root element of the DOM tree
293
     */
294
    public function toUnsignedXML(?DOMElement $parent = null): DOMElement
295
    {
296
        $e = parent::toUnsignedXML($parent);
297
298
        if (is_bool($this->authnRequestsSigned)) {
299
            $e->setAttribute('AuthnRequestsSigned', $this->authnRequestsSigned ? 'true' : 'false');
300
        }
301
302
        if (is_bool($this->wantAssertionsSigned)) {
303
            $e->setAttribute('WantAssertionsSigned', $this->wantAssertionsSigned ? 'true' : 'false');
304
        }
305
306
        foreach ($this->assertionConsumerService as $ep) {
307
            $ep->toXML($e);
308
        }
309
310
        foreach ($this->attributeConsumingService as $acs) {
311
            $acs->toXML($e);
312
        }
313
314
        return $e;
315
    }
316
}
317