Test Setup Failed
Push — master ( 4e700f...c7183e )
by Julito
63:12
created

WSSESoapServer   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 155
rs 9.8
c 0
b 0
f 0
wmc 31
lcom 2
cbo 3
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)) {
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