Completed
Pull Request — master (#9)
by Asmir
163:43 queued 133:54
created

WsSecurityFilterResponse::filterDom()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 41
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 41
c 0
b 0
f 0
rs 6.7272
cc 7
eloc 20
nc 9
nop 1
1
<?php
2
3
namespace GoetasWebservices\SoapServices\SoapClient\WssWsSecurity\Serializer;
4
5
use ass\XmlSecurity\DSig as XmlSecurityDSig;
6
use ass\XmlSecurity\Enc as XmlSecurityEnc;
7
use ass\XmlSecurity\Key as XmlSecurityKey;
8
use GoetasWebservices\SoapServices\SoapClient\WssWsSecurity\Exception\ClientException;
9
10
class WsSecurityFilterResponse extends AbstractWsSecurityFilter
11
{
12
    /**
13
     * Gets the referenced node for the given URI.
14
     *
15
     * @param \DOMElement $node Node
16
     * @param string $uri URI
17
     *
18
     * @return \DOMElement
19
     */
20
    private function getReferenceNodeForUri(\DOMElement $node, $uri)
21
    {
22
        $url = parse_url($uri);
23
        $referenceId = $url['fragment'];
24
        $query = '//*[@wsu:Id="' . $referenceId . '" or @Id="' . $referenceId . '"]';
25
        $xpath = new \DOMXPath($node->ownerDocument);
26
        $xpath->registerNamespace('wsu', self::NS_WSU);
27
28
        return $xpath->query($query)->item(0);
29
    }
30
31
    /**
32
     * Tries to resolve a key from the given \DOMElement.
33
     *
34
     * @param \DOMElement $node Node where to resolve the key
35
     * @param string $algorithm XML security key algorithm
36
     *
37
     * @return \ass\XmlSecurity\Key|null
38
     */
39
    public function keyInfoSecurityTokenReferenceResolver(\DOMElement $node, $algorithm)
40
    {
41
        foreach ($node->childNodes as $key) {
42
            if (self::NS_WSS === $key->namespaceURI) {
43
                switch ($key->localName) {
44
                    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...
45
46
                        return $this->serviceSecurityKey->getPublicKey();
47
                    case 'Reference':
48
                        $uri = $key->getAttribute('URI');
49
                        $referencedNode = $this->getReferenceNodeForUri($node, $uri);
50
51
                        if (XmlSecurityEnc::NS_XMLENC === $referencedNode->namespaceURI
52
                            && 'EncryptedKey' == $referencedNode->localName
53
                        ) {
54
                            $key = XmlSecurityEnc::decryptEncryptedKey($referencedNode, $this->userSecurityKey->getPrivateKey());
55
56
                            return XmlSecurityKey::factory($algorithm, $key, false, XmlSecurityKey::TYPE_PRIVATE);
57
                        } elseif (self::NS_WSS === $referencedNode->namespaceURI
58
                            && 'BinarySecurityToken' == $referencedNode->localName
59
                        ) {
60
61
                            $key = XmlSecurityPem::formatKeyInPemFormat($referencedNode->textContent);
62
63
                            return XmlSecurityKey::factory(XmlSecurityKey::RSA_SHA1, $key, false, XmlSecurityKey::TYPE_PUBLIC);
64
                        }
65
                }
66
            }
67
        }
68
69
        return null;
70
    }
71
72
73
    /**
74
     * Modify the given request XML.
75
     *
76
     * @param \DOMDocument $dom
77
     *
78
     * @return void
79
     */
80
    public function filterDom(\DOMDocument $dom)
81
    {
82
        // locate security header
83
        $security = $dom->getElementsByTagNameNS(self::NS_WSS, 'Security')->item(0);
84
        if (null !== $security) {
85
            // add SecurityTokenReference resolver for KeyInfo
86
            $keyResolver = array($this, 'keyInfoSecurityTokenReferenceResolver');
87
            XmlSecurityDSig::addKeyInfoResolver(self::NS_WSS, 'SecurityTokenReference', $keyResolver);
88
            // do we have a reference list in header
89
            $referenceList = XmlSecurityEnc::locateReferenceList($security);
90
            // get a list of encrypted nodes
91
92
            $encryptedNodes = XmlSecurityEnc::locateEncryptedData($dom, $referenceList);
93
94
            // decrypt them
95
            if (null !== $encryptedNodes) {
96
97
                foreach ($encryptedNodes as $encryptedNode) {
98
                    XmlSecurityEnc::decryptNode($encryptedNode);
99
                }
100
            }
101
            // locate signature node
102
            $signature = XmlSecurityDSig::locateSignature($security);
103
            if (null !== $signature) {
104
                // verify references
105
                $options = array(
106
                    'id_ns_prefix' => 'wsu', // used only for the xpath prefix
107
                    'id_prefix_ns' => self::NS_WSU
108
                );
109
                if (XmlSecurityDSig::verifyReferences($signature, $options) !== true) {
110
                    throw new ClientException('The node signature or decryption was invalid');
111
                }
112
                // verify signature
113
                if (XmlSecurityDSig::verifyDocumentSignature($signature) !== true) {
114
                    throw new ClientException('The document signature or decryption was invalid');
115
                }
116
            }
117
118
            $security->parentNode->removeChild($security);
119
        }
120
    }
121
}
122