Completed
Pull Request — master (#9)
by Asmir
231:31 queued 229:42
created

WsSecurityFilterRequest::handleSignature()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 6.1308

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 22
cts 26
cp 0.8462
rs 8.439
c 0
b 0
f 0
cc 6
eloc 23
nc 16
nop 1
crap 6.1308
1
<?php
2
3
namespace GoetasWebservices\SoapServices\SoapClient\WssWsSecurity;
4
5
use ass\XmlSecurity\DSig as XmlSecurityDSig;
6
use ass\XmlSecurity\Enc as XmlSecurityEnc;
7
8
class WsSecurityFilterRequest extends AbstractWsSecurityFilter
9
{
10
    /**
11
     * Web Services Security: SOAP Message Security 1.0 (WS-Security 2004)
12
     */
13
    const NAME_WSS_SMS = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0';
14
15
    /**
16
     * Web Services Security UsernameToken Profile 1.0
17
     */
18
    const NAME_WSS_UTP = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0';
19
20
    /**
21
     * Web Services Security X.509 Certificate Token Profile
22
     */
23
    const NAME_WSS_X509 = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0';
24
25
    /**
26
     * The date format to be used with {@link \DateTime}
27
     */
28
    const DATETIME_FORMAT = 'Y-m-d\TH:i:s.000\Z';
29
30
    /**
31
     * (X509 3.2.1) Reference to a Subject Key Identifier
32
     */
33
    const TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER = 0;
34
35
    /**
36
     * (X509 3.2.1) Reference to a Security Token
37
     */
38
    const TOKEN_REFERENCE_SECURITY_TOKEN = 1;
39
40
    /**
41
     * (SMS_1.1 7.3) Key Identifiers
42
     */
43
    const TOKEN_REFERENCE_THUMBPRINT_SHA1 = 2;
44
45
    /**
46
     * (SMS 10) Add security timestamp.
47
     *
48
     * @var boolean
49
     */
50
    private $addTimestamp = true;
51
52
    /**
53
     * Encrypt the signature?
54
     *
55
     * @var boolean
56
     */
57
    private $encryptSignature = false;
58
59
    /**
60
     * (SMS 10) Security timestamp expires time in seconds.
61
     *
62
     * @var int
63
     */
64
    private $expires = 300;
65
66
    /**
67
     * Sign all headers.
68
     *
69
     * @var boolean
70
     */
71
    private $signAllHeaders = false;
72
73
    /**
74
     * @var \DateTime
75
     */
76
    private $initialTimestamp;
77
78
    /**
79
     * (X509 3.2) Token reference type for encryption.
80
     *
81
     * @var int
82
     */
83
    private $tokenReferenceEncryption = null;
84
85
    /**
86
     * (X509 3.2) Token reference type for signature.
87
     *
88
     * @var int
89
     */
90
    private $tokenReferenceSignature = null;
91
92
93
    public function setTimestampOptions($addTimestamp = true, $expires = 300)
94
    {
95
        $this->addTimestamp = $addTimestamp;
96
        $this->expires = $expires;
97
    }
98
99
    /**
100
     * @param \DateTime $initialTimestamp
101
     */
102 1
    public function __construct(\DateTime $initialTimestamp = null)
103
    {
104 1
        $this->initialTimestamp = $initialTimestamp;
105 1
    }
106
107
    /**
108
     * Set security options.
109
     *
110
     * @param int $tokenReference self::TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER | self::TOKEN_REFERENCE_SECURITY_TOKEN | self::TOKEN_REFERENCE_THUMBPRINT_SHA1
111
     * @param boolean $encryptSignature Encrypt signature
112
     *
113
     * @return void
114
     */
115
    public function setSecurityOptionsEncryption($tokenReference, $encryptSignature = false)
116
    {
117
        $this->tokenReferenceEncryption = $tokenReference;
118
        $this->encryptSignature = $encryptSignature;
119
    }
120
121
    /**
122
     * Set security options.
123
     *
124
     * @param int $tokenReference self::TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER | self::TOKEN_REFERENCE_SECURITY_TOKEN | self::TOKEN_REFERENCE_THUMBPRINT_SHA1
125
     * @param boolean $signAllHeaders Sign all headers?
126
     *
127
     * @return void
128
     */
129
    public function setSecurityOptionsSignature($tokenReference, $signAllHeaders = false)
130
    {
131
        $this->tokenReferenceSignature = $tokenReference;
132
        $this->signAllHeaders = $signAllHeaders;
133
    }
134
135
    /**
136
     * Adds the configured KeyInfo to the parentNode.
137
     *
138
     * @param \DOMDocument $dom
139
     * @param int $tokenReference Token reference type
140
     * @param string $guid Unique ID
141
     * @param XmlSecurityKey $xmlSecurityKey XML security key
142
     *
143
     * @return \DOMElement
144
     */
145 1
    private function createKeyInfo(\DOMDocument $dom, $tokenReference, $guid, XmlSecurityKey $xmlSecurityKey = null)
146
    {
147 1
        $keyInfo = $dom->createElementNS(XmlSecurityDSig::NS_XMLDSIG, 'KeyInfo');
148 1
        $securityTokenReference = $dom->createElementNS(self::NS_WSS, 'SecurityTokenReference');
149 1
        $keyInfo->appendChild($securityTokenReference);
150
        // security token
151 1
        if (self::TOKEN_REFERENCE_SECURITY_TOKEN === $tokenReference) {
152 1
            $reference = $dom->createElementNS(self::NS_WSS, 'Reference');
153 1
            $reference->setAttribute('URI', '#' . $guid);
154 1
            if (null !== $xmlSecurityKey) {
155
                $reference->setAttribute('ValueType', self::NAME_WSS_X509 . '#X509v3');
156
            }
157 1
            $securityTokenReference->appendChild($reference);
158
            // subject key identifier
159 1
        } elseif (self::TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER === $tokenReference && null !== $xmlSecurityKey) {
160
            $keyIdentifier = $dom->createElementNS(self::NS_WSS, 'KeyIdentifier');
161
            $keyIdentifier->setAttribute('EncodingType', self::NAME_WSS_SMS . '#Base64Binary');
162
            $keyIdentifier->setAttribute('ValueType', self::NAME_WSS_X509 . '#509SubjectKeyIdentifier');
163
            $securityTokenReference->appendChild($keyIdentifier);
164
            $certificate = $xmlSecurityKey->getX509SubjectKeyIdentifier();
165
            $dataNode = new \DOMText($certificate);
166
            $keyIdentifier->appendChild($dataNode);
167
            // thumbprint sha1
168
        } elseif (self::TOKEN_REFERENCE_THUMBPRINT_SHA1 === $tokenReference && null !== $xmlSecurityKey) {
169
            $keyIdentifier = $dom->createElementNS(self::NS_WSS, 'KeyIdentifier');
170
            $keyIdentifier->setAttribute('EncodingType', self::NAME_WSS_SMS . '#Base64Binary');
171
            $keyIdentifier->setAttribute('ValueType', self::NAME_WSS_SMS_1_1 . '#ThumbprintSHA1');
172
            $securityTokenReference->appendChild($keyIdentifier);
173
            $thumbprintSha1 = base64_encode(sha1(base64_decode($xmlSecurityKey->getX509Certificate(true)), true));
174
            $dataNode = new \DOMText($thumbprintSha1);
175
            $keyIdentifier->appendChild($dataNode);
176
        }
177
178 1
        return $keyInfo;
179
    }
180
181
    /**
182
     * Create a list of \DOMNodes that should be encrypted.
183
     *
184
     * @param \DOMDocument $dom DOMDocument to query
185
     *
186
     * @return \DOMNodeList
187
     */
188 1
    private function createNodeListForEncryption(\DOMDocument $dom)
189
    {
190 1
        $xpath = new \DOMXPath($dom);
191 1
        $xpath->registerNamespace('SOAP-ENV', $dom->documentElement->namespaceURI);
192 1
        $xpath->registerNamespace('ds', XmlSecurityDSig::NS_XMLDSIG);
193 1
        if ($this->encryptSignature === true) {
194
            $query = '//ds:Signature | //SOAP-ENV:Body';
195
        } else {
196 1
            $query = '//SOAP-ENV:Body';
197
        }
198
199 1
        return $xpath->query($query);
200 1
    }
201
202
    /**
203
     * Create a list of \DOMNodes that should be signed.
204
     *
205
     * @param \DOMDocument $dom DOMDocument to query
206
     * @param \DOMElement $security Security element
207
     *
208
     * @return array(\DOMNode)
0 ignored issues
show
Documentation introduced by
The doc-type array(\DOMNode) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
209
     */
210 1
    private function createNodeListForSigning(\DOMDocument $dom, \DOMElement $security)
211
    {
212 1
        $nodes = array();
213 1
        $body = $dom->getElementsByTagNameNS($dom->documentElement->namespaceURI, 'Body')->item(0);
214 1
        if (null !== $body) {
215 1
            $nodes[] = $body;
216 1
        }
217 1
        foreach ($security->childNodes as $node) {
218 1
            if (XML_ELEMENT_NODE === $node->nodeType) {
219 1
                $nodes[] = $node;
220 1
            }
221 1
        }
222 1
        if ($this->signAllHeaders) {
223
            foreach ($security->parentNode->childNodes as $node) {
224
                if (XML_ELEMENT_NODE === $node->nodeType &&
225
                    self::NS_WSS !== $node->namespaceURI
226
                ) {
227
                    $nodes[] = $node;
228
                }
229
            }
230
        }
231 1
        return $nodes;
232
    }
233
234
235
    /**
236
     * Modify the given request XML.
237
     *
238
     * @param \DOMDocument $dom
239
     * @param Security $securityData
240
     *
241
     * @return \DOMElement
242
     */
243 1
    public function filterDom(\DOMDocument $dom, Security $securityData)
244
    {
245 1
        $security = $dom->createElementNS(self::NS_WSS, 'Security');
246
247 1
        $root = $dom->documentElement;
248 1
        $root->setAttributeNS(
249 1
            'http://www.w3.org/2000/xmlns/', // xmlns namespace URI
250 1
            'xmlns:wssu',
251
            self::NS_WSU
252 1
        );
253 1
        $root->setAttributeNS(
254 1
            'http://www.w3.org/2000/xmlns/', // xmlns namespace URI
255 1
            'xmlns:wsss',
256
            self::NS_WSS
257 1
        );
258 1
        $root->setAttributeNS(
259 1
            'http://www.w3.org/2000/xmlns/', // xmlns namespace URI
260 1
            'xmlns:dsig',
261
            XmlSecurityDSig::NS_XMLDSIG
262 1
        );
263 1
        $root->setAttributeNS(
264 1
            'http://www.w3.org/2000/xmlns/', // xmlns namespace URI
265 1
            'xmlns:xenc',
266
            XmlSecurityEnc::NS_XMLENC
267 1
        );
268
269
        // init timestamp
270 1
        $dt = $this->initialTimestamp ?: new \DateTime('now', new \DateTimeZone('UTC'));
271
272 1
        if (true === $this->addTimestamp || null !== $this->expires) {
273 1
            $this->handleTimestamp($security, $dt);
274 1
        }
275
276 1
        if (null !== $securityData->getUsername()) {
277 1
            $this->handleUsername($security, $dt, $securityData);
278 1
        }
279
280 1
        if (null !== $this->userSecurityKey && $this->userSecurityKey->hasKeys()) {
281 1
            $signature = $this->handleSignature($security);
282
283
            // encrypt soap document
284 1
            if (null !== $this->serviceSecurityKey && $this->serviceSecurityKey->hasKeys()) {
285 1
                $this->handleEncryption($security, $signature);
286 1
            }
287 1
        }
288 1
        return $security;
289
    }
290
291
    /**
292
     * Generate a pseudo-random version 4 UUID.
293
     *
294
     * @see http://de.php.net/manual/en/function.uniqid.php#94959
295
     *
296
     * @return string
297
     */
298 1
    private static function generateUUID()
299
    {
300 1
        return sprintf(
301 1
            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
302
            // 32 bits for "time_low"
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
303 1
            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
304
            // 16 bits for "time_mid"
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
305 1
            mt_rand(0, 0xffff),
306
            // 16 bits for "time_hi_and_version",
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
307
            // four most significant bits holds version number 4
308 1
            mt_rand(0, 0x0fff) | 0x4000,
309
            // 16 bits, 8 bits for "clk_seq_hi_res",
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
310
            // 8 bits for "clk_seq_low",
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
311
            // two most significant bits holds zero and one for variant DCE1.1
312 1
            mt_rand(0, 0x3fff) | 0x8000,
313
            // 48 bits for "node"
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
314 1
            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
315 1
        );
316
    }
317
318
    /**
319
     * @param \DOMElement $security
320
     * @param \DateTime $dt
321
     */
322 1
    private function handleTimestamp(\DOMElement $security, \DateTime $dt)
323
    {
324 1
        $dom = $security->ownerDocument;
325 1
        $timestamp = $dom->createElementNS(self::NS_WSU, 'Timestamp');
326 1
        $created = $dom->createElementNS(self::NS_WSU, 'Created', $dt->format(self::DATETIME_FORMAT));
327 1
        $timestamp->appendChild($created);
328 1
        if (null !== $this->expires) {
329 1
            $dt = clone $dt;
330 1
            $dt->modify('+' . $this->expires . ' seconds');
331 1
            $expiresTimestamp = $dt->format(self::DATETIME_FORMAT);
332 1
            $expires = $dom->createElementNS(self::NS_WSU, 'Expires', $expiresTimestamp);
333 1
            $timestamp->appendChild($expires);
334 1
        }
335 1
        $security->appendChild($timestamp);
336 1
    }
337
338
    /**
339
     * @param \DOMElement $security
340
     * @param $dt
341
     * @param Security $securityData
342
     */
343 1
    private function handleUsername(\DOMElement $security, $dt, Security $securityData)
344
    {
345 1
        $dom = $security->ownerDocument;
346 1
        $usernameToken = $dom->createElementNS(self::NS_WSS, 'UsernameToken');
347 1
        $security->appendChild($usernameToken);
348
349 1
        $username = $dom->createElementNS(self::NS_WSS, 'Username', $securityData->getUsername());
350 1
        $usernameToken->appendChild($username);
351
352 1
        if (null !== $securityData->getPassword()
353 1
            && (null === $this->userSecurityKey
354 1
                || (null !== $this->userSecurityKey && !$this->userSecurityKey->hasPrivateKey()))
355 1
        ) {
356
357
            if ($securityData->isPasswordDigest()) {
358
                $nonce = mt_rand();
359
                $password = base64_encode(sha1($nonce . $dt->format(self::DATETIME_FORMAT) . $securityData->getPassword(), true));
360
                $passwordType = self::NAME_WSS_UTP . '#PasswordDigest';
361
            } else {
362
                $password = $securityData->getPassword();
363
                $passwordType = self::NAME_WSS_UTP . '#PasswordText';
364
            }
365
366
            $password = $dom->createElementNS(self::NS_WSS, 'Password', $password);
367
            $password->setAttribute('Type', $passwordType);
368
            $usernameToken->appendChild($password);
369
            if ($securityData->isPasswordDigest()) {
370
                $nonce = $dom->createElementNS(self::NS_WSS, 'Nonce', base64_encode($nonce));
0 ignored issues
show
Bug introduced by
The variable $nonce does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
371
                $usernameToken->appendChild($nonce);
372
373
                $created = $dom->createElementNS(self::NS_WSU, 'Created', $dt->format(self::DATETIME_FORMAT));
374
                $usernameToken->appendChild($created);
375
            }
376
        }
377 1
    }
378
379
    /**
380
     * @param \DOMElement $security
381
     * @return \DOMElement
382
     */
383 1
    private function handleSignature(\DOMElement $security)
384
    {
385 1
        $dom = $security->ownerDocument;
386 1
        $guid = 'CertId-' . self::generateUUID();
387
        // add token references
388 1
        $keyInfo = null;
389 1
        if (null !== $this->tokenReferenceSignature) {
390
            $keyInfo = $this->createKeyInfo($dom, $this->tokenReferenceSignature, $guid, $this->userSecurityKey->getPublicKey());
0 ignored issues
show
Documentation introduced by
$this->userSecurityKey->getPublicKey() is of type object<ass\XmlSecurity\Key>, but the function expects a null|object<GoetasWebser...ecurity\XmlSecurityKey>.

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...
391
        }
392 1
        $nodes = $this->createNodeListForSigning($dom, $security);
393 1
        $signature = XmlSecurityDSig::createSignature($this->userSecurityKey->getPrivateKey(), XmlSecurityDSig::EXC_C14N, $security, null, $keyInfo);
394
395 1
        if ((!$prefix = $security->lookupPrefix(self::NS_WSU)) && (!$prefix = $security->ownerDocument->lookupPrefix(self::NS_WSU))) {
396
            $prefix = 'ns-'.  substr(sha1(self::NS_WSU), 0, 8);
397
        }
398
399
        $options = array(
400 1
            'id_ns_prefix' => $prefix ?: 'wsu',
401 1
            'id_prefix_ns' => self::NS_WSU,
402 1
        );
403 1
        foreach ($nodes as $node) {
404 1
            XmlSecurityDSig::addNodeToSignature($signature, $node, XmlSecurityDSig::SHA1, XmlSecurityDSig::EXC_C14N, $options);
405 1
        }
406 1
        XmlSecurityDSig::signDocument($signature, $this->userSecurityKey->getPrivateKey(), XmlSecurityDSig::EXC_C14N);
407
408 1
        $publicCertificate = $this->userSecurityKey->getPublicKey()->getX509Certificate(true);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class ass\XmlSecurity\Key as the method getX509Certificate() does only exist in the following sub-classes of ass\XmlSecurity\Key: ass\XmlSecurity\Key\PrivatePublic, ass\XmlSecurity\Key\Rsa15, ass\XmlSecurity\Key\RsaOaepMgf1p, ass\XmlSecurity\Key\RsaSha1, ass\XmlSecurity\Key\RsaSha256, ass\XmlSecurity\Key\RsaSha384, ass\XmlSecurity\Key\RsaSha512. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
409 1
        $binarySecurityToken = $dom->createElementNS(self::NS_WSS, 'BinarySecurityToken', $publicCertificate);
410 1
        $binarySecurityToken->setAttribute('EncodingType', self::NAME_WSS_SMS . '#Base64Binary');
411 1
        $binarySecurityToken->setAttribute('ValueType', self::NAME_WSS_X509 . '#X509v3');
412
413 1
        $security->insertBefore($binarySecurityToken, $signature);
414
415 1
        $binarySecurityToken->setAttributeNs(self::NS_WSU, $prefix.':Id', $guid);
416
417
418 1
        return $signature;
419
    }
420
421
    /**
422
     * @param \DOMElement $security
423
     * @param \DOMElement $signature
424
     */
425 1
    private function handleEncryption(\DOMElement $security, \DOMElement $signature)
426
    {
427 1
        $dom = $security->ownerDocument;
428 1
        $guid = 'EncKey-' . self::generateUUID();
429
        // add token references
430 1
        $keyInfo = null;
431 1
        if (null !== $this->tokenReferenceEncryption) {
432
            $keyInfo = $this->createKeyInfo($dom, $this->tokenReferenceEncryption, $guid, $this->serviceSecurityKey->getPublicKey());
0 ignored issues
show
Documentation introduced by
$this->serviceSecurityKey->getPublicKey() is of type object<ass\XmlSecurity\Key>, but the function expects a null|object<GoetasWebser...ecurity\XmlSecurityKey>.

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...
433
        }
434 1
        $encryptedKey = XmlSecurityEnc::createEncryptedKey($guid, $this->serviceSecurityKey->getPrivateKey(), $this->serviceSecurityKey->getPublicKey(), $security, $signature, $keyInfo);
435 1
        $referenceList = XmlSecurityEnc::createReferenceList($encryptedKey);
436
        // token reference to encrypted key
437 1
        $keyInfo = $this->createKeyInfo($dom, self::TOKEN_REFERENCE_SECURITY_TOKEN, $guid);
438 1
        $nodes = $this->createNodeListForEncryption($dom);
439 1
        foreach ($nodes as $node) {
440 1
            $type = XmlSecurityEnc::ELEMENT;
441 1
            if ($node->localName == 'Body') {
442 1
                $type = XmlSecurityEnc::CONTENT;
443 1
            }
444 1
            XmlSecurityEnc::encryptNode($node, $type, $this->serviceSecurityKey->getPrivateKey(), $referenceList, $keyInfo);
445 1
        }
446 1
    }
447
}
448