Completed
Push — master ( 4e360d...80bc96 )
by Daan van
07:27
created

AuthnRequest::setProtocolBinding()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace SAML2;
4
5
use RobRichards\XMLSecLibs\XMLSecEnc;
6
use RobRichards\XMLSecLibs\XMLSecurityKey;
7
use SAML2\XML\saml\SubjectConfirmation;
8
9
/**
10
 * Class for SAML 2 authentication request messages.
11
 *
12
 * @package SimpleSAMLphp
13
 */
14
class AuthnRequest extends Request
15
{
16
    /**
17
     * The options for what type of name identifier should be returned.
18
     *
19
     * @var array
20
     */
21
    private $nameIdPolicy;
22
23
    /**
24
     * Whether the Identity Provider must authenticate the user again.
25
     *
26
     * @var bool
27
     */
28
    private $forceAuthn;
29
30
31
    /**
32
     * Optional ProviderID attribute
33
     *
34
     * @var string
35
     */
36
    private $ProviderName;
37
38
39
    /**
40
     * Set to true if this request is passive.
41
     *
42
     * @var bool.
43
     */
44
    private $isPassive;
45
46
    /**
47
     * The list of providerIDs in this request's scoping element
48
     *
49
     * @var array
50
     */
51
    private $IDPList = array();
52
53
    /**
54
     * The ProxyCount in this request's scoping element
55
     *
56
     * @var int
57
     */
58
    private $ProxyCount = null;
59
60
    /**
61
     * The RequesterID list in this request's scoping element
62
     *
63
     * @var array
64
     */
65
66
    private $RequesterID = array();
67
68
    /**
69
     * The URL of the asertion consumer service where the response should be delivered.
70
     *
71
     * @var string|null
72
     */
73
    private $assertionConsumerServiceURL;
74
75
76
    /**
77
     * What binding should be used when sending the response.
78
     *
79
     * @var string|null
80
     */
81
    private $protocolBinding;
82
83
84
    /**
85
     * The index of the AttributeConsumingService.
86
     *
87
     * @var int|null
88
     */
89
    private $attributeConsumingServiceIndex;
90
91
    /**
92
     * The index of the AssertionConsumerService.
93
     *
94
     * @var int|null
95
     */
96
    private $assertionConsumerServiceIndex;
97
98
99
    /**
100
     * What authentication context was requested.
101
     *
102
     * Array with the following elements.
103
     * - AuthnContextClassRef (required)
104
     * - Comparison (optinal)
105
     *
106
     * @var array
107
     */
108
    private $requestedAuthnContext;
109
110
    /**
111
     * @var \SAML2\XML\saml\SubjectConfirmation[]
112
     */
113
    private $subjectConfirmation = array();
114
115
    /**
116
     * @var string
117
     */
118
    private $encryptedNameId;
119
120
    /**
121
     * @var string
122
     */
123
    private $nameId;
124
125
    /**
126
     * Constructor for SAML 2 authentication request messages.
127
     *
128
     * @param \DOMElement|null $xml The input message.
129
     * @throws \Exception
130
     */
131
    public function __construct(\DOMElement $xml = null)
132
    {
133
        parent::__construct('AuthnRequest', $xml);
134
135
        $this->nameIdPolicy = array();
136
        $this->forceAuthn = false;
137
        $this->isPassive = false;
138
139
        if ($xml === null) {
140
            return;
141
        }
142
143
        $this->forceAuthn = Utils::parseBoolean($xml, 'ForceAuthn', false);
144
        $this->isPassive = Utils::parseBoolean($xml, 'IsPassive', false);
145
146
        if ($xml->hasAttribute('AssertionConsumerServiceURL')) {
147
            $this->assertionConsumerServiceURL = $xml->getAttribute('AssertionConsumerServiceURL');
148
        }
149
150
        if ($xml->hasAttribute('ProtocolBinding')) {
151
            $this->protocolBinding = $xml->getAttribute('ProtocolBinding');
152
        }
153
154
        if ($xml->hasAttribute('AttributeConsumingServiceIndex')) {
155
            $this->attributeConsumingServiceIndex = (int) $xml->getAttribute('AttributeConsumingServiceIndex');
156
        }
157
158
        if ($xml->hasAttribute('AssertionConsumerServiceIndex')) {
159
            $this->assertionConsumerServiceIndex = (int) $xml->getAttribute('AssertionConsumerServiceIndex');
160
        }
161
162
        $this->parseSubject($xml);
163
        $this->parseNameIdPolicy($xml);
164
        $this->parseRequestedAuthnContext($xml);
165
        $this->parseScoping($xml);
166
    }
167
168
    /**
169
     * @param $xml
170
     *
171
     * @throws \Exception
172
     */
173 View Code Duplication
    private function parseSubject(\DOMElement $xml)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
174
    {
175
        $subject = Utils::xpQuery($xml, './saml_assertion:Subject');
176
        if (empty($subject)) {
177
            return;
178
        }
179
180
        if (count($subject) > 1) {
181
            throw new \Exception('More than one <saml:Subject> in <saml:AuthnRequest>.');
182
        }
183
        $subject = $subject[0];
184
185
        $nameId = Utils::xpQuery(
186
            $subject,
187
            './saml_assertion:NameID | ./saml_assertion:EncryptedID/xenc:EncryptedData'
188
        );
189
        if (empty($nameId)) {
190
            throw new \Exception('Missing <saml:NameID> or <saml:EncryptedID> in <saml:Subject>.');
191
        } elseif (count($nameId) > 1) {
192
            throw new \Exception('More than one <saml:NameID> or <saml:EncryptedID> in <saml:Subject>.');
193
        }
194
        $nameId = $nameId[0];
195
        if ($nameId->localName === 'EncryptedData') {
196
            /* The NameID element is encrypted. */
197
            $this->encryptedNameId = $nameId;
0 ignored issues
show
Documentation Bug introduced by
It seems like $nameId of type object<DOMElement> is incompatible with the declared type string of property $encryptedNameId.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
198
        } else {
199
            $this->nameId = Utils::parseNameId($nameId);
0 ignored issues
show
Documentation Bug introduced by
It seems like \SAML2\Utils::parseNameId($nameId) of type array<string,string> is incompatible with the declared type string of property $nameId.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
200
        }
201
202
        $subjectConfirmation = Utils::xpQuery($subject, './saml_assertion:SubjectConfirmation');
203
        foreach ($subjectConfirmation as $sc) {
204
            $this->subjectConfirmation[] = new SubjectConfirmation($sc);
205
        }
206
    }
207
208
    /**
209
     * @param \DOMElement $xml
210
     *
211
     * @throws \Exception
212
     */
213
    protected function parseNameIdPolicy(\DOMElement $xml)
214
    {
215
        $nameIdPolicy = Utils::xpQuery($xml, './saml_protocol:NameIDPolicy');
216
        if (empty($nameIdPolicy)) {
217
            return;
218
        }
219
220
        $nameIdPolicy = $nameIdPolicy[0];
221
        if ($nameIdPolicy->hasAttribute('Format')) {
222
            $this->nameIdPolicy['Format'] = $nameIdPolicy->getAttribute('Format');
223
        }
224
        if ($nameIdPolicy->hasAttribute('SPNameQualifier')) {
225
            $this->nameIdPolicy['SPNameQualifier'] = $nameIdPolicy->getAttribute('SPNameQualifier');
226
        }
227
        if ($nameIdPolicy->hasAttribute('AllowCreate')) {
228
            $this->nameIdPolicy['AllowCreate'] = Utils::parseBoolean($nameIdPolicy, 'AllowCreate', false);
229
        }
230
    }
231
232
    /**
233
     * @param \DOMElement $xml
234
     */
235
    protected function parseRequestedAuthnContext(\DOMElement $xml)
236
    {
237
        $requestedAuthnContext = Utils::xpQuery($xml, './saml_protocol:RequestedAuthnContext');
238
        if (empty($requestedAuthnContext)) {
239
            return;
240
        }
241
242
        $requestedAuthnContext = $requestedAuthnContext[0];
243
244
        $rac = array(
245
            'AuthnContextClassRef' => array(),
246
            'Comparison'           => Constants::COMPARISON_EXACT,
247
        );
248
249
        $accr = Utils::xpQuery($requestedAuthnContext, './saml_assertion:AuthnContextClassRef');
250
        foreach ($accr as $i) {
251
            $rac['AuthnContextClassRef'][] = trim($i->textContent);
252
        }
253
254
        if ($requestedAuthnContext->hasAttribute('Comparison')) {
255
            $rac['Comparison'] = $requestedAuthnContext->getAttribute('Comparison');
256
        }
257
258
        $this->requestedAuthnContext = $rac;
259
    }
260
261
    /**
262
     * @param \DOMElement $xml
263
     *
264
     * @throws \Exception
265
     */
266
    protected function parseScoping(\DOMElement $xml)
267
    {
268
        $scoping = Utils::xpQuery($xml, './saml_protocol:Scoping');
269
        if (empty($scoping)) {
270
            return;
271
        }
272
273
        $scoping = $scoping[0];
274
275
        if ($scoping->hasAttribute('ProxyCount')) {
276
            $this->ProxyCount = (int) $scoping->getAttribute('ProxyCount');
277
        }
278
        $idpEntries = Utils::xpQuery($scoping, './saml_protocol:IDPList/saml_protocol:IDPEntry');
279
280
        foreach ($idpEntries as $idpEntry) {
281
            if (!$idpEntry->hasAttribute('ProviderID')) {
282
                throw new \Exception("Could not get ProviderID from Scoping/IDPEntry element in AuthnRequest object");
283
            }
284
            $this->IDPList[] = $idpEntry->getAttribute('ProviderID');
285
        }
286
287
        $requesterIDs = Utils::xpQuery($scoping, './saml_protocol:RequesterID');
288
        foreach ($requesterIDs as $requesterID) {
289
            $this->RequesterID[] = trim($requesterID->textContent);
290
        }
291
    }
292
293
    /**
294
     * Retrieve the NameIdPolicy.
295
     *
296
     * @see \SAML2\AuthnRequest::setNameIdPolicy()
297
     * @return array The NameIdPolicy.
298
     */
299
    public function getNameIdPolicy()
300
    {
301
        return $this->nameIdPolicy;
302
    }
303
304
305
    /**
306
     * Set the NameIDPolicy.
307
     *
308
     * This function accepts an array with the following options:
309
     *  - 'Format'
310
     *  - 'SPNameQualifier'
311
     *  - 'AllowCreate'
312
     *
313
     * @param array $nameIdPolicy The NameIDPolicy.
314
     */
315
    public function setNameIdPolicy(array $nameIdPolicy)
316
    {
317
        $this->nameIdPolicy = $nameIdPolicy;
318
    }
319
320
321
    /**
322
     * Retrieve the value of the ForceAuthn attribute.
323
     *
324
     * @return bool The ForceAuthn attribute.
325
     */
326
    public function getForceAuthn()
327
    {
328
        return $this->forceAuthn;
329
    }
330
331
332
    /**
333
     * Set the value of the ForceAuthn attribute.
334
     *
335
     * @param bool $forceAuthn The ForceAuthn attribute.
336
     */
337
    public function setForceAuthn($forceAuthn)
338
    {
339
        assert('is_bool($forceAuthn)');
340
341
        $this->forceAuthn = $forceAuthn;
342
    }
343
344
345
    /**
346
     * Retrieve the value of the ProviderName attribute.
347
     *
348
     * @return string The ProviderName attribute.
349
     */
350
    public function getProviderName()
351
    {
352
        return $this->ProviderName;
353
    }
354
355
356
    /**
357
     * Set the value of the ProviderName attribute.
358
     *
359
     * @param string $ProviderName The ProviderName attribute.
360
     */
361
    public function setProviderName($ProviderName)
362
    {
363
        assert('is_string($ProviderName)');
364
365
        $this->ProviderName = $ProviderName;
366
    }
367
368
369
    /**
370
     * Retrieve the value of the IsPassive attribute.
371
     *
372
     * @return bool The IsPassive attribute.
373
     */
374
    public function getIsPassive()
375
    {
376
        return $this->isPassive;
377
    }
378
379
380
    /**
381
     * Set the value of the IsPassive attribute.
382
     *
383
     * @param bool $isPassive The IsPassive attribute.
384
     */
385
    public function setIsPassive($isPassive)
386
    {
387
        assert('is_bool($isPassive)');
388
389
        $this->isPassive = $isPassive;
390
    }
391
392
393
    /**
394
     * This function sets the scoping for the request.
395
     * See Core 3.4.1.2 for the definition of scoping.
396
     * Currently we support an IDPList of idpEntries.
397
     *
398
     * Each idpEntries consists of an array, containing
399
     * keys (mapped to attributes) and corresponding values.
400
     * Allowed attributes: Loc, Name, ProviderID.
401
     *
402
     * For backward compatibility, an idpEntries can also
403
     * be a string instead of an array, where each string
404
     * is mapped to the value of attribute ProviderID.
405
     */
406
    public function setIDPList($IDPList)
407
    {
408
        assert('is_array($IDPList)');
409
        $this->IDPList = $IDPList;
410
    }
411
412
413
    /**
414
     * This function retrieves the list of providerIDs from this authentication request.
415
     * Currently we only support a list of ipd ientity id's.
416
     * @return array List of idp EntityIDs from the request
417
     */
418
    public function getIDPList()
419
    {
420
        return $this->IDPList;
421
    }
422
423
    /**
424
     * @param int $ProxyCount
425
     */
426
    public function setProxyCount($ProxyCount)
427
    {
428
        assert('is_int($ProxyCount)');
429
        $this->ProxyCount = $ProxyCount;
430
    }
431
432
    /**
433
     * @return int
434
     */
435
    public function getProxyCount()
436
    {
437
        return $this->ProxyCount;
438
    }
439
440
    /**
441
     * @param array $RequesterID
442
     */
443
    public function setRequesterID(array $RequesterID)
444
    {
445
        $this->RequesterID = $RequesterID;
446
    }
447
448
    /**
449
     * @return array
450
     */
451
    public function getRequesterID()
452
    {
453
        return $this->RequesterID;
454
    }
455
456
    /**
457
     * Retrieve the value of the AssertionConsumerServiceURL attribute.
458
     *
459
     * @return string|null The AssertionConsumerServiceURL attribute.
460
     */
461
    public function getAssertionConsumerServiceURL()
462
    {
463
        return $this->assertionConsumerServiceURL;
464
    }
465
466
    /**
467
     * Set the value of the AssertionConsumerServiceURL attribute.
468
     *
469
     * @param string|null $assertionConsumerServiceURL The AssertionConsumerServiceURL attribute.
470
     */
471
    public function setAssertionConsumerServiceURL($assertionConsumerServiceURL)
472
    {
473
        assert('is_string($assertionConsumerServiceURL) || is_null($assertionConsumerServiceURL)');
474
475
        $this->assertionConsumerServiceURL = $assertionConsumerServiceURL;
476
    }
477
478
    /**
479
     * Retrieve the value of the ProtocolBinding attribute.
480
     *
481
     * @return string|null The ProtocolBinding attribute.
482
     */
483
    public function getProtocolBinding()
484
    {
485
        return $this->protocolBinding;
486
    }
487
488
    /**
489
     * Set the value of the ProtocolBinding attribute.
490
     *
491
     * @param string $protocolBinding The ProtocolBinding attribute.
492
     */
493
    public function setProtocolBinding($protocolBinding)
494
    {
495
        assert('is_string($protocolBinding) || is_null($protocolBinding)');
496
497
        $this->protocolBinding = $protocolBinding;
498
    }
499
500
    /**
501
     * Retrieve the value of the AttributeConsumingServiceIndex attribute.
502
     *
503
     * @return int|null The AttributeConsumingServiceIndex attribute.
504
     */
505
    public function getAttributeConsumingServiceIndex()
506
    {
507
        return $this->attributeConsumingServiceIndex;
508
    }
509
510
    /**
511
     * Set the value of the AttributeConsumingServiceIndex attribute.
512
     *
513
     * @param int|null $attributeConsumingServiceIndex The AttributeConsumingServiceIndex attribute.
514
     */
515
    public function setAttributeConsumingServiceIndex($attributeConsumingServiceIndex)
516
    {
517
        assert('is_int($attributeConsumingServiceIndex) || is_null($attributeConsumingServiceIndex)');
518
519
        $this->attributeConsumingServiceIndex = $attributeConsumingServiceIndex;
520
    }
521
522
    /**
523
     * Retrieve the value of the AssertionConsumerServiceIndex attribute.
524
     *
525
     * @return int|null The AssertionConsumerServiceIndex attribute.
526
     */
527
    public function getAssertionConsumerServiceIndex()
528
    {
529
        return $this->assertionConsumerServiceIndex;
530
    }
531
532
    /**
533
     * Set the value of the AssertionConsumerServiceIndex attribute.
534
     *
535
     * @param int|null $assertionConsumerServiceIndex The AssertionConsumerServiceIndex attribute.
536
     */
537
    public function setAssertionConsumerServiceIndex($assertionConsumerServiceIndex)
538
    {
539
        assert('is_int($assertionConsumerServiceIndex) || is_null($assertionConsumerServiceIndex)');
540
541
        $this->assertionConsumerServiceIndex = $assertionConsumerServiceIndex;
542
    }
543
544
    /**
545
     * Retrieve the RequestedAuthnContext.
546
     *
547
     * @return array|null The RequestedAuthnContext.
548
     */
549
    public function getRequestedAuthnContext()
550
    {
551
        return $this->requestedAuthnContext;
552
    }
553
554
    /**
555
     * Set the RequestedAuthnContext.
556
     *
557
     * @param array|null $requestedAuthnContext The RequestedAuthnContext.
558
     */
559
    public function setRequestedAuthnContext($requestedAuthnContext)
560
    {
561
        assert('is_array($requestedAuthnContext) || is_null($requestedAuthnContext)');
562
563
        $this->requestedAuthnContext = $requestedAuthnContext;
0 ignored issues
show
Documentation Bug introduced by
It seems like $requestedAuthnContext can be null. However, the property $requestedAuthnContext is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
564
    }
565
566
    /**
567
     * Retrieve the NameId of the subject in the assertion.
568
     *
569
     * The returned NameId is in the format used by \SAML2\Utils::addNameId().
570
     *
571
     * @see \SAML2\Utils::addNameId()
572
     * @return array|null The name identifier of the assertion.
573
     * @throws \Exception
574
     */
575
    public function getNameId()
576
    {
577
        if ($this->encryptedNameId !== null) {
578
            throw new \Exception('Attempted to retrieve encrypted NameID without decrypting it first.');
579
        }
580
581
        return $this->nameId;
582
    }
583
584
    /**
585
     * Set the NameId of the subject in the assertion.
586
     *
587
     * The NameId must be in the format accepted by \SAML2\Utils::addNameId().
588
     *
589
     * @see \SAML2\Utils::addNameId()
590
     *
591
     * @param array|null $nameId The name identifier of the assertion.
592
     */
593
    public function setNameId($nameId)
594
    {
595
        assert('is_array($nameId) || is_null($nameId)');
596
597
        $this->nameId = $nameId;
0 ignored issues
show
Documentation Bug introduced by
It seems like $nameId can also be of type array. However, the property $nameId is declared as type string. 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...
598
    }
599
600
    /**
601
     * Encrypt the NameID in the AuthnRequest.
602
     *
603
     * @param XMLSecurityKey $key The encryption key.
604
     */
605 View Code Duplication
    public function encryptNameId(XMLSecurityKey $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
606
    {
607
        /* First create a XML representation of the NameID. */
608
        $doc  = new \DOMDocument();
609
        $root = $doc->createElement('root');
610
        $doc->appendChild($root);
611
        Utils::addNameId($root, $this->nameId);
0 ignored issues
show
Documentation introduced by
$this->nameId is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
612
        $nameId = $root->firstChild;
613
614
        Utils::getContainer()->debugMessage($nameId, 'encrypt');
0 ignored issues
show
Documentation introduced by
$nameId is of type object<DOMNode>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
615
616
        /* Encrypt the NameID. */
617
        $enc = new XMLSecEnc();
618
        $enc->setNode($nameId);
619
        // @codingStandardsIgnoreStart
620
        $enc->type = XMLSecEnc::Element;
621
        // @codingStandardsIgnoreEnd
622
623
        $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
624
        $symmetricKey->generateSessionKey();
625
        $enc->encryptKey($key, $symmetricKey);
626
627
        $this->encryptedNameId = $enc->encryptNode($symmetricKey);
0 ignored issues
show
Documentation Bug introduced by
It seems like $enc->encryptNode($symmetricKey) of type object<RobRichards\XMLSecLibs\DOMElement> is incompatible with the declared type string of property $encryptedNameId.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
628
        $this->nameId          = null;
629
    }
630
631
    /**
632
     * Decrypt the NameId of the subject in the assertion.
633
     *
634
     * @param XMLSecurityKey $key       The decryption key.
635
     * @param array          $blacklist Blacklisted decryption algorithms.
636
     */
637 View Code Duplication
    public function decryptNameId(XMLSecurityKey $key, array $blacklist = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
638
    {
639
        if ($this->encryptedNameId === null) {
640
            /* No NameID to decrypt. */
641
            return;
642
        }
643
644
        $nameId = Utils::decryptElement($this->encryptedNameId, $key, $blacklist);
0 ignored issues
show
Documentation introduced by
$this->encryptedNameId is of type string, but the function expects a object<DOMElement>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
645
        Utils::getContainer()->debugMessage($nameId, 'decrypt');
0 ignored issues
show
Documentation introduced by
$nameId is of type object<DOMElement>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
646
        $this->nameId = Utils::parseNameId($nameId);
0 ignored issues
show
Documentation Bug introduced by
It seems like \SAML2\Utils::parseNameId($nameId) of type array<string,string> is incompatible with the declared type string of property $nameId.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
647
648
        $this->encryptedNameId = null;
649
    }
650
651
    /**
652
     * Retrieve the SubjectConfirmation elements we have in our Subject element.
653
     *
654
     * @return \SAML2\XML\saml\SubjectConfirmation[]
655
     */
656
    public function getSubjectConfirmation()
657
    {
658
        return $this->subjectConfirmation;
659
    }
660
661
    /**
662
     * Set the SubjectConfirmation elements that should be included in the assertion.
663
     *
664
     * @param array \SAML2\XML\saml\SubjectConfirmation[]
665
     */
666
    public function setSubjectConfirmation(array $subjectConfirmation)
667
    {
668
        $this->subjectConfirmation = $subjectConfirmation;
669
    }
670
671
    /**
672
     * Convert this authentication request to an XML element.
673
     *
674
     * @return \DOMElement This authentication request.
675
     */
676
    public function toUnsignedXML()
677
    {
678
        $root = parent::toUnsignedXML();
679
680
        if ($this->forceAuthn) {
681
            $root->setAttribute('ForceAuthn', 'true');
682
        }
683
684
        if ($this->ProviderName !== null) {
685
            $root->setAttribute('ProviderName', $this->ProviderName);
686
        }
687
688
        if ($this->isPassive) {
689
            $root->setAttribute('IsPassive', 'true');
690
        }
691
692
        if ($this->assertionConsumerServiceIndex !== null) {
693
            $root->setAttribute('AssertionConsumerServiceIndex', $this->assertionConsumerServiceIndex);
694
        } else {
695
            if ($this->assertionConsumerServiceURL !== null) {
696
                $root->setAttribute('AssertionConsumerServiceURL', $this->assertionConsumerServiceURL);
697
            }
698
            if ($this->protocolBinding !== null) {
699
                $root->setAttribute('ProtocolBinding', $this->protocolBinding);
700
            }
701
        }
702
703
        if ($this->attributeConsumingServiceIndex !== null) {
704
            $root->setAttribute('AttributeConsumingServiceIndex', $this->attributeConsumingServiceIndex);
705
        }
706
707
        $this->addSubject($root);
708
709
        if (!empty($this->nameIdPolicy)) {
710
            $nameIdPolicy = $this->document->createElementNS(Constants::NS_SAMLP, 'NameIDPolicy');
711
            if (array_key_exists('Format', $this->nameIdPolicy)) {
712
                $nameIdPolicy->setAttribute('Format', $this->nameIdPolicy['Format']);
713
            }
714
            if (array_key_exists('SPNameQualifier', $this->nameIdPolicy)) {
715
                $nameIdPolicy->setAttribute('SPNameQualifier', $this->nameIdPolicy['SPNameQualifier']);
716
            }
717
            if (array_key_exists('AllowCreate', $this->nameIdPolicy) && $this->nameIdPolicy['AllowCreate']) {
718
                $nameIdPolicy->setAttribute('AllowCreate', 'true');
719
            }
720
            $root->appendChild($nameIdPolicy);
721
        }
722
723
        $rac = $this->requestedAuthnContext;
724
        if (!empty($rac) && !empty($rac['AuthnContextClassRef'])) {
725
            $e = $this->document->createElementNS(Constants::NS_SAMLP, 'RequestedAuthnContext');
726
            $root->appendChild($e);
727
            if (isset($rac['Comparison']) && $rac['Comparison'] !== Constants::COMPARISON_EXACT) {
728
                $e->setAttribute('Comparison', $rac['Comparison']);
729
            }
730
            foreach ($rac['AuthnContextClassRef'] as $accr) {
731
                Utils::addString($e, Constants::NS_SAML, 'AuthnContextClassRef', $accr);
732
            }
733
        }
734
735
        if ($this->ProxyCount !== null || count($this->IDPList) > 0 || count($this->RequesterID) > 0) {
736
            $scoping = $this->document->createElementNS(Constants::NS_SAMLP, 'Scoping');
737
            $root->appendChild($scoping);
738
            if ($this->ProxyCount !== null) {
739
                $scoping->setAttribute('ProxyCount', $this->ProxyCount);
740
            }
741
            if (count($this->IDPList) > 0) {
742
                $idplist = $this->document->createElementNS(Constants::NS_SAMLP, 'IDPList');
743
                foreach ($this->IDPList as $provider) {
744
                    $idpEntry = $this->document->createElementNS(Constants::NS_SAMLP, 'IDPEntry');
745
                    if (is_string($provider)) {
746
                        $idpEntry->setAttribute('ProviderID', $provider);
747
                    } elseif (is_array($provider)) {
748
                        foreach ($provider as $attribute => $value) {
749
                            if (in_array($attribute, array(
750
                                'ProviderID',
751
                                'Loc',
752
                                'Name'
753
                            ))) {
754
                                $idpEntry->setAttribute($attribute, $value);
755
                            }
756
                        }
757
                    }
758
                    $idplist->appendChild($idpEntry);
759
                }
760
                $scoping->appendChild($idplist);
761
            }
762
            if (count($this->RequesterID) > 0) {
763
                Utils::addStrings($scoping, Constants::NS_SAMLP, 'RequesterID', false, $this->RequesterID);
764
            }
765
        }
766
767
        return $root;
768
    }
769
770
    /**
771
     * Add a Subject-node to the assertion.
772
     *
773
     * @param \DOMElement $root The assertion element we should add the subject to.
774
     */
775 View Code Duplication
    private function addSubject(\DOMElement $root)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
776
    {
777
        // If there is no nameId (encrypted or not) there is nothing to create a subject for
778
        if ($this->nameId === null && $this->encryptedNameId === null) {
779
            return;
780
        }
781
782
        $subject = $root->ownerDocument->createElementNS(Constants::NS_SAML, 'saml:Subject');
783
        $root->appendChild($subject);
784
785
        if ($this->encryptedNameId === null) {
786
            Utils::addNameId($subject, $this->nameId);
0 ignored issues
show
Documentation introduced by
$this->nameId is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
787
        } else {
788
            $eid = $subject->ownerDocument->createElementNS(Constants::NS_SAML, 'saml:EncryptedID');
789
            $eid->appendChild($subject->ownerDocument->importNode($this->encryptedNameId, true));
790
            $subject->appendChild($eid);
791
        }
792
793
        foreach ($this->subjectConfirmation as $sc) {
794
            $sc->toXML($subject);
795
        }
796
    }
797
}
798