AuthnRequest::toUnsignedXML()   F
last analyzed

Complexity

Conditions 14
Paths 640

Size

Total Lines 51
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 28
nc 640
nop 1
dl 0
loc 51
rs 2.6
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\samlp;
6
7
use DOMElement;
8
use SimpleSAML\SAML2\Assert\Assert;
9
use SimpleSAML\SAML2\Exception\Protocol\RequestVersionTooHighException;
10
use SimpleSAML\SAML2\Exception\Protocol\RequestVersionTooLowException;
11
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
12
use SimpleSAML\SAML2\Type\SAMLAnyURIValue;
13
use SimpleSAML\SAML2\Type\SAMLDateTimeValue;
14
use SimpleSAML\SAML2\Type\SAMLStringValue;
15
use SimpleSAML\SAML2\XML\saml\Conditions;
16
use SimpleSAML\SAML2\XML\saml\Issuer;
17
use SimpleSAML\SAML2\XML\saml\Subject;
18
use SimpleSAML\XML\SchemaValidatableElementInterface;
19
use SimpleSAML\XML\SchemaValidatableElementTrait;
20
use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException;
21
use SimpleSAML\XMLSchema\Exception\TooManyElementsException;
22
use SimpleSAML\XMLSchema\Type\BooleanValue;
23
use SimpleSAML\XMLSchema\Type\IDValue;
24
use SimpleSAML\XMLSchema\Type\UnsignedShortValue;
25
use SimpleSAML\XMLSecurity\XML\ds\Signature;
26
27
use function array_pop;
28
use function strval;
29
30
/**
31
 * Class for SAML 2 authentication request messages.
32
 *
33
 * @package simplesamlphp/saml2
34
 */
35
class AuthnRequest extends AbstractRequest implements SchemaValidatableElementInterface
36
{
37
    use SchemaValidatableElementTrait;
38
39
40
    /**
41
     * Constructor for SAML 2 AuthnRequest
42
     *
43
     * @param \SimpleSAML\XMLSchema\Type\IDValue $id
44
     * @param \SimpleSAML\SAML2\Type\SAMLDateTimeValue $issueInstant
45
     * @param \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext|null $requestedAuthnContext
46
     * @param \SimpleSAML\SAML2\XML\saml\Subject|null $subject
47
     * @param \SimpleSAML\SAML2\XML\samlp\NameIDPolicy|null $nameIdPolicy
48
     * @param \SimpleSAML\SAML2\XML\saml\Conditions|null $conditions
49
     * @param \SimpleSAML\XMLSchema\Type\BooleanValue|null $forceAuthn
50
     * @param \SimpleSAML\XMLSchema\Type\BooleanValue|null $isPassive
51
     * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null $assertionConsumerServiceURL
52
     * @param \SimpleSAML\XMLSchema\Type\UnsignedShortValue|null $assertionConsumerServiceIndex
53
     * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null $protocolBinding
54
     * @param \SimpleSAML\XMLSchema\Type\UnsignedShortValue|null $attributeConsumingServiceIndex
55
     * @param \SimpleSAML\SAML2\Type\SAMLStringValue|null $providerName
56
     * @param \SimpleSAML\SAML2\XML\saml\Issuer|null $issuer
57
     * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null $destination
58
     * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null $consent
59
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions|null $extensions
60
     * @param \SimpleSAML\SAML2\XML\samlp\Scoping|null $scoping
61
     * @throws \Exception
62
     */
63
    final public function __construct(
64
        IDValue $id,
65
        SAMLDateTimeValue $issueInstant,
66
        protected ?RequestedAuthnContext $requestedAuthnContext = null,
67
        protected ?Subject $subject = null,
68
        protected ?NameIDPolicy $nameIdPolicy = null,
69
        protected ?Conditions $conditions = null,
70
        protected ?BooleanValue $forceAuthn = null,
71
        protected ?BooleanValue $isPassive = null,
72
        protected ?SAMLAnyURIValue $assertionConsumerServiceURL = null,
73
        protected ?UnsignedShortValue $assertionConsumerServiceIndex = null,
74
        protected ?SAMLAnyURIValue $protocolBinding = null,
75
        protected ?UnsignedShortValue $attributeConsumingServiceIndex = null,
76
        protected ?SAMLStringValue $providerName = null,
77
        ?Issuer $issuer = null,
78
        ?SAMLAnyURIValue $destination = null,
79
        ?SAMLAnyURIValue $consent = null,
80
        ?Extensions $extensions = null,
81
        protected ?Scoping $scoping = null,
82
    ) {
83
        Assert::oneOf(
84
            null,
85
            [$assertionConsumerServiceURL, $assertionConsumerServiceIndex],
86
            'The AssertionConsumerServiceURL and AssertionConsumerServiceIndex are mutually exclusive;'
87
            . ' please specify one or the other.',
88
            ProtocolViolationException::class,
89
        );
90
        Assert::oneOf(
91
            null,
92
            [$protocolBinding, $assertionConsumerServiceIndex],
93
            'The ProtocolBinding and AssertionConsumerServiceIndex are mutually exclusive;'
94
            . ' please specify one or the other.',
95
            ProtocolViolationException::class,
96
        );
97
98
        parent::__construct($id, $issuer, $issueInstant, $destination, $consent, $extensions);
99
    }
100
101
102
    /**
103
     * @return \SimpleSAML\SAML2\XML\saml\Subject|null
104
     */
105
    public function getSubject(): ?Subject
106
    {
107
        return $this->subject;
108
    }
109
110
111
    /**
112
     * @return \SimpleSAML\SAML2\XML\samlp\Scoping|null
113
     */
114
    public function getScoping(): ?Scoping
115
    {
116
        return $this->scoping;
117
    }
118
119
120
    /**
121
     * @return \SimpleSAML\SAML2\XML\saml\Conditions|null
122
     */
123
    public function getConditions(): ?Conditions
124
    {
125
        return $this->conditions;
126
    }
127
128
129
    /**
130
     * Retrieve the NameIdPolicy.
131
     *
132
     * @return \SimpleSAML\SAML2\XML\samlp\NameIDPolicy|null The NameIdPolicy.
133
     */
134
    public function getNameIdPolicy(): ?NameIDPolicy
135
    {
136
        return $this->nameIdPolicy;
137
    }
138
139
140
    /**
141
     * Retrieve the value of the ForceAuthn attribute.
142
     *
143
     * @return \SimpleSAML\XMLSchema\Type\BooleanValue|null The ForceAuthn attribute.
144
     */
145
    public function getForceAuthn(): ?BooleanValue
146
    {
147
        return $this->forceAuthn;
148
    }
149
150
151
    /**
152
     * Retrieve the value of the ProviderName attribute.
153
     *
154
     * @return \SimpleSAML\SAML2\Type\SAMLStringValue|null The ProviderName attribute.
155
     */
156
    public function getProviderName(): ?SAMLStringValue
157
    {
158
        return $this->providerName;
159
    }
160
161
162
    /**
163
     * Retrieve the value of the IsPassive attribute.
164
     *
165
     * @return \SimpleSAML\XMLSchema\Type\BooleanValue|null The IsPassive attribute.
166
     */
167
    public function getIsPassive(): ?BooleanValue
168
    {
169
        return $this->isPassive;
170
    }
171
172
173
    /**
174
     * Retrieve the value of the AssertionConsumerServiceURL attribute.
175
     *
176
     * @return \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null The AssertionConsumerServiceURL attribute.
177
     */
178
    public function getAssertionConsumerServiceURL(): ?SAMLAnyURIValue
179
    {
180
        return $this->assertionConsumerServiceURL;
181
    }
182
183
184
    /**
185
     * Retrieve the value of the ProtocolBinding attribute.
186
     *
187
     * @return \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null The ProtocolBinding attribute.
188
     */
189
    public function getProtocolBinding(): ?SAMLAnyURIValue
190
    {
191
        return $this->protocolBinding;
192
    }
193
194
195
    /**
196
     * Retrieve the value of the AttributeConsumingServiceIndex attribute.
197
     *
198
     * @return \SimpleSAML\XMLSchema\Type\UnsignedShortValue|null The AttributeConsumingServiceIndex attribute.
199
     */
200
    public function getAttributeConsumingServiceIndex(): ?UnsignedShortValue
201
    {
202
        return $this->attributeConsumingServiceIndex;
203
    }
204
205
206
    /**
207
     * Retrieve the value of the AssertionConsumerServiceIndex attribute.
208
     *
209
     * @return \SimpleSAML\XMLSchema\Type\UnsignedShortValue|null The AssertionConsumerServiceIndex attribute.
210
     */
211
    public function getAssertionConsumerServiceIndex(): ?UnsignedShortValue
212
    {
213
        return $this->assertionConsumerServiceIndex;
214
    }
215
216
217
    /**
218
     * Retrieve the RequestedAuthnContext.
219
     *
220
     * @return \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext|null The RequestedAuthnContext.
221
     */
222
    public function getRequestedAuthnContext(): ?RequestedAuthnContext
223
    {
224
        return $this->requestedAuthnContext;
225
    }
226
227
228
    /**
229
     * Convert XML into an AuthnRequest
230
     *
231
     * @param \DOMElement $xml The XML element we should load
232
     * @return static
233
     *
234
     * @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException
235
     *   if the qualified name of the supplied element is wrong
236
     * @throws \SimpleSAML\XMLSchema\Exception\MissingAttributeException
237
     *   if the supplied element is missing one of the mandatory attributes
238
     * @throws \SimpleSAML\XMLSchema\Exception\TooManyElementsException
239
     *   if too many child-elements of a type are specified
240
     */
241
    public static function fromXML(DOMElement $xml): static
242
    {
243
        Assert::same($xml->localName, 'AuthnRequest', InvalidDOMElementException::class);
244
        Assert::same($xml->namespaceURI, AuthnRequest::NS, InvalidDOMElementException::class);
245
246
        $version = self::getAttribute($xml, 'Version', SAMLStringValue::class);
247
        Assert::true(version_compare('2.0', strval($version), '<='), RequestVersionTooLowException::class);
248
        Assert::true(version_compare('2.0', strval($version), '>='), RequestVersionTooHighException::class);
249
250
        $conditions = Conditions::getChildrenOfClass($xml);
251
        Assert::maxCount(
252
            $conditions,
253
            1,
254
            'Only one <saml:Conditions> element is allowed.',
255
            TooManyElementsException::class,
256
        );
257
258
        $nameIdPolicy = NameIDPolicy::getChildrenOfClass($xml);
259
        Assert::maxCount(
260
            $nameIdPolicy,
261
            1,
262
            'Only one <samlp:NameIDPolicy> element is allowed.',
263
            TooManyElementsException::class,
264
        );
265
266
        $subject = Subject::getChildrenOfClass($xml);
267
        Assert::maxCount($subject, 1, 'Only one <saml:Subject> element is allowed.', TooManyElementsException::class);
268
269
        $issuer = Issuer::getChildrenOfClass($xml);
270
        Assert::maxCount($issuer, 1, 'Only one <saml:Issuer> element is allowed.', TooManyElementsException::class);
271
272
        $requestedAuthnContext = RequestedAuthnContext::getChildrenOfClass($xml);
273
        Assert::maxCount(
274
            $requestedAuthnContext,
275
            1,
276
            'Only one <samlp:RequestedAuthnContext> element is allowed.',
277
            TooManyElementsException::class,
278
        );
279
280
        $extensions = Extensions::getChildrenOfClass($xml);
281
        Assert::maxCount(
282
            $extensions,
283
            1,
284
            'Only one <samlp:Extensions> element is allowed.',
285
            TooManyElementsException::class,
286
        );
287
288
        $signature = Signature::getChildrenOfClass($xml);
289
        Assert::maxCount(
290
            $signature,
291
            1,
292
            'Only one <ds:Signature> element is allowed.',
293
            TooManyElementsException::class,
294
        );
295
296
        $scoping = Scoping::getChildrenOfClass($xml);
297
        Assert::maxCount($scoping, 1, 'Only one <samlp:Scoping> element is allowed.', TooManyElementsException::class);
298
299
        $request = new static(
300
            self::getAttribute($xml, 'ID', IDValue::class),
301
            self::getAttribute($xml, 'IssueInstant', SAMLDateTimeValue::class),
302
            array_pop($requestedAuthnContext),
303
            array_pop($subject),
304
            array_pop($nameIdPolicy),
305
            array_pop($conditions),
306
            self::getOptionalAttribute($xml, 'ForceAuthn', BooleanValue::class, null),
307
            self::getOptionalAttribute($xml, 'IsPassive', BooleanValue::class, null),
308
            self::getOptionalAttribute($xml, 'AssertionConsumerServiceURL', SAMLAnyURIValue::class, null),
309
            self::getOptionalAttribute($xml, 'AssertionConsumerServiceIndex', UnsignedShortValue::class, null),
310
            self::getOptionalAttribute($xml, 'ProtocolBinding', SAMLAnyURIValue::class, null),
311
            self::getOptionalAttribute($xml, 'AttributeConsumingServiceIndex', UnsignedShortValue::class, null),
312
            self::getOptionalAttribute($xml, 'ProviderName', SAMLStringValue::class, null),
313
            array_pop($issuer),
314
            self::getOptionalAttribute($xml, 'Destination', SAMLAnyURIValue::class, null),
315
            self::getOptionalAttribute($xml, 'Consent', SAMLAnyURIValue::class, null),
316
            array_pop($extensions),
317
            array_pop($scoping),
318
        );
319
320
        if (!empty($signature)) {
321
            $request->setSignature($signature[0]);
322
            $request->messageContainedSignatureUponConstruction = true;
323
            $request->setXML($xml);
324
        }
325
326
        return $request;
327
    }
328
329
330
    /**
331
     * Convert this message to an unsigned XML document.
332
     * This method does not sign the resulting XML document.
333
     *
334
     * @return \DOMElement The root element of the DOM tree
335
     */
336
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
337
    {
338
        $e = parent::toUnsignedXML($parent);
339
340
        if ($this->getForceAuthn() === true) {
0 ignored issues
show
introduced by
The condition $this->getForceAuthn() === true is always false.
Loading history...
341
            $e->setAttribute('ForceAuthn', strval($this->getForceAuthn()));
342
        }
343
344
        if ($this->getProviderName() !== null) {
345
            $e->setAttribute('ProviderName', strval($this->getProviderName()));
346
        }
347
348
        if ($this->getIsPassive() === true) {
0 ignored issues
show
introduced by
The condition $this->getIsPassive() === true is always false.
Loading history...
349
            $e->setAttribute('IsPassive', strval($this->getIsPassive()));
350
        }
351
352
        if ($this->getAssertionConsumerServiceIndex() !== null) {
353
            $e->setAttribute('AssertionConsumerServiceIndex', strval($this->getAssertionConsumerServiceIndex()));
354
        } else {
355
            if ($this->getAssertionConsumerServiceURL() !== null) {
356
                $e->setAttribute('AssertionConsumerServiceURL', strval($this->getAssertionConsumerServiceURL()));
357
            }
358
            if ($this->getProtocolBinding() !== null) {
359
                $e->setAttribute('ProtocolBinding', strval($this->getProtocolBinding()));
360
            }
361
        }
362
363
        if ($this->getAttributeConsumingServiceIndex() !== null) {
364
            $e->setAttribute('AttributeConsumingServiceIndex', strval($this->getAttributeConsumingServiceIndex()));
365
        }
366
367
        $this->getSubject()?->toXML($e);
368
369
        $nameIdPolicy = $this->getNameIdPolicy();
370
        if ($nameIdPolicy !== null && !$nameIdPolicy->isEmptyElement()) {
371
            $nameIdPolicy->toXML($e);
372
        }
373
374
        $conditions = $this->getConditions();
375
        if ($conditions !== null && !$conditions->isEmptyElement()) {
376
            $conditions->toXML($e);
377
        }
378
379
        $this->getRequestedAuthnContext()?->toXML($e);
380
381
        $scoping = $this->getScoping();
382
        if ($scoping !== null && !$scoping->isEmptyElement()) {
383
            $scoping->toXML($e);
384
        }
385
386
        return $e;
387
    }
388
}
389