Passed
Pull Request — master (#280)
by Tim
02:22
created

AuthnRequest::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 35
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 18
dl 0
loc 35
rs 9.8333
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\samlp;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\SAML2\Exception\InvalidArgumentException;
10
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
11
use SimpleSAML\SAML2\XML\saml\Conditions;
12
use SimpleSAML\SAML2\XML\saml\Issuer;
13
use SimpleSAML\SAML2\XML\saml\Subject;
14
use SimpleSAML\SAML2\XML\saml\SubjectConfirmation;
15
use SimpleSAML\XML\Exception\InvalidDOMElementException;
16
use SimpleSAML\XML\Exception\TooManyElementsException;
17
use SimpleSAML\XML\Utils as XMLUtils;
18
use SimpleSAML\XMLSecurity\XML\ds\Signature;
19
20
use function array_pop;
21
use function filter_var;
22
use function is_null;
23
use function strval;
24
25
/**
26
 * Class for SAML 2 authentication request messages.
27
 *
28
 * @package simplesamlphp/saml2
29
 */
30
class AuthnRequest extends AbstractRequest
31
{
32
    /**
33
     * @var \SimpleSAML\SAML2\XML\saml\Subject|null
34
     */
35
    protected ?Subject $subject = null;
36
37
    /**
38
     * @var \SimpleSAML\SAML2\XML\samlp\Scoping|null
39
     */
40
    protected ?Scoping $scoping = null;
41
42
    /**
43
     * The options for what type of name identifier should be returned.
44
     *
45
     * @var \SimpleSAML\SAML2\XML\samlp\NameIDPolicy|null
46
     */
47
    protected ?NameIDPolicy $nameIdPolicy = null;
48
49
    /**
50
     * Whether the Identity Provider must authenticate the user again.
51
     *
52
     * @var bool|null
53
     */
54
    protected ?bool $forceAuthn = false;
55
56
    /**
57
     * Optional ProviderID attribute
58
     *
59
     * @var string|null
60
     */
61
    protected ?string $ProviderName = null;
62
63
    /**
64
     * Set to true if this request is passive.
65
     *
66
     * @var bool|null
67
     */
68
    protected ?bool $isPassive = false;
69
70
    /**
71
     * The URL of the assertion consumer service where the response should be delivered.
72
     *
73
     * @var string|null
74
     */
75
    protected ?string $assertionConsumerServiceURL;
76
77
    /**
78
     * What binding should be used when sending the response.
79
     *
80
     * @var string|null
81
     */
82
    protected ?string $protocolBinding;
83
84
    /**
85
     * The index of the AttributeConsumingService.
86
     *
87
     * @var int|null
88
     */
89
    protected ?int $attributeConsumingServiceIndex;
90
91
    /**
92
     * The index of the AssertionConsumerService.
93
     *
94
     * @var int|null
95
     */
96
    protected ?int $assertionConsumerServiceIndex = null;
97
98
    /**
99
     * What authentication context was requested.
100
     *
101
     * @var \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext|null
102
     */
103
    protected ?RequestedAuthnContext $requestedAuthnContext;
104
105
    /**
106
     * @var \SimpleSAML\SAML2\XML\saml\Conditions|null
107
     */
108
    protected ?Conditions $conditions = null;
109
110
111
    /**
112
     * Constructor for SAML 2 AuthnRequest
113
     *
114
     * @param \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext $requestedAuthnContext
115
     * @param \SimpleSAML\SAML2\XML\saml\Subject $subject
116
     * @param \SimpleSAML\SAML2\XML\samlp\NameIDPolicy $nameIdPolicy
117
     * @param \SimpleSAML\SAML2\XML\saml\Conditions $conditions
118
     * @param bool $forceAuthn
119
     * @param bool $isPassive
120
     * @param string|null $assertionConsumerServiceUrl
121
     * @param int|null $assertionConsumerServiceIndex
122
     * @param string|null $protocolBinding
123
     * @param int|null $attributeConsumingServiceIndex
124
     * @param string|null $providerName
125
     * @param \SimpleSAML\SAML2\XML\saml\Issuer|null $issuer
126
     * @param string|null $id
127
     * @param int|null $issueInstant
128
     * @param string|null $destination
129
     * @param string|null $consent
130
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions|null $extensions
131
     * @param \SimpleSAML\SAML2\XML\samlp\Scoping|null $scoping
132
     * @throws \Exception
133
     */
134
    public function __construct(
135
        ?RequestedAuthnContext $requestedAuthnContext = null,
136
        ?Subject $subject = null,
137
        ?NameIDPolicy $nameIdPolicy = null,
138
        Conditions $conditions = null,
139
        ?bool $forceAuthn = null,
140
        ?bool $isPassive = null,
141
        ?string $assertionConsumerServiceUrl = null,
142
        ?int $assertionConsumerServiceIndex = null,
143
        ?string $protocolBinding = null,
144
        ?int $attributeConsumingServiceIndex = null,
145
        ?string $providerName = null,
146
        ?Issuer $issuer = null,
147
        ?string $id = null,
148
        ?int $issueInstant = null,
149
        ?string $destination = null,
150
        ?string $consent = null,
151
        ?Extensions $extensions = null,
152
        ?Scoping $scoping = null
153
    ) {
154
        parent::__construct($issuer, $id, $issueInstant, $destination, $consent, $extensions);
155
156
        $this->setRequestedAuthnContext($requestedAuthnContext);
157
        $this->setSubject($subject);
158
        $this->setNameIdPolicy($nameIdPolicy);
159
        $this->setConditions($conditions);
160
161
        $this->setForceAuthn($forceAuthn);
162
        $this->setIsPassive($isPassive);
163
        $this->setAssertionConsumerServiceUrl($assertionConsumerServiceUrl);
164
        $this->setAssertionConsumerServiceIndex($assertionConsumerServiceIndex);
165
        $this->setProtocolBinding($protocolBinding);
166
        $this->setAttributeConsumingServiceIndex($attributeConsumingServiceIndex);
167
        $this->setProviderName($providerName);
168
        $this->setScoping($scoping);
169
    }
170
171
172
    /**
173
     * @param \SimpleSAML\SAML2\XML\saml\Subject|null $subject
174
     */
175
    private function setSubject(?Subject $subject): void
176
    {
177
        $this->subject = $subject;
178
    }
179
180
181
    /**
182
     * @return \SimpleSAML\SAML2\XML\saml\Subject|null
183
     */
184
    public function getSubject(): ?Subject
185
    {
186
        return $this->subject;
187
    }
188
189
190
    /**
191
     * @param \SimpleSAML\SAML2\XML\samlp\Scoping|null $scoping
192
     */
193
    private function setScoping(?Scoping $scoping): void
194
    {
195
        $this->scoping = $scoping;
196
    }
197
198
199
    /**
200
     * @return \SimpleSAML\SAML2\XML\samlp\Scoping|null
201
     */
202
    public function getScoping(): ?Scoping
203
    {
204
        return $this->scoping;
205
    }
206
207
208
    /**
209
     * @param \SimpleSAML\SAML2\XML\saml\Conditions|null $conditions
210
     */
211
    private function setConditions(?Conditions $conditions): void
212
    {
213
        $this->conditions = $conditions;
214
    }
215
216
217
    /**
218
     * @return \SimpleSAML\SAML2\XML\saml\Conditions|null
219
     */
220
    public function getConditions(): ?Conditions
221
    {
222
        return $this->conditions;
223
    }
224
225
226
    /**
227
     * Retrieve the NameIdPolicy.
228
     *
229
     * @see \SimpleSAML\SAML2\AuthnRequest::setNameIdPolicy()
230
     * @return \SimpleSAML\SAML2\XML\samlp\NameIDPolicy|null The NameIdPolicy.
231
     */
232
    public function getNameIdPolicy(): ?NameIDPolicy
233
    {
234
        return $this->nameIdPolicy;
235
    }
236
237
238
    /**
239
     * Set the NameIDPolicy.
240
     *
241
     * @param \SimpleSAML\SAML2\XML\samlp\NameIDPolicy|null $nameIdPolicy The NameIDPolicy.
242
     */
243
    private function setNameIdPolicy(?NameIDPolicy $nameIdPolicy): void
244
    {
245
        $this->nameIdPolicy = $nameIdPolicy;
246
    }
247
248
249
    /**
250
     * Retrieve the value of the ForceAuthn attribute.
251
     *
252
     * @return bool|null The ForceAuthn attribute.
253
     */
254
    public function getForceAuthn(): ?bool
255
    {
256
        return $this->forceAuthn;
257
    }
258
259
260
    /**
261
     * Set the value of the ForceAuthn attribute.
262
     *
263
     * @param bool $forceAuthn The ForceAuthn attribute.
264
     */
265
    private function setForceAuthn(?bool $forceAuthn): void
266
    {
267
        $this->forceAuthn = $forceAuthn;
268
    }
269
270
271
    /**
272
     * Retrieve the value of the ProviderName attribute.
273
     *
274
     * @return string|null The ProviderName attribute.
275
     */
276
    public function getProviderName(): ?string
277
    {
278
        return $this->ProviderName;
279
    }
280
281
282
    /**
283
     * Set the value of the ProviderName attribute.
284
     *
285
     * @param string|null $ProviderName The ProviderName attribute.
286
     */
287
    private function setProviderName(?string $ProviderName): void
288
    {
289
        Assert::nullOrNotWhitespaceOnly($ProviderName);
290
        $this->ProviderName = $ProviderName;
291
    }
292
293
294
    /**
295
     * Retrieve the value of the IsPassive attribute.
296
     *
297
     * @return bool|null The IsPassive attribute.
298
     */
299
    public function getIsPassive(): ?bool
300
    {
301
        return $this->isPassive;
302
    }
303
304
305
    /**
306
     * Set the value of the IsPassive attribute.
307
     *
308
     * @param bool|null $isPassive The IsPassive attribute.
309
     */
310
    private function setIsPassive(?bool $isPassive): void
311
    {
312
        $this->isPassive = $isPassive;
313
    }
314
315
316
    /**
317
     * Retrieve the value of the AssertionConsumerServiceURL attribute.
318
     *
319
     * @return string|null The AssertionConsumerServiceURL attribute.
320
     */
321
    public function getAssertionConsumerServiceURL(): ?string
322
    {
323
        return $this->assertionConsumerServiceURL;
324
    }
325
326
327
    /**
328
     * Set the value of the AssertionConsumerServiceURL attribute.
329
     *
330
     * @param string|null $assertionConsumerServiceURL The AssertionConsumerServiceURL attribute.
331
     */
332
    private function setAssertionConsumerServiceURL(string $assertionConsumerServiceURL = null): void
333
    {
334
        if (!is_null($assertionConsumerServiceURL) && !filter_var($assertionConsumerServiceURL, FILTER_VALIDATE_URL)) {
335
            throw new InvalidArgumentException('AuthnRequest AssertionConsumerServiceURL is not a valid URL.');
336
        }
337
338
        $this->assertionConsumerServiceURL = $assertionConsumerServiceURL;
339
    }
340
341
342
    /**
343
     * Retrieve the value of the ProtocolBinding attribute.
344
     *
345
     * @return string|null The ProtocolBinding attribute.
346
     */
347
    public function getProtocolBinding(): ?string
348
    {
349
        return $this->protocolBinding;
350
    }
351
352
353
    /**
354
     * Set the value of the ProtocolBinding attribute.
355
     *
356
     * @param string|null $protocolBinding The ProtocolBinding attribute.
357
     */
358
    private function setProtocolBinding(?string $protocolBinding): void
359
    {
360
        Assert::nullOrNotWhitespaceOnly($protocolBinding);
361
362
        $this->protocolBinding = $protocolBinding;
363
    }
364
365
366
    /**
367
     * Retrieve the value of the AttributeConsumingServiceIndex attribute.
368
     *
369
     * @return int|null The AttributeConsumingServiceIndex attribute.
370
     */
371
    public function getAttributeConsumingServiceIndex(): ?int
372
    {
373
        return $this->attributeConsumingServiceIndex;
374
    }
375
376
377
    /**
378
     * Set the value of the AttributeConsumingServiceIndex attribute.
379
     *
380
     * @param int|null $attributeConsumingServiceIndex The AttributeConsumingServiceIndex attribute.
381
     */
382
    private function setAttributeConsumingServiceIndex(?int $attributeConsumingServiceIndex): void
383
    {
384
        Assert::nullOrRange($attributeConsumingServiceIndex, 0, 65535);
385
        $this->attributeConsumingServiceIndex = $attributeConsumingServiceIndex;
386
    }
387
388
389
    /**
390
     * Retrieve the value of the AssertionConsumerServiceIndex attribute.
391
     *
392
     * @return int|null The AssertionConsumerServiceIndex attribute.
393
     */
394
    public function getAssertionConsumerServiceIndex(): ?int
395
    {
396
        return $this->assertionConsumerServiceIndex;
397
    }
398
399
400
    /**
401
     * Set the value of the AssertionConsumerServiceIndex attribute.
402
     *
403
     * @param int|null $assertionConsumerServiceIndex The AssertionConsumerServiceIndex attribute.
404
     */
405
    private function setAssertionConsumerServiceIndex(?int $assertionConsumerServiceIndex): void
406
    {
407
        Assert::nullOrRange($assertionConsumerServiceIndex, 0, 65535);
408
        $this->assertionConsumerServiceIndex = $assertionConsumerServiceIndex;
409
    }
410
411
412
    /**
413
     * Retrieve the RequestedAuthnContext.
414
     *
415
     * @return \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext|null The RequestedAuthnContext.
416
     */
417
    public function getRequestedAuthnContext(): ?RequestedAuthnContext
418
    {
419
        return $this->requestedAuthnContext;
420
    }
421
422
423
    /**
424
     * Set the RequestedAuthnContext.
425
     *
426
     * @param \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext|null $requestedAuthnContext The RequestedAuthnContext.
427
     */
428
    private function setRequestedAuthnContext(RequestedAuthnContext $requestedAuthnContext = null): void
429
    {
430
        $this->requestedAuthnContext = $requestedAuthnContext;
431
    }
432
433
434
    /**
435
     * Convert XML into an AuthnRequest
436
     *
437
     * @param \DOMElement $xml The XML element we should load
438
     * @return \SimpleSAML\SAML2\XML\samlp\AuthnRequest
439
     *
440
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
441
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
442
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
443
     */
444
    public static function fromXML(DOMElement $xml): object
445
    {
446
        Assert::same($xml->localName, 'AuthnRequest', InvalidDOMElementException::class);
447
        Assert::same($xml->namespaceURI, AuthnRequest::NS, InvalidDOMElementException::class);
448
        Assert::same('2.0', self::getAttribute($xml, 'Version'));
449
450
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
451
        Assert::validDateTimeZulu($issueInstant, ProtocolViolationException::class);
452
        $issueInstant = XMLUtils::xsDateTimeToTimestamp($issueInstant);
453
454
        $attributeConsumingServiceIndex = self::getIntegerAttribute($xml, 'AttributeConsumingServiceIndex', null);
455
        $assertionConsumerServiceIndex = self::getIntegerAttribute($xml, 'AssertionConsumerServiceIndex', null);
456
457
        $conditions = Conditions::getChildrenOfClass($xml);
458
        Assert::maxCount($conditions, 1, 'Only one <saml:Conditions> element is allowed.', TooManyElementsException::class);
459
460
        $nameIdPolicy = NameIDPolicy::getChildrenOfClass($xml);
461
        Assert::maxCount($nameIdPolicy, 1, 'Only one <samlp:NameIDPolicy> element is allowed.', TooManyElementsException::class);
462
463
        $subject = Subject::getChildrenOfClass($xml);
464
        Assert::maxCount($subject, 1, 'Only one <saml:Subject> element is allowed.', TooManyElementsException::class);
465
466
        $issuer = Issuer::getChildrenOfClass($xml);
467
        Assert::maxCount($issuer, 1, 'Only one <saml:Issuer> element is allowed.', TooManyElementsException::class);
468
469
        $requestedAuthnContext = RequestedAuthnContext::getChildrenOfClass($xml);
470
        Assert::maxCount(
471
            $requestedAuthnContext,
472
            1,
473
            'Only one <samlp:RequestedAuthnContext> element is allowed.',
474
            TooManyElementsException::class
475
        );
476
477
        $extensions = Extensions::getChildrenOfClass($xml);
478
        Assert::maxCount($extensions, 1, 'Only one <samlp:Extensions> element is allowed.', TooManyElementsException::class);
479
480
        $signature = Signature::getChildrenOfClass($xml);
481
        Assert::maxCount($signature, 1, 'Only one <ds:Signature> element is allowed.', TooManyElementsException::class);
482
483
        $scoping = Scoping::getChildrenOfClass($xml);
484
        Assert::maxCount($scoping, 1, 'Only one <samlp:Scoping> element is allowed.', TooManyElementsException::class);
485
486
        $request = new self(
487
            array_pop($requestedAuthnContext),
488
            array_pop($subject),
489
            array_pop($nameIdPolicy),
490
            array_pop($conditions),
491
            self::getBooleanAttribute($xml, 'ForceAuthn', null),
492
            self::getBooleanAttribute($xml, 'IsPassive', null),
493
            self::getAttribute($xml, 'AssertionConsumerServiceURL', null),
494
            $assertionConsumerServiceIndex,
495
            self::getAttribute($xml, 'ProtocolBinding', null),
496
            $attributeConsumingServiceIndex,
497
            self::getAttribute($xml, 'ProviderName', null),
498
            array_pop($issuer),
499
            self::getAttribute($xml, 'ID'),
500
            $issueInstant,
501
            self::getAttribute($xml, 'Destination', null),
502
            self::getAttribute($xml, 'Consent', null),
503
            array_pop($extensions),
504
            array_pop($scoping)
505
        );
506
507
        if (!empty($signature)) {
508
            $request->setSignature($signature[0]);
509
            $request->messageContainedSignatureUponConstruction = true;
510
        }
511
512
        $request->setXML($xml);
513
        return $request;
514
    }
515
516
517
    /**
518
     * Convert this message to an unsigned XML document.
519
     * This method does not sign the resulting XML document.
520
     *
521
     * @param \DOMElement|null $parent
522
     * @return \DOMElement The root element of the DOM tree
523
     */
524
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
525
    {
526
        $e = parent::toUnsignedXML($parent);
527
528
        if ($this->forceAuthn === true) {
529
            $e->setAttribute('ForceAuthn', 'true');
530
        }
531
532
        if (!empty($this->ProviderName)) {
533
            $e->setAttribute('ProviderName', $this->ProviderName);
534
        }
535
536
        if ($this->isPassive === true) {
537
            $e->setAttribute('IsPassive', 'true');
538
        }
539
540
        if ($this->assertionConsumerServiceIndex !== null) {
541
            $e->setAttribute('AssertionConsumerServiceIndex', strval($this->assertionConsumerServiceIndex));
542
        } else {
543
            if ($this->assertionConsumerServiceURL !== null) {
544
                $e->setAttribute('AssertionConsumerServiceURL', $this->assertionConsumerServiceURL);
545
            }
546
            if ($this->protocolBinding !== null) {
547
                $e->setAttribute('ProtocolBinding', $this->protocolBinding);
548
            }
549
        }
550
551
        if ($this->attributeConsumingServiceIndex !== null) {
552
            $e->setAttribute('AttributeConsumingServiceIndex', strval($this->attributeConsumingServiceIndex));
553
        }
554
555
        if ($this->subject !== null) {
556
            $this->subject->toXML($e);
557
        }
558
559
        if ($this->nameIdPolicy !== null) {
560
            if (!$this->nameIdPolicy->isEmptyElement()) {
561
                $this->nameIdPolicy->toXML($e);
562
            }
563
        }
564
565
        if ($this->conditions !== null) {
566
            if (!$this->conditions->isEmptyElement()) {
567
                $this->conditions->toXML($e);
568
            }
569
        }
570
571
        if (!empty($this->requestedAuthnContext)) {
572
            $this->requestedAuthnContext->toXML($e);
573
        }
574
575
        if ($this->scoping !== null) {
576
            if (!$this->scoping->isEmptyElement()) {
577
                $this->scoping->toXML($e);
578
            }
579
        }
580
581
        return $e;
582
    }
583
}
584