Passed
Pull Request — master (#226)
by Jaime Pérez
02:19
created

AuthnRequest::setConditions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SAML2\XML\samlp;
6
7
use DOMDocument;
8
use DOMElement;
9
use Exception;
10
use RobRichards\XMLSecLibs\XMLSecEnc;
11
use RobRichards\XMLSecLibs\XMLSecurityKey;
12
use SAML2\Constants;
13
use SAML2\Exception\InvalidArgumentException;
14
use SAML2\XML\ds\Signature;
15
use SAML2\XML\saml\Conditions;
16
use SAML2\XML\saml\Issuer;
17
use SAML2\XML\saml\NameID;
18
use SAML2\XML\saml\Subject;
19
use SAML2\XML\saml\SubjectConfirmation;
20
use SAML2\Utils;
21
use Webmozart\Assert\Assert;
22
23
/**
24
 * Class for SAML 2 authentication request messages.
25
 *
26
 * @package SimpleSAMLphp
27
 */
28
class AuthnRequest extends AbstractRequest
29
{
30
    /**
31
     * @var \SAML2\XML\saml\Subject|null
32
     */
33
    protected $subject = null;
34
35
    /**
36
     * @var \SAML2\XML\saml\Scoping|null
0 ignored issues
show
Bug introduced by
The type SAML2\XML\saml\Scoping was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
     */
38
    protected $scoping = null;
39
40
    /**
41
     * The options for what type of name identifier should be returned.
42
     *
43
     * @var \SAML2\XML\samlp\NameIDPolicy|null
44
     */
45
    protected $nameIdPolicy = null;
46
47
    /**
48
     * Whether the Identity Provider must authenticate the user again.
49
     *
50
     * @var bool|null
51
     */
52
    protected $forceAuthn = false;
53
54
    /**
55
     * Optional ProviderID attribute
56
     *
57
     * @var string|null
58
     */
59
    protected $ProviderName = null;
60
61
    /**
62
     * Set to true if this request is passive.
63
     *
64
     * @var bool|null
65
     */
66
    protected $isPassive = false;
67
68
    /**
69
     * The URL of the assertion consumer service where the response should be delivered.
70
     *
71
     * @var string|null
72
     */
73
    protected $assertionConsumerServiceURL;
74
75
    /**
76
     * What binding should be used when sending the response.
77
     *
78
     * @var string|null
79
     */
80
    protected $protocolBinding;
81
82
    /**
83
     * The index of the AttributeConsumingService.
84
     *
85
     * @var int|null
86
     */
87
    protected $attributeConsumingServiceIndex;
88
89
    /**
90
     * The index of the AssertionConsumerService.
91
     *
92
     * @var int|null
93
     */
94
    protected $assertionConsumerServiceIndex;
95
96
    /**
97
     * What authentication context was requested.
98
     *
99
     * @var \SAML2\XML\samlp\RequestedAuthnContext|null
100
     */
101
    protected $requestedAuthnContext;
102
103
    /**
104
     * @var \SAML2\XML\saml\Conditions|null
105
     */
106
    protected $conditions = null;
107
108
    /**
109
     * @var \SAML2\XML\saml\SubjectConfirmation[]
110
     */
111
    protected $subjectConfirmation = [];
112
113
114
    /**
115
     * Constructor for SAML 2 AuthnRequest
116
     *
117
     * @param \SAML2\XML\samlp\RequestedAuthnContext $requestedAuthnContext
118
     * @param \SAML2\XML\saml\Subject $subject
119
     * @param \SAML2\XML\samlp\NameIDPolicy $nameIdPolicy
120
     * @param \SAML2\XML\saml\Conditions $conditions
121
     * @param bool $forceAuthn
122
     * @param bool $isPassive
123
     * @param string $assertionConsumerServiceUrl
124
     * @param string $protocolBinding
125
     * @param int $attributeConsumingServiceIndex
126
     * @param string $providerName
127
     * @param \SAML2\XML\saml\Issuer|null $issuer
128
     * @param string|null $id
129
     * @param string|null $version
130
     * @param int|null $issueInstant
131
     * @param string|null $destination
132
     * @param string|null $consent
133
     * @param \SAML2\XML\samlp\Extensions|null $extensions
134
     * @param \SAML2\XML\samlp\Scoping|null $scoping
135
     */
136
    public function __construct(
137
        ?RequestedAuthnContext $requestedAuthnContext = null,
138
        ?Subject $subject = null,
139
        ?NameIDPolicy $nameIdPolicy = null,
140
        Conditions $conditions = null,
141
142
        ?bool $forceAuthn = null,
143
        ?bool $isPassive = null,
144
        ?string $assertionConsumerServiceUrl = null,
145
        ?string $protocolBinding = null,
146
        ?int $attributeConsumingServiceIndex = null,
147
        ?string $providerName = null,
148
149
        ?Issuer $issuer = null,
150
        ?string $id = null,
151
        ?string $version = null,
152
        ?int $issueInstant = null,
153
        ?string $destination = null,
154
        ?string $consent = null,
155
        ?Extensions $extensions = null,
156
        ?Scoping $scoping = null
157
    ) {
158
        parent::__construct($issuer, $id, $version, $issueInstant, $destination, $consent, $extensions);
159
160
        $this->setRequestedAuthnContext($requestedAuthnContext);
161
        $this->setSubject($subject);
162
        $this->setNameIdPolicy($nameIdPolicy);
163
        $this->setConditions($conditions);
164
165
        $this->setForceAuthn($forceAuthn);
166
        $this->setIsPassive($isPassive);
167
        $this->setAssertionConsumerServiceUrl($assertionConsumerServiceUrl);
168
        $this->setProtocolBinding($protocolBinding);
169
        $this->setAttributeConsumingServiceIndex($attributeConsumingServiceIndex);
170
        $this->setProviderName($providerName);
171
        $this->setScoping($scoping);
172
    }
173
174
175
    /**
176
     * @param \SAML2\XML\saml\Subject|null $subject
177
     * @return void
178
     */
179
    private function setSubject(?Subject $subject): void
180
    {
181
        $this->subject = $subject;
182
    }
183
184
185
    /**
186
     * @return \SAML2\XML\saml\Subject|null
187
     */
188
    public function getSubject(): ?Subject
189
    {
190
        return $this->subject;
191
    }
192
193
194
    /**
195
     * @param \SAML2\XML\saml\Scoping|null $scoping
196
     * @return void
197
     */
198
    private function setScoping(?Scoping $scoping): void
199
    {
200
        $this->scoping = $scoping;
0 ignored issues
show
Documentation Bug introduced by
It seems like $scoping can also be of type SAML2\XML\samlp\Scoping. However, the property $scoping is declared as type SAML2\XML\saml\Scoping|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
201
    }
202
203
204
    /**
205
     * @return \SAML2\XML\saml\Scoping|null
206
     */
207
    public function getScoping(): ?Scoping
208
    {
209
        return $this->scoping;
210
    }
211
212
213
    /**
214
     * @param \SAML2\XML\saml\Conditions|null $conditions
215
     * @return void
216
     */
217
    private function setConditions(?Conditions $conditions): void
218
    {
219
        $this->conditions = $conditions;
220
    }
221
222
223
    /**
224
     * @return \SAML2\XML\saml\Conditions|null
225
     */
226
    public function getConditions(): ?Conditions
227
    {
228
        return $this->conditions;
229
    }
230
231
232
    /**
233
     * Retrieve the NameIdPolicy.
234
     *
235
     * @see \SAML2\AuthnRequest::setNameIdPolicy()
236
     * @return \SAML2\XML\samlp\NameIDPolicy|null The NameIdPolicy.
237
     */
238
    public function getNameIdPolicy(): ?NameIDPolicy
239
    {
240
        return $this->nameIdPolicy;
241
    }
242
243
244
    /**
245
     * Set the NameIDPolicy.
246
     *
247
     * @param \SAML2\XML\samlp\NameIDPolicy|null $nameIdPolicy The NameIDPolicy.
248
     * @return void
249
     */
250
    private function setNameIdPolicy(?NameIDPolicy $nameIdPolicy): void
251
    {
252
        $this->nameIdPolicy = $nameIdPolicy;
253
    }
254
255
256
    /**
257
     * Retrieve the value of the ForceAuthn attribute.
258
     *
259
     * @return bool|null The ForceAuthn attribute.
260
     */
261
    public function getForceAuthn(): ?bool
262
    {
263
        return $this->forceAuthn;
264
    }
265
266
267
    /**
268
     * Set the value of the ForceAuthn attribute.
269
     *
270
     * @param bool $forceAuthn The ForceAuthn attribute.
271
     * @return void
272
     */
273
    private function setForceAuthn(?bool $forceAuthn): void
274
    {
275
        $this->forceAuthn = $forceAuthn;
276
    }
277
278
279
    /**
280
     * Retrieve the value of the ProviderName attribute.
281
     *
282
     * @return string|null The ProviderName attribute.
283
     */
284
    public function getProviderName(): ?string
285
    {
286
        return $this->ProviderName;
287
    }
288
289
290
    /**
291
     * Set the value of the ProviderName attribute.
292
     *
293
     * @param string|null $ProviderName The ProviderName attribute.
294
     * @return void
295
     */
296
    private function setProviderName(?string $ProviderName): void
297
    {
298
        $this->ProviderName = $ProviderName;
299
    }
300
301
302
    /**
303
     * Retrieve the value of the IsPassive attribute.
304
     *
305
     * @return bool|null The IsPassive attribute.
306
     */
307
    public function getIsPassive(): ?bool
308
    {
309
        return $this->isPassive;
310
    }
311
312
313
    /**
314
     * Set the value of the IsPassive attribute.
315
     *
316
     * @param bool|null $isPassive The IsPassive attribute.
317
     * @return void
318
     */
319
    private function setIsPassive(?bool $isPassive): void
320
    {
321
        $this->isPassive = $isPassive;
322
    }
323
324
325
    /**
326
     * Retrieve the value of the AssertionConsumerServiceURL attribute.
327
     *
328
     * @return string|null The AssertionConsumerServiceURL attribute.
329
     */
330
    public function getAssertionConsumerServiceURL(): ?string
331
    {
332
        return $this->assertionConsumerServiceURL;
333
    }
334
335
336
    /**
337
     * Set the value of the AssertionConsumerServiceURL attribute.
338
     *
339
     * @param string|null $assertionConsumerServiceURL The AssertionConsumerServiceURL attribute.
340
     * @return void
341
     */
342
    private function setAssertionConsumerServiceURL(string $assertionConsumerServiceURL = null): void
343
    {
344
        $this->assertionConsumerServiceURL = $assertionConsumerServiceURL;
345
    }
346
347
348
    /**
349
     * Retrieve the value of the ProtocolBinding attribute.
350
     *
351
     * @return string|null The ProtocolBinding attribute.
352
     */
353
    public function getProtocolBinding(): ?string
354
    {
355
        return $this->protocolBinding;
356
    }
357
358
359
    /**
360
     * Set the value of the ProtocolBinding attribute.
361
     *
362
     * @param string $protocolBinding The ProtocolBinding attribute.
363
     * @return void
364
     */
365
    private function setProtocolBinding(string $protocolBinding = null): void
366
    {
367
        $this->protocolBinding = $protocolBinding;
368
    }
369
370
371
    /**
372
     * Retrieve the value of the AttributeConsumingServiceIndex attribute.
373
     *
374
     * @return int|null The AttributeConsumingServiceIndex attribute.
375
     */
376
    public function getAttributeConsumingServiceIndex(): ?int
377
    {
378
        return $this->attributeConsumingServiceIndex;
379
    }
380
381
382
    /**
383
     * Set the value of the AttributeConsumingServiceIndex attribute.
384
     *
385
     * @param int|null $attributeConsumingServiceIndex The AttributeConsumingServiceIndex attribute.
386
     * @return void
387
     */
388
    private function setAttributeConsumingServiceIndex(int $attributeConsumingServiceIndex = null): void
389
    {
390
        $this->attributeConsumingServiceIndex = $attributeConsumingServiceIndex;
391
    }
392
393
394
    /**
395
     * Retrieve the value of the AssertionConsumerServiceIndex attribute.
396
     *
397
     * @return int|null The AssertionConsumerServiceIndex attribute.
398
     */
399
    public function getAssertionConsumerServiceIndex(): ?int
400
    {
401
        return $this->assertionConsumerServiceIndex;
402
    }
403
404
405
    /**
406
     * Set the value of the AssertionConsumerServiceIndex attribute.
407
     *
408
     * @param int|null $assertionConsumerServiceIndex The AssertionConsumerServiceIndex attribute.
409
     * @return void
410
     */
411
    private function setAssertionConsumerServiceIndex(int $assertionConsumerServiceIndex = null): void
0 ignored issues
show
Unused Code introduced by
The method setAssertionConsumerServiceIndex() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
412
    {
413
        $this->assertionConsumerServiceIndex = $assertionConsumerServiceIndex;
414
    }
415
416
417
    /**
418
     * Retrieve the RequestedAuthnContext.
419
     *
420
     * @return \SAML2\XML\samlp\RequestedAuthnContext|null The RequestedAuthnContext.
421
     */
422
    public function getRequestedAuthnContext(): ?RequestedAuthnContext
423
    {
424
        return $this->requestedAuthnContext;
425
    }
426
427
428
    /**
429
     * Set the RequestedAuthnContext.
430
     *
431
     * @param \SAML2\XML\samlp\RequestedAuthnContext|null $requestedAuthnContext The RequestedAuthnContext.
432
     * @return void
433
     */
434
    private function setRequestedAuthnContext(RequestedAuthnContext $requestedAuthnContext = null): void
435
    {
436
        $this->requestedAuthnContext = $requestedAuthnContext;
437
    }
438
439
440
    /**
441
     * Retrieve the SubjectConfirmation elements we have in our Subject element.
442
     *
443
     * @return \SAML2\XML\saml\SubjectConfirmation[]
444
     */
445
    public function getSubjectConfirmation(): array
446
    {
447
        return $this->subjectConfirmation;
448
    }
449
450
451
    /**
452
     * Set the SubjectConfirmation elements that should be included in the assertion.
453
     *
454
     * @param array \SAML2\XML\saml\SubjectConfirmation[]
455
     * @return void
456
     */
457
    private function setSubjectConfirmation(array $subjectConfirmation): void
0 ignored issues
show
Unused Code introduced by
The method setSubjectConfirmation() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
458
    {
459
        $this->subjectConfirmation = $subjectConfirmation;
460
    }
461
462
463
    /**
464
     * Convert XML into an AuthnRequest
465
     *
466
     * @param \DOMElement $xml The XML element we should load
467
     * @return \SAML2\XML\samlp\AuthnRequest
468
     * @throws \InvalidArgumentException if the qualified name of the supplied element is wrong
469
     */
470
    public static function fromXML(DOMElement $xml): object
471
    {
472
        Assert::same($xml->localName, 'AuthnRequest');
473
        Assert::same($xml->namespaceURI, AuthnRequest::NS);
474
475
        $id = self::getAttribute($xml, 'ID');
476
        $version = self::getAttribute($xml, 'Version');
477
        $issueInstant = Utils::xsDateTimeToTimestamp(self::getAttribute($xml, 'IssueInstant'));
478
        $inResponseTo = self::getAttribute($xml, 'InResponseTo', null);
0 ignored issues
show
Unused Code introduced by
The assignment to $inResponseTo is dead and can be removed.
Loading history...
479
        $destination = self::getAttribute($xml, 'Destination', null);
480
        $consent = self::getAttribute($xml, 'Consent', null);
481
482
        $forceAuthn = self::getBooleanAttribute($xml, 'ForceAuthn', 'false');
483
        $isPassive = self::getBooleanAttribute($xml, 'IsPassive', 'false');
484
485
        $assertionConsumerServiceUrl = self::getAttribute($xml, 'AssertionConsumerServiceURL', null);
486
        $protocolBinding = self::getAttribute($xml, 'ProtocolBinding', null);
487
488
        $attributeConsumingServiceIndex = self::getAttribute($xml, 'AttributeConsumingServiceIndex', null);
489
        if ($attributeConsumingServiceIndex !== null) {
490
            $attributeConsumingServiceIndex = intval($attributeConsumingServiceIndex);
491
        }
492
493
        $assertionConsumerServiceIndex = self::getAttribute($xml, 'AssertionConsumerServiceIndex', null);
494
        if ($assertionConsumerServiceIndex !== null) {
495
            $assertionConsumerServiceIndex = intval($assertionConsumerServiceIndex);
0 ignored issues
show
Unused Code introduced by
The assignment to $assertionConsumerServiceIndex is dead and can be removed.
Loading history...
496
        }
497
498
        $providerName = self::getAttribute($xml, 'ProviderName', null);
499
500
        $conditions = Conditions::getChildrenOfClass($xml);
501
        Assert::maxCount($conditions, 1, 'Only one <saml:Conditions> element is allowed.');
502
503
        $nameIdPolicy = NameIDPolicy::getChildrenOfClass($xml);
504
        Assert::maxCount($nameIdPolicy, 1, 'Only one <samlp:NameIDPolicy> element is allowed.');
505
506
        $subject = Subject::getChildrenOfClass($xml);
507
        Assert::maxCount($subject, 1, 'Only one <saml:Subject> element is allowed.');
508
509
        $issuer = Issuer::getChildrenOfClass($xml);
510
        Assert::maxCount($issuer, 1, 'Only one <saml:Issuer> element is allowed.');
511
512
        $requestedAuthnContext = RequestedAuthnContext::getChildrenOfClass($xml);
513
        Assert::maxCount($requestedAuthnContext, 1, 'Only one <samlp:RequestedAuthnContext> element is allowed.');
514
515
        $extensions = Extensions::getChildrenOfClass($xml);
516
        Assert::maxCount($extensions, 1, 'Only one <samlp:Extensions> element is allowed.');
517
518
        $signature = Signature::getChildrenOfClass($xml);
519
        Assert::maxCount($signature, 1, 'Only one <ds:Signature> element is allowed.');
520
521
        $scoping = Scoping::getChildrenOfClass($xml);
522
        Assert::maxCount($scoping, 1, 'Only one <samlp:Scoping> element is allowed.');
523
524
525
        $request = new self(
526
            array_pop($requestedAuthnContext),
527
            array_pop($subject),
528
            array_pop($nameIdPolicy),
529
            array_pop($conditions),
530
531
            $forceAuthn,
532
            $isPassive,
533
            $assertionConsumerServiceUrl,
534
            $protocolBinding,
535
            $attributeConsumingServiceIndex,
536
            $providerName,
537
538
            array_pop($issuer),
539
            $id,
540
            $version,
541
            $issueInstant,
542
            $destination,
543
            $consent,
544
            array_pop($extensions),
545
            array_pop($scoping)
546
        );
547
548
        if (!empty($signature)) {
549
            $request->setSignature($signature[0]);
550
            $request->messageContainedSignatureUponConstruction = true;
551
        }
552
553
        return $request;
554
555
    }
556
557
558
    /**
559
     * Convert this authentication request to an XML element.
560
     *
561
     * @return \DOMElement This authentication request.
562
     */
563
    public function toXML(?DOMElement $parent = null): DOMElement
564
    {
565
        Assert::null($parent);
566
567
        $parent = parent::toXML($parent);
568
569
        if ($this->forceAuthn) {
570
            $parent->setAttribute('ForceAuthn', 'true');
571
        }
572
573
        if (!empty($this->ProviderName)) {
574
            $parent->setAttribute('ProviderName', $this->ProviderName);
575
        }
576
577
        if ($this->isPassive) {
578
            $parent->setAttribute('IsPassive', 'true');
579
        }
580
581
        if ($this->assertionConsumerServiceIndex !== null) {
582
            $parent->setAttribute('AssertionConsumerServiceIndex', strval($this->assertionConsumerServiceIndex));
583
        } else {
584
            if ($this->assertionConsumerServiceURL !== null) {
585
                $parent->setAttribute('AssertionConsumerServiceURL', $this->assertionConsumerServiceURL);
586
            }
587
            if ($this->protocolBinding !== null) {
588
                $parent->setAttribute('ProtocolBinding', $this->protocolBinding);
589
            }
590
        }
591
592
        if ($this->attributeConsumingServiceIndex !== null) {
593
            $parent->setAttribute('AttributeConsumingServiceIndex', strval($this->attributeConsumingServiceIndex));
594
        }
595
596
        if ($this->subject !== null) {
597
            $this->subject->toXML($parent);
598
        }
599
600
        if ($this->nameIdPolicy !== null) {
601
            if (!$this->nameIdPolicy->isEmptyElement()) {
602
                $this->nameIdPolicy->toXML($parent);
603
            }
604
        }
605
606
        if ($this->conditions !== null) {
607
            if (!$this->conditions->isEmptyElement()) {
608
                $this->conditions->toXML($parent);
609
            }
610
        }
611
612
        if (!empty($this->requestedAuthnContext)) {
613
            $this->requestedAuthnContext->toXML($parent);
614
        }
615
616
        if ($this->scoping !== null) {
617
            if (!$this->scoping->isEmptyElement()) {
618
                $this->scoping->toXML($parent);
619
            }
620
        }
621
622
        return $this->signElement($parent);
623
    }
624
}
625