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