Passed
Push — master ( 6db269...70aff8 )
by Jaime Pérez
02:49
created

SPSSODescriptor::fromXML()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 38
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 30
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 38
rs 9.1288
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SAML2\XML\md;
6
7
use DOMElement;
8
use SAML2\Constants;
9
use SAML2\Utils;
10
use SAML2\XML\ds\Signature;
11
use Webmozart\Assert\Assert;
12
13
/**
14
 * Class representing SAML 2 SPSSODescriptor.
15
 *
16
 * @package simplesamlphp/saml2
17
 */
18
final class SPSSODescriptor extends AbstractSSODescriptor
19
{
20
    /**
21
     * Whether this SP signs authentication requests.
22
     *
23
     * @var bool|null
24
     */
25
    protected $authnRequestsSigned = null;
26
27
    /**
28
     * Whether this SP wants the Assertion elements to be signed.
29
     *
30
     * @var bool|null
31
     */
32
    protected $wantAssertionsSigned = null;
33
34
    /**
35
     * List of AssertionConsumerService endpoints for this SP.
36
     *
37
     * Array with IndexedEndpointType objects.
38
     *
39
     * @var \SAML2\XML\md\AssertionConsumerService[]
40
     */
41
    protected $assertionConsumerService = [];
42
43
    /**
44
     * List of AttributeConsumingService descriptors for this SP.
45
     *
46
     * Array with \SAML2\XML\md\AttributeConsumingService objects.
47
     *
48
     * @var \SAML2\XML\md\AttributeConsumingService[]
49
     */
50
    protected $attributeConsumingService = [];
51
52
53
54
    /**
55
     * SPSSODescriptor constructor.
56
     *
57
     * @param \SAML2\XML\md\AssertionConsumerService[] $assertionConsumerService
58
     * @param string[] $protocolSupportEnumeration
59
     * @param bool|null $authnRequestsSigned
60
     * @param bool|null $wantAssertionsSigned
61
     * @param \SAML2\XML\md\AttributeConsumingService[] $attributeConsumingService
62
     * @param string|null $ID
63
     * @param int|null $validUntil
64
     * @param string|null $cacheDuration
65
     * @param \SAML2\XML\md\Extensions|null $extensions
66
     * @param string|null $errorURL
67
     * @param \SAML2\XML\md\KeyDescriptor[] $keyDescriptors
68
     * @param \SAML2\XML\md\Organization|null $organization
69
     * @param \SAML2\XML\md\ContactPerson[] $contacts
70
     * @param \SAML2\XML\md\ArtifactResolutionService[] $artifactResolutionService
71
     * @param \SAML2\XML\md\SingleLogoutService[] $singleLogoutService
72
     * @param \SAML2\XML\md\ManageNameIDService[] $manageNameIDService
73
     * @param string[] $nameIDFormat
74
     */
75
    public function __construct(
76
        array $assertionConsumerService,
77
        array $protocolSupportEnumeration,
78
        ?bool $authnRequestsSigned = null,
79
        ?bool $wantAssertionsSigned = null,
80
        array $attributeConsumingService = [],
81
        ?string $ID = null,
82
        ?int $validUntil = null,
83
        ?string $cacheDuration = null,
84
        ?Extensions $extensions = null,
85
        ?string $errorURL = null,
86
        array $keyDescriptors = [],
87
        ?Organization $organization = null,
88
        array $contacts = [],
89
        array $artifactResolutionService = [],
90
        array $singleLogoutService = [],
91
        array $manageNameIDService = [],
92
        array $nameIDFormat = []
93
    ) {
94
        parent::__construct(
95
            $protocolSupportEnumeration,
96
            $ID,
97
            $validUntil,
98
            $cacheDuration,
99
            $extensions,
100
            $errorURL,
101
            $keyDescriptors,
102
            $organization,
103
            $contacts,
104
            $artifactResolutionService,
105
            $singleLogoutService,
106
            $manageNameIDService,
107
            $nameIDFormat
108
        );
109
110
        $this->setAssertionConsumerService($assertionConsumerService);
111
        $this->setAuthnRequestsSigned($authnRequestsSigned);
112
        $this->setWantAssertionsSigned($wantAssertionsSigned);
113
        $this->setAttributeConsumingService($attributeConsumingService);
114
115
        // test that only one ACS is marked as default
116
        Assert::maxCount(
117
            array_filter(
118
                $this->getAttributeConsumingService(),
119
                function (AttributeConsumingService $acs) {
120
                    return $acs->getIsDefault() === true;
121
                }
122
            ),
123
            1,
124
            'Only one md:AttributeConsumingService can be set as default.'
125
        );
126
    }
127
128
129
    /**
130
     * Collect the value of the AuthnRequestsSigned-property
131
     *
132
     * @return bool|null
133
     */
134
    public function getAuthnRequestsSigned(): ?bool
135
    {
136
        return $this->authnRequestsSigned;
137
    }
138
139
140
    /**
141
     * Set the value of the AuthnRequestsSigned-property
142
     *
143
     * @param bool|null $flag
144
     * @return void
145
     */
146
    private function setAuthnRequestsSigned(?bool $flag): void
147
    {
148
        $this->authnRequestsSigned = $flag;
149
    }
150
151
152
    /**
153
     * Collect the value of the WantAssertionsSigned-property
154
     *
155
     * @return bool|null
156
     */
157
    public function getWantAssertionsSigned(): ?bool
158
    {
159
        return $this->wantAssertionsSigned;
160
    }
161
162
163
    /**
164
     * Set the value of the WantAssertionsSigned-property
165
     *
166
     * @param bool|null $flag
167
     * @return void
168
     */
169
    private function setWantAssertionsSigned(?bool $flag): void
170
    {
171
        $this->wantAssertionsSigned = $flag;
172
    }
173
174
175
    /**
176
     * Collect the value of the AssertionConsumerService-property
177
     *
178
     * @return \SAML2\XML\md\AssertionConsumerService[]
179
     */
180
    public function getAssertionConsumerService(): array
181
    {
182
        return $this->assertionConsumerService;
183
    }
184
185
186
    /**
187
     * Set the value of the AssertionConsumerService-property
188
     *
189
     * @param \SAML2\XML\md\AssertionConsumerService[] $acs
190
     * @return void
191
     * @throws \InvalidArgumentException
192
     */
193
    private function setAssertionConsumerService(array $acs): void
194
    {
195
        Assert::minCount($acs, 1, 'At least one AssertionConsumerService must be specified.');
196
        Assert::allIsInstanceOf(
197
            $acs,
198
            AssertionConsumerService::class,
199
            'All md:AssertionConsumerService endpoints must be an instance of AssertionConsumerService.'
200
        );
201
        $this->assertionConsumerService = $acs;
202
    }
203
204
205
    /**
206
     * Collect the value of the AttributeConsumingService-property
207
     *
208
     * @return \SAML2\XML\md\AttributeConsumingService[]
209
     */
210
    public function getAttributeConsumingService(): array
211
    {
212
        return $this->attributeConsumingService;
213
    }
214
215
216
    /**
217
     * Set the value of the AttributeConsumingService-property
218
     *
219
     * @param \SAML2\XML\md\AttributeConsumingService[] $acs
220
     * @return void
221
     * @throws \InvalidArgumentException
222
     */
223
    private function setAttributeConsumingService(array $acs): void
224
    {
225
        Assert::allIsInstanceOf(
226
            $acs,
227
            AttributeConsumingService::class,
228
            'All md:AttributeConsumingService endpoints must be an instance of AttributeConsumingService.'
229
        );
230
        $this->attributeConsumingService = $acs;
231
    }
232
233
234
    /**
235
     * Convert XML into a SPSSODescriptor
236
     *
237
     * @param \DOMElement $xml The XML element we should load
238
     *
239
     * @return self
240
     * @throws \InvalidArgumentException if the qualified name of the supplied element is wrong*@throws \Exception
241
     * @throws \Exception
242
     */
243
    public static function fromXML(DOMElement $xml): object
244
    {
245
        Assert::same($xml->localName, 'SPSSODescriptor');
246
        Assert::same($xml->namespaceURI, SPSSODescriptor::NS);
247
248
        $validUntil = self::getAttribute($xml, 'validUntil', null);
249
        $orgs = Organization::getChildrenOfClass($xml);
250
        Assert::maxCount($orgs, 1, 'More than one Organization found in this descriptor');
251
252
        $extensions = Extensions::getChildrenOfClass($xml);
253
        Assert::maxCount($extensions, 1, 'Only one md:Extensions element is allowed.');
254
255
        $signature = Signature::getChildrenOfClass($xml);
256
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.');
257
258
        $spssod = new self(
259
            AssertionConsumerService::getChildrenOfClass($xml),
260
            preg_split('/[\s]+/', trim(self::getAttribute($xml, 'protocolSupportEnumeration'))),
0 ignored issues
show
Bug introduced by
It seems like preg_split('/[\s]+/', tr...lSupportEnumeration'))) can also be of type false; however, parameter $protocolSupportEnumeration of SAML2\XML\md\SPSSODescriptor::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

260
            /** @scrutinizer ignore-type */ preg_split('/[\s]+/', trim(self::getAttribute($xml, 'protocolSupportEnumeration'))),
Loading history...
261
            self::getBooleanAttribute($xml, 'AuthnRequestsSigned', null),
262
            self::getBooleanAttribute($xml, 'WantAssertionsSigned', null),
263
            AttributeConsumingService::getChildrenOfClass($xml),
264
            self::getAttribute($xml, 'ID', null),
265
            $validUntil !== null ? Utils::xsDateTimeToTimestamp($validUntil) : null,
266
            self::getAttribute($xml, 'cacheDuration', null),
267
            !empty($extensions) ? $extensions[0] : null,
268
            self::getAttribute($xml, 'errorURL', null),
269
            KeyDescriptor::getChildrenOfClass($xml),
270
            !empty($orgs) ? $orgs[0] : null,
271
            ContactPerson::getChildrenOfClass($xml),
272
            ArtifactResolutionService::getChildrenOfClass($xml),
273
            SingleLogoutService::getChildrenOfClass($xml),
274
            ManageNameIDService::getChildrenOfClass($xml),
275
            Utils::extractStrings($xml, Constants::NS_MD, 'NameIDFormat')
276
        );
277
        if (!empty($signature)) {
278
            $spssod->setSignature($signature[0]);
279
        }
280
        return $spssod;
281
    }
282
283
284
    /**
285
     * Add this SPSSODescriptor to an EntityDescriptor.
286
     *
287
     * @param \DOMElement|null $parent The EntityDescriptor we should append this SPSSODescriptor to.
288
     * @return \DOMElement
289
     * @throws \Exception
290
     */
291
    public function toXML(DOMElement $parent = null): DOMElement
292
    {
293
        $e = parent::toXML($parent);
294
295
        if (is_bool($this->authnRequestsSigned)) {
296
            $e->setAttribute('AuthnRequestsSigned', $this->authnRequestsSigned ? 'true' : 'false');
297
        }
298
299
        if (is_bool($this->wantAssertionsSigned)) {
300
            $e->setAttribute('WantAssertionsSigned', $this->wantAssertionsSigned ? 'true' : 'false');
301
        }
302
303
        foreach ($this->assertionConsumerService as $ep) {
304
            $ep->toXML($e);
305
        }
306
307
        foreach ($this->attributeConsumingService as $acs) {
308
            $acs->toXML($e);
309
        }
310
311
        return $this->signElement($e);
312
    }
313
}
314