Test Setup Failed
Push — master ( f71949...6c6bd7 )
by Julito
55:21
created

WSSESoapServer::locateSecurityHeader()   C

Complexity

Conditions 8
Paths 6

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 17
nc 6
nop 1
dl 0
loc 25
rs 5.3846
c 0
b 0
f 0
1
<?php
2
/**
3
 * soap-server-wsse.php
4
 *
5
 * Copyright (c) 2007, Robert Richards <[email protected]>.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 *
12
 *   * Redistributions of source code must retain the above copyright
13
 *     notice, this list of conditions and the following disclaimer.
14
 *
15
 *   * Redistributions in binary form must reproduce the above copyright
16
 *     notice, this list of conditions and the following disclaimer in
17
 *     the documentation and/or other materials provided with the
18
 *     distribution.
19
 *
20
 *   * Neither the name of Robert Richards nor the names of his
21
 *     contributors may be used to endorse or promote products derived
22
 *     from this software without specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
 * POSSIBILITY OF SUCH DAMAGE.
36
 *
37
 * @author     Robert Richards <[email protected]>
38
 * @copyright  2007 Robert Richards <[email protected]>
39
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
40
 * @version    1.0.0
41
 */
42
43
require('xmlseclibs.php');
44
45
class WSSESoapServer {
46
    const WSSENS = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
47
    const WSSENS_2003 = 'http://schemas.xmlsoap.org/ws/2003/06/secext';
48
    const WSUNS = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
49
    const WSSEPFX = 'wsse';
50
    const WSUPFX = 'wsu';
51
    private $soapNS, $soapPFX;
52
    private $soapDoc = NULL;
53
    private $envelope = NULL;
54
    private $SOAPXPath = NULL;
55
    private $secNode = NULL;
56
    public $signAllHeaders = FALSE;
57
58
    private function locateSecurityHeader($setActor=NULL) {
59
        $wsNamespace = NULL;
60
        if ($this->secNode == NULL) {
61
            $secnode = NULL;
62
            $headers = $this->SOAPXPath->query('//wssoap:Envelope/wssoap:Header');
63
            if ($header = $headers->item(0)) {
64
                $secnodes = $this->SOAPXPath->query('./*[local-name()="Security"]', $header);
65
66
                foreach ($secnodes AS $node) {
67
                    $nsURI = $node->namespaceURI;
68
                    if (($nsURI == self::WSSENS) || ($nsURI == self::WSSENS_2003)) {
69
                        $actor = $node->getAttributeNS($this->soapNS, 'actor');
70
                        if (empty($actor) || ($actor == $setActor)) {
71
                            $secnode = $node;
72
                            $wsNamespace = $nsURI;
73
                            break;
74
                        }
75
                    }
76
                }
77
            }
78
            $this->secNode = $secnode;
79
        }
80
81
        return $wsNamespace;
82
    }
83
84
    public function __construct($doc)
85
    {
86
        $this->soapDoc = $doc;
87
        $this->envelope = $doc->documentElement;
88
89
        $this->soapNS = $this->envelope->namespaceURI;
90
        $this->soapPFX = $this->envelope->prefix;
91
92
        $this->SOAPXPath = new DOMXPath($doc);
93
        $this->SOAPXPath->registerNamespace('wssoap', $this->soapNS);
94
        $this->SOAPXPath->registerNamespace('wswsu', self::WSUNS);
95
        $wsNamespace = $this->locateSecurityHeader();
96
        if (!empty($wsNamespace)) {
97
            $this->SOAPXPath->registerNamespace('wswsse', $wsNamespace);
98
        }
99
    }
100
101
    public function processSignature($refNode)
102
    {
103
        $objXMLSecDSig = new XMLSecurityDSig();
104
        $objXMLSecDSig->idKeys[] = 'wswsu:Id';
105
        $objXMLSecDSig->idNS['wswsu'] = self::WSUNS;
106
        $objXMLSecDSig->sigNode = $refNode;
107
108
        /* Canonicalize the signed info */
109
        $objXMLSecDSig->canonicalizeSignedInfo();
110
        $retVal = $objXMLSecDSig->validateReference();
111
112
        if (! $retVal) {
113
            throw new Exception("Validation Failed");
114
        }
115
116
        $key = NULL;
117
        $objKey = $objXMLSecDSig->locateKey();
118
119
        if ($objKey) {
120
            if ($objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $refNode)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
121
                /* Handle any additional key processing such as encrypted keys here */
122
            }
123
        }
124
125
        if (empty($objKey)) {
126
            throw new Exception("Error loading key to handle Signature");
127
        }
128
        do {
129
            if (empty($objKey->key)) {
130
                $this->SOAPXPath->registerNamespace('xmlsecdsig', XMLSecurityDSig::XMLDSIGNS);
131
                $query = "./xmlsecdsig:KeyInfo/wswsse:SecurityTokenReference/wswsse:Reference";
132
                $nodeset = $this->SOAPXPath->query($query, $refNode);
133
                if ($encmeth = $nodeset->item(0)) {
134
                    if ($uri = $encmeth->getAttribute("URI")) {
135
136
                        $arUrl = parse_url($uri);
137
138
                        if (empty($arUrl['path']) && ($identifier = $arUrl['fragment'])) {
139
                            $query = '//wswsse:BinarySecurityToken[@wswsu:Id="'.$identifier.'"]';
140
                            $nodeset = $this->SOAPXPath->query($query);
141
                            if ($encmeth = $nodeset->item(0)) {
142
                                $x509cert = $encmeth->textContent;
143
                                $x509cert = str_replace(array("\r", "\n"), "", $x509cert);
144
                                $x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
145
146
                                $objKey->loadKey($x509cert);
147
                                break;
148
                            }
149
                        }
150
                    }
151
                }
152
                throw new Exception("Error loading key to handle Signature");
153
            }
154
        } while(0);
155
156
        if (! $objXMLSecDSig->verify($objKey)) {
157
            throw new Exception("Unable to validate Signature");
158
        }
159
160
        return true;
161
    }
162
163
    public function process()
164
    {
165
        if (empty($this->secNode)) {
166
            return;
167
        }
168
        $node = $this->secNode->firstChild;
169
        while ($node) {
170
            $nextNode = $node->nextSibling;
171
            switch ($node->localName) {
172
                case "Signature":
173
                    if ($this->processSignature($node)) {
174
                        if ($node->parentNode) {
175
                            $node->parentNode->removeChild($node);
176
                        }
177
                    } else {
178
                        /* throw fault */
179
                        return false;
180
                    }
181
            }
182
            $node = $nextNode;
183
        }
184
        $this->secNode->parentNode->removeChild($this->secNode);
185
        $this->secNode = NULL;
186
187
        return true;
188
    }
189
190
    public function saveXML()
191
    {
192
        return $this->soapDoc->saveXML();
193
    }
194
195
    public function save($file)
196
    {
197
        return $this->soapDoc->save($file);
198
    }
199
}
200
201