Completed
Pull Request — master (#9)
by Asmir
148:13 queued 118:12
created

WsSecurityFilterResponse::filterDom()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 39
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 20
nc 9
nop 1
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 WsSecurityFilterResponse extends AbstractWsSecurityFilter
9
{
10
11
    /**
12
     * Gets the referenced node for the given URI.
13
     *
14
     * @param \DOMElement $node Node
15
     * @param string $uri URI
16
     *
17
     * @return \DOMElement
18
     */
19
    private function getReferenceNodeForUri(\DOMElement $node, $uri)
20
    {
21
        $url = parse_url($uri);
22
        $referenceId = $url['fragment'];
23
        $query = '//*[@wsu:Id="' . $referenceId . '" or @Id="' . $referenceId . '"]';
24
        $xpath = new \DOMXPath($node->ownerDocument);
25
        $xpath->registerNamespace('wsu', self::NS_WSU);
26
27
        return $xpath->query($query)->item(0);
28
    }
29
30
    /**
31
     * Tries to resolve a key from the given \DOMElement.
32
     *
33
     * @param \DOMElement $node Node where to resolve the key
34
     * @param string $algorithm XML security key algorithm
35
     *
36
     * @return \ass\XmlSecurity\Key|null
37
     */
38
    protected function keyInfoSecurityTokenReferenceResolver(\DOMElement $node, $algorithm)
39
    {
40
        foreach ($node->childNodes as $key) {
41
            if (self::NS_WSS === $key->namespaceURI) {
42
                switch ($key->localName) {
43
                    case 'KeyIdentifier':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
44
45
                        return $this->serviceSecurityKey->getPublicKey();
46
                    case 'Reference':
47
                        $uri = $key->getAttribute('URI');
48
                        $referencedNode = $this->getReferenceNodeForUri($node, $uri);
49
50
                        if (XmlSecurityEnc::NS_XMLENC === $referencedNode->namespaceURI
51
                            && 'EncryptedKey' == $referencedNode->localName
52
                        ) {
53
                            $key = XmlSecurityEnc::decryptEncryptedKey($referencedNode, $this->userSecurityKey->getPrivateKey());
54
55
                            return XmlSecurityKey::factory($algorithm, $key, false, XmlSecurityKey::TYPE_PRIVATE);
56
                        } elseif (self::NS_WSS === $referencedNode->namespaceURI
57
                            && 'BinarySecurityToken' == $referencedNode->localName
58
                        ) {
59
60
                            $key = XmlSecurityPem::formatKeyInPemFormat($referencedNode->textContent);
61
62
                            return XmlSecurityKey::factory(XmlSecurityKey::RSA_SHA1, $key, false, XmlSecurityKey::TYPE_PUBLIC);
63
                        }
64
                }
65
            }
66
        }
67
68
        return null;
69
    }
70
71
    /**
72
     * Modify the given request XML.
73
     *
74
     * @param \DOMDocument $dom
75
     *
76
     * @return void
77
     */
78
    public function filterDom(\DOMDocument $dom)
79
    {
80
81
        // locate security header
82
        $security = $dom->getElementsByTagNameNS(self::NS_WSS, 'Security')->item(0);
83
        if (null !== $security) {
84
            // add SecurityTokenReference resolver for KeyInfo
85
            $keyResolver = array($this, 'keyInfoSecurityTokenReferenceResolver');
86
            XmlSecurityDSig::addKeyInfoResolver(self::NS_WSS, 'SecurityTokenReference', $keyResolver);
87
            // do we have a reference list in header
88
            $referenceList = XmlSecurityEnc::locateReferenceList($security);
89
            // get a list of encrypted nodes
90
            $encryptedNodes = XmlSecurityEnc::locateEncryptedData($dom, $referenceList);
91
            // decrypt them
92
            if (null !== $encryptedNodes) {
93
                foreach ($encryptedNodes as $encryptedNode) {
94
                    XmlSecurityEnc::decryptNode($encryptedNode);
95
                }
96
            }
97
            // locate signature node
98
            $signature = XmlSecurityDSig::locateSignature($security);
99
            if (null !== $signature) {
100
                // verify references
101
                $options = array(
102
                    'id_ns_prefix' => 'wsu', // used only for the xpath prefix
103
                    'id_prefix_ns' => self::PFX_WSU
104
                );
105
                if (XmlSecurityDSig::verifyReferences($signature, $options) !== true) {
106
                    throw new \SoapFault('wsse:FailedCheck', 'The signature or decryption was invalid');
107
                }
108
                // verify signature
109
                if (XmlSecurityDSig::verifyDocumentSignature($signature) !== true) {
110
                    throw new \SoapFault('wsse:FailedCheck', 'The signature or decryption was invalid');
111
                }
112
            }
113
114
            $security->parentNode->removeChild($security);
115
        }
116
    }
117
}
118