From 1b5e86183a72b7b10b6c89e4f95f08c5da9716db Mon Sep 17 00:00:00 2001 From: matthew Date: Fri, 17 Aug 2012 19:50:08 +0000 Subject: [PATCH] Fixes for potential XXE/XEE vulnerabilities - Patch provided by Padriac Brady, reviewed by Ralph Schindler and Matthew Weier O'Phinney - Merged from r25031 git-svn-id: http://framework.zend.com/svn/framework/standard/branches/release-1.12@25033 44c647ce-9c0f-0410-b52a-842ac1e357ba --- library/Zend/Dom/Query.php | 10 + library/Zend/Feed/Reader.php | 23 +- library/Zend/Serializer/Adapter/Wddx.php | 14 +- library/Zend/Soap/Client/Local.php | 7 + library/Zend/Soap/Server.php | 23 +- library/Zend/Soap/Wsdl.php | 12 + library/Zend/XmlRpc/Request.php | 12 +- library/Zend/XmlRpc/Response.php | 12 + tests/Zend/Dom/QueryTest.php | 14 + .../Feed/Reader/_files/Reader/xxe-atom10.xml | 5 + .../Feed/Reader/_files/Reader/xxe-info.txt | 1 + tests/Zend/Feed/ReaderTest.php | 8 + tests/Zend/Serializer/Adapter/WddxTest.php | 22 + tests/Zend/Soap/ServerTest.php | 41 +- tests/Zend/Soap/TestAsset/commontypes.php | 634 ++++++++++++++++++ tests/Zend/XmlRpc/RequestTest.php | 10 + tests/Zend/XmlRpc/ResponseTest.php | 7 + 17 files changed, 847 insertions(+), 8 deletions(-) create mode 100644 tests/Zend/Feed/Reader/_files/Reader/xxe-atom10.xml create mode 100644 tests/Zend/Feed/Reader/_files/Reader/xxe-info.txt create mode 100644 tests/Zend/Soap/TestAsset/commontypes.php diff --git a/library/Zend/Dom/Query.php b/library/Zend/Dom/Query.php index 897714f6b8..41d0286d43 100644 --- a/library/Zend/Dom/Query.php +++ b/library/Zend/Dom/Query.php @@ -245,6 +245,7 @@ public function queryXpath($xpathQuery, $query = null) $encoding = $this->getEncoding(); libxml_use_internal_errors(true); + libxml_disable_entity_loader(true); if (null === $encoding) { $domDoc = new DOMDocument('1.0'); } else { @@ -254,6 +255,14 @@ public function queryXpath($xpathQuery, $query = null) switch ($type) { case self::DOC_XML: $success = $domDoc->loadXML($document); + foreach ($domDoc->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/Dom/Exception.php'; + throw new Zend_Dom_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } break; case self::DOC_HTML: case self::DOC_XHTML: @@ -266,6 +275,7 @@ public function queryXpath($xpathQuery, $query = null) $this->_documentErrors = $errors; libxml_clear_errors(); } + libxml_disable_entity_loader(false); libxml_use_internal_errors(false); if (!$success) { diff --git a/library/Zend/Feed/Reader.php b/library/Zend/Feed/Reader.php index 7666cde055..49aef04c6e 100644 --- a/library/Zend/Feed/Reader.php +++ b/library/Zend/Feed/Reader.php @@ -333,10 +333,19 @@ public static function importFeed(Zend_Feed_Abstract $feed) */ public static function importString($string) { - $libxml_errflag = libxml_use_internal_errors(true); + $oldValue = libxml_disable_entity_loader(true); $dom = new DOMDocument; $status = $dom->loadXML($string); + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } + libxml_disable_entity_loader($oldValue); libxml_use_internal_errors($libxml_errflag); if (!$status) { @@ -407,8 +416,10 @@ public static function findFeedLinks($uri) } $responseHtml = $response->getBody(); $libxml_errflag = libxml_use_internal_errors(true); + $oldValue = libxml_disable_entity_loader(true); $dom = new DOMDocument; $status = $dom->loadHTML($responseHtml); + libxml_disable_entity_loader($oldValue); libxml_use_internal_errors($libxml_errflag); if (!$status) { // Build error message @@ -442,8 +453,18 @@ public static function detectType($feed, $specOnly = false) $dom = $feed; } elseif(is_string($feed) && !empty($feed)) { @ini_set('track_errors', 1); + $oldValue = libxml_disable_entity_loader(true); $dom = new DOMDocument; $status = @$dom->loadXML($feed); + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } + libxml_disable_entity_loader($oldValue); @ini_restore('track_errors'); if (!$status) { if (!isset($php_errormsg)) { diff --git a/library/Zend/Serializer/Adapter/Wddx.php b/library/Zend/Serializer/Adapter/Wddx.php index e45f2a7501..dfa98d69b3 100644 --- a/library/Zend/Serializer/Adapter/Wddx.php +++ b/library/Zend/Serializer/Adapter/Wddx.php @@ -100,7 +100,19 @@ public function unserialize($wddx, array $opts = array()) // check if the returned NULL is valid // or based on an invalid wddx string try { - $simpleXml = new SimpleXMLElement($wddx); + $oldLibxmlDisableEntityLoader = libxml_disable_entity_loader(true); + $dom = new DOMDocument; + $dom->loadXML($wddx); + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/Serializer/Exception.php'; + throw new Zend_Serializer_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } + $simpleXml = simplexml_import_dom($dom); + libxml_disable_entity_loader($oldLibxmlDisableEntityLoader); if (isset($simpleXml->data[0]->null[0])) { return null; // valid null } diff --git a/library/Zend/Soap/Client/Local.php b/library/Zend/Soap/Client/Local.php index 5c0b99addb..6cb5721bae 100644 --- a/library/Zend/Soap/Client/Local.php +++ b/library/Zend/Soap/Client/Local.php @@ -84,6 +84,13 @@ public function _doRequest(Zend_Soap_Client_Common $client, $request, $location, ob_start(); $this->_server->handle($request); $response = ob_get_clean(); + + if ($response === null || $response === '') { + $serverResponse = $this->server->getResponse(); + if ($serverResponse !== null) { + $response = $serverResponse; + } + } return $response; } diff --git a/library/Zend/Soap/Server.php b/library/Zend/Soap/Server.php index 13a53b5687..a615167535 100644 --- a/library/Zend/Soap/Server.php +++ b/library/Zend/Soap/Server.php @@ -729,11 +729,21 @@ protected function _setRequest($request) $xml = $request; } + libxml_disable_entity_loader(true); $dom = new DOMDocument(); if(strlen($xml) == 0 || !$dom->loadXML($xml)) { require_once 'Zend/Soap/Server/Exception.php'; throw new Zend_Soap_Server_Exception('Invalid XML'); } + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/Soap/Server/Exception.php'; + throw new Zend_Soap_Server_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } + libxml_disable_entity_loader(false); } $this->_request = $xml; return $this; @@ -866,16 +876,16 @@ public function handle($request = null) $soap = $this->_getSoap(); + $fault = false; ob_start(); - if($setRequestException instanceof Exception) { - // Send SOAP fault message if we've catched exception - $soap->fault("Sender", $setRequestException->getMessage()); + if ($setRequestException instanceof Exception) { + // Create SOAP fault message if we've caught a request exception + $fault = $this->fault($setRequestException->getMessage(), 'Sender'); } else { try { $soap->handle($this->_request); } catch (Exception $e) { $fault = $this->fault($e); - $soap->fault($fault->faultcode, $fault->faultstring); } } $this->_response = ob_get_clean(); @@ -884,6 +894,11 @@ public function handle($request = null) restore_error_handler(); ini_set('display_errors', $displayErrorsOriginalState); + // Send a fault, if we have one + if ($fault) { + $this->_response = $fault; + } + if (!$this->_returnResponse) { echo $this->_response; return; diff --git a/library/Zend/Soap/Wsdl.php b/library/Zend/Soap/Wsdl.php index 1ec94d0c44..c33146dfca 100644 --- a/library/Zend/Soap/Wsdl.php +++ b/library/Zend/Soap/Wsdl.php @@ -96,13 +96,23 @@ public function __construct($name, $uri, $strategy = true) xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap-enc='http://schemas.xmlsoap.org/soap/encoding/' xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'>"; + libxml_disable_entity_loader(true); $this->_dom = new DOMDocument(); if (!$this->_dom->loadXML($wsdl)) { require_once 'Zend/Server/Exception.php'; throw new Zend_Server_Exception('Unable to create DomDocument'); } else { + foreach ($this->_dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } $this->_wsdl = $this->_dom->documentElement; } + libxml_disable_entity_loader(false); $this->setComplexTypeStrategy($strategy); } @@ -125,8 +135,10 @@ public function setUri($uri) // @todo: This is the worst hack ever, but its needed due to design and non BC issues of WSDL generation $xml = $this->_dom->saveXML(); $xml = str_replace($oldUri, $uri, $xml); + libxml_disable_entity_loader(true); $this->_dom = new DOMDocument(); $this->_dom->loadXML($xml); + libxml_disable_entity_loader(false); } return $this; diff --git a/library/Zend/XmlRpc/Request.php b/library/Zend/XmlRpc/Request.php index 3ca3eee40b..0b8dfc1de6 100644 --- a/library/Zend/XmlRpc/Request.php +++ b/library/Zend/XmlRpc/Request.php @@ -306,7 +306,17 @@ public function loadXml($request) // @see ZF-12293 - disable external entities for security purposes $loadEntities = libxml_disable_entity_loader(true); try { - $xml = new SimpleXMLElement($request); + $dom = new DOMDocument; + $dom->loadXML($request); + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/XmlRpc/Exception.php'; + throw new Zend_XmlRpc_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } + $xml = simplexml_import_dom($dom); libxml_disable_entity_loader($loadEntities); } catch (Exception $e) { // Not valid XML diff --git a/library/Zend/XmlRpc/Response.php b/library/Zend/XmlRpc/Response.php index a0c51c62d6..bbafab6372 100644 --- a/library/Zend/XmlRpc/Response.php +++ b/library/Zend/XmlRpc/Response.php @@ -180,6 +180,18 @@ public function loadXml($response) $loadEntities = libxml_disable_entity_loader(true); $useInternalXmlErrors = libxml_use_internal_errors(true); try { + $dom = new DOMDocument; + $dom->loadXML($response); + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + require_once 'Zend/XmlRpc/Exception.php'; + throw new Zend_XmlRpc_Exception( + 'Invalid XML: Detected use of illegal DOCTYPE' + ); + } + } + // TODO: Locate why this passes tests but a simplexml import doesn't + // $xml = simplexml_import_dom($dom); $xml = new SimpleXMLElement($response); libxml_disable_entity_loader($loadEntities); libxml_use_internal_errors($useInternalXmlErrors); diff --git a/tests/Zend/Dom/QueryTest.php b/tests/Zend/Dom/QueryTest.php index 059d10a5ca..8abe688fcf 100644 --- a/tests/Zend/Dom/QueryTest.php +++ b/tests/Zend/Dom/QueryTest.php @@ -348,6 +348,20 @@ public function testXhtmlDocumentWithXmlAndDoctypeDeclaration() $this->query->setDocument($xhtmlWithXmlDecl, 'utf-8'); $this->assertEquals(1, $this->query->query('//p')->count()); } + + public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttacks() + { + $xml = << +]> + + This result is &harmless; + +XML; + $this->query->setDocumentXml($xml); + $this->setExpectedException("Zend_Dom_Exception"); + $this->query->queryXpath('/'); + } } // Call Zend_Dom_QueryTest::main() if this source file is executed directly. diff --git a/tests/Zend/Feed/Reader/_files/Reader/xxe-atom10.xml b/tests/Zend/Feed/Reader/_files/Reader/xxe-atom10.xml new file mode 100644 index 0000000000..6a4a47d567 --- /dev/null +++ b/tests/Zend/Feed/Reader/_files/Reader/xxe-atom10.xml @@ -0,0 +1,5 @@ + + ]> + + info:&discloseInfo; + diff --git a/tests/Zend/Feed/Reader/_files/Reader/xxe-info.txt b/tests/Zend/Feed/Reader/_files/Reader/xxe-info.txt new file mode 100644 index 0000000000..603572bbbd --- /dev/null +++ b/tests/Zend/Feed/Reader/_files/Reader/xxe-info.txt @@ -0,0 +1 @@ +xxe-information-disclosed diff --git a/tests/Zend/Feed/ReaderTest.php b/tests/Zend/Feed/ReaderTest.php index 418a061a80..19dafc0f1f 100644 --- a/tests/Zend/Feed/ReaderTest.php +++ b/tests/Zend/Feed/ReaderTest.php @@ -336,6 +336,14 @@ public function testImportingUriWithEmptyResponseBodyTriggersException() $result = Zend_Feed_Reader::import('http://www.example.com'); } + public function testXxePreventionOnFeedParsing() + { + $string = file_get_contents($this->_feedSamplePath.'/Reader/xxe-atom10.xml'); + $string = str_replace('XXE_URI', $this->_feedSamplePath.'/Reader/xxe-info.txt', $string); + $this->setExpectedException('Zend_Feed_Exception'); + $feed = Zend_Feed_Reader::importString($string); + } + protected function _getTempDirectory() { $tmpdir = array(); diff --git a/tests/Zend/Serializer/Adapter/WddxTest.php b/tests/Zend/Serializer/Adapter/WddxTest.php index c5c22ac41f..f224f4563c 100644 --- a/tests/Zend/Serializer/Adapter/WddxTest.php +++ b/tests/Zend/Serializer/Adapter/WddxTest.php @@ -221,6 +221,28 @@ public function testSerializeStringUtf8() { $this->assertEquals($expected, $data); } + public function testUnserializeInvalidXml() + { + if (!class_exists('SimpleXMLElement', false)) { + $this->markTestSkipped('Skipped by missing ext/simplexml'); + } + + $value = 'not a serialized string'; + $this->setExpectedException( + 'Zend_Serializer_Exception', + 'DOMDocument::loadXML(): Start tag expected' + ); + $this->_adapter->unserialize($value); + } + + public function testShouldThrowExceptionIfXmlToUnserializeFromContainsADoctype() + { + $value = '' + . '
' + . 'test'; + $this->setExpectedException("Zend_Serializer_Exception"); + $data = $this->_adapter->unserialize($value); + } } diff --git a/tests/Zend/Soap/ServerTest.php b/tests/Zend/Soap/ServerTest.php index 47652190bc..08e2c76238 100644 --- a/tests/Zend/Soap/ServerTest.php +++ b/tests/Zend/Soap/ServerTest.php @@ -27,6 +27,8 @@ require_once "Zend/Config.php"; +require_once dirname(__FILE__) . '/TestAsset/commontypes.php'; + /** * Zend_Soap_Server * @@ -542,6 +544,9 @@ public function testGetPersistence() $this->assertEquals(SOAP_PERSISTENCE_SESSION, $server->getPersistence()); } + /** + * @runInSeparateProcess + */ public function testGetLastRequest() { if (headers_sent()) { @@ -575,6 +580,9 @@ public function testGetLastRequest() $this->assertEquals($request, $server->getLastRequest()); } + /** + * @runInSeparateProcess + */ public function testWsiCompliant() { $server = new Zend_Soap_Server(null, array('wsi_compliant' => true)); @@ -877,11 +885,13 @@ public function testLoadFunctionsIsNotImplemented() } } + /** + * @runInSeparateProcess + */ public function testErrorHandlingOfSoapServerChangesToThrowingSoapFaultWhenInHandleMode() { if (headers_sent()) { $this->markTestSkipped('Cannot run ' . __METHOD__ . '() when headers have already been sent; enable output buffering to run this test'); - return; } $server = new Zend_Soap_Server(); @@ -967,6 +977,35 @@ public function testHandleUsesProperRequestParameter() $r = $server->handle(new DomDocument('1.0', 'UTF-8')); $this->assertTrue(is_string($server->mockSoapServer->handle[0])); } + + /** + * @runInSeparateProcess + */ + public function testShouldThrowExceptionIfHandledRequestContainsDoctype() + { + $server = new Zend_Soap_Server(); + $server->setOptions(array('location'=>'test://', 'uri'=>'http://framework.zend.com')); + $server->setReturnResponse(true); + + $server->setClass('Zend_Soap_TestAsset_ServerTestClass'); + + $request = + '' . "\n" . '' . "\n" + . '' + . '' + . '' + . 'World' + . '' + . '' + . '' . "\n"; + $response = $server->handle($request); + $this->assertContains('Invalid XML', $response->getMessage()); + } } diff --git a/tests/Zend/Soap/TestAsset/commontypes.php b/tests/Zend/Soap/TestAsset/commontypes.php new file mode 100644 index 0000000000..bf1edacdfa --- /dev/null +++ b/tests/Zend/Soap/TestAsset/commontypes.php @@ -0,0 +1,634 @@ + 'bar', 'baz' => true, 1 => false, 'bat' => 123); +} + +/** + * Return Object + * + * @return StdClass + */ +function Zend_Soap_TestAsset_TestFunc8() +{ + $return = (object) array('foo' => 'bar', 'baz' => true, 'bat' => 123, 'qux' => false); + return $return; +} + +/** + * Multiple Args + * + * @param string $foo + * @param string $bar + * @return string + */ +function Zend_Soap_TestAsset_TestFunc9($foo, $bar) +{ + return "$foo $bar"; +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_TestFixingMultiplePrototypes +{ + /** + * Test function + * + * @param integer $a + * @param integer $b + * @param integer $d + * @return integer + */ + public function testFunc($a=100, $b=200, $d=300) + { + + } +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_Test +{ + /** + * Test Function 1 + * + * @return string + */ + public function testFunc1() + { + return "Hello World"; + } + + /** + * Test Function 2 + * + * @param string $who Some Arg + * @return string + */ + public function testFunc2($who) + { + return "Hello $who!"; + } + + /** + * Test Function 3 + * + * @param string $who Some Arg + * @param int $when Some + * @return string + */ + public function testFunc3($who, $when) + { + return "Hello $who, How are you $when"; + } + + /** + * Test Function 4 + * + * @return string + */ + public static function testFunc4() + { + return "I'm Static!"; + } +} + +class Zend_Soap_TestAsset_AutoDiscoverTestClass1 +{ + /** + * @var integer $var + */ + public $var = 1; + + /** + * @var string $param + */ + public $param = "hello"; +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_AutoDiscoverTestClass2 +{ + /** + * + * @param Zend_Soap_TestAsset_AutoDiscoverTestClass1 $test + * @return boolean + */ + public function add(AutoDiscoverTestClass1 $test) + { + return true; + } + + /** + * @return Zend_Soap_TestAsset_AutoDiscoverTestClass1[] + */ + public function fetchAll() + { + return array( + new AutoDiscoverTestClass1(), + new AutoDiscoverTestClass1(), + ); + } + + /** + * @param Zend_Soap_TestAsset_AutoDiscoverTestClass1[] + */ + public function addMultiple($test) + { + + } +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_ComplexTypeB +{ + /** + * @var string + */ + public $bar; + /** + * @var string + */ + public $foo; +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_ComplexTypeA +{ + /** + * @var Zend_Soap_TestAsset_ComplexTypeB[] + */ + public $baz = array(); +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_ComplexTest +{ + /** + * @var int + */ + public $var = 5; +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_ComplexObjectStructure +{ + /** + * @var boolean + */ + public $boolean = true; + + /** + * @var string + */ + public $string = "Hello World"; + + /** + * @var int + */ + public $int = 10; + + /** + * @var array + */ + public $array = array(1, 2, 3); +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_ComplexObjectWithObjectStructure +{ + /** + * @var Zend_Soap_TestAsset_ComplexTest + */ + public $object; +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_MyService +{ + /** + * @param string $foo + * @return Zend_Soap_TestAsset_MyResponse[] + */ + public function foo($foo) + { + } + /** + * @param string $bar + * @return Zend_Soap_TestAsset_MyResponse[] + */ + public function bar($bar) + { + } + + /** + * @param string $baz + * @return Zend_Soap_TestAsset_MyResponse[] + */ + public function baz($baz) + { + } +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_MyServiceSequence +{ + /** + * @param string $foo + * @return string[] + */ + public function foo($foo) + { + } + /** + * @param string $bar + * @return string[] + */ + public function bar($bar) + { + } + + /** + * @param string $baz + * @return string[] + */ + public function baz($baz) + { + } + + /** + * @param string $baz + * @return string[][][] + */ + public function bazNested($baz) + { + } +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_MyResponse +{ + /** + * @var string + */ + public $p1; +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_Recursion +{ + /** + * @var Zend_Soap_TestAsset_Recursion + */ + public $recursion; + + /** + * @return Zend_Soap_TestAsset_Recursion + */ + public function create() {} +} + +/** + * @param string $message + */ +function Zend_Soap_TestAsset_OneWay($message) +{ + +} + +/** + * @category Zend + * @package Zend_Soap + * @subpackage UnitTests + */ +class Zend_Soap_TestAsset_NoReturnType +{ + /** + * + * @param string $message + */ + public function pushOneWay($message) + { + + } +} + +/* Client test classes */ +/** Test Class */ +class Zend_Soap_TestAsset_TestClass +{ + /** + * Test Function 1 + * + * @return string + */ + public function testFunc1() + { + return "Hello World"; + } + + /** + * Test Function 2 + * + * @param string $who Some Arg + * @return string + */ + public function testFunc2($who) + { + return "Hello $who!"; + } + + /** + * Test Function 3 + * + * @param string $who Some Arg + * @param int $when Some + * @return string + */ + public function testFunc3($who, $when) + { + return "Hello $who, How are you $when"; + } + + /** + * Test Function 4 + * + * @return string + */ + public static function testFunc4() + { + return "I'm Static!"; + } +} + +/** Test class 2 */ +class Zend_Soap_TestAsset_TestData1 +{ + /** + * Property1 + * + * @var string + */ + public $property1; + + /** + * Property2 + * + * @var float + */ + public $property2; +} + +/** Test class 2 */ +class Zend_Soap_TestAsset_TestData2 +{ + /** + * Property1 + * + * @var integer + */ + public $property1; + + /** + * Property1 + * + * @var float + */ + public $property2; +} + +class Zend_Soap_TestAsset_MockSoapServer +{ + public $handle = null; + public function handle() + { + $this->handle = func_get_args(); + } + public function __call($name, $args) {} +} + +class Zend_Soap_TestAsset_MockServer extends Zend_Soap_Server +{ + public $mockSoapServer = null; + protected function _getSoap() + { + $this->mockSoapServer = new MockSoapServer(); + return $this->mockSoapServer; + } +} + + +/** Server test classes */ +class Zend_Soap_TestAsset_ServerTestClass +{ + /** + * Test Function 1 + * + * @return string + */ + public function testFunc1() + { + return "Hello World"; + } + + /** + * Test Function 2 + * + * @param string $who Some Arg + * @return string + */ + public function testFunc2($who) + { + return "Hello $who!"; + } + + /** + * Test Function 3 + * + * @param string $who Some Arg + * @param int $when Some + * @return string + */ + public function testFunc3($who, $when) + { + return "Hello $who, How are you $when"; + } + + /** + * Test Function 4 + * + * @return string + */ + public static function testFunc4() + { + return "I'm Static!"; + } + + /** + * Test Function 5 raises a user error + * + * @return void + */ + public function testFunc5() + { + trigger_error("Test Message", E_USER_ERROR); + } +} + +if (extension_loaded('soap')) { + +/** Local SOAP client */ +class Zend_Soap_TestAsset_TestLocalSoapClient extends SoapClient +{ + /** + * Server object + * + * @var Zend_Soap_Server + */ + public $server; + + /** + * Local client constructor + * + * @param Zend_Soap_Server $server + * @param string $wsdl + * @param array $options + */ + public function __construct(Zend_Soap_Server $server, $wsdl, $options) + { + $this->server = $server; + parent::__construct($wsdl, $options); + } + + public function __doRequest($request, $location, $action, $version, $one_way = 0) + { + ob_start(); + $this->server->handle($request); + $response = ob_get_clean(); + + return $response; + } +} + +} diff --git a/tests/Zend/XmlRpc/RequestTest.php b/tests/Zend/XmlRpc/RequestTest.php index db1cbc71f3..50d028229e 100644 --- a/tests/Zend/XmlRpc/RequestTest.php +++ b/tests/Zend/XmlRpc/RequestTest.php @@ -352,6 +352,9 @@ public function testSetGetEncoding() /** * @group ZF-12293 ++ * ++ * Test should remain, but is defunct since DOCTYPE presence should return FALSE ++ * from loadXml() */ public function testDoesNotAllowExternalEntities() { @@ -364,4 +367,11 @@ public function testDoesNotAllowExternalEntities() $this->assertNotContains('Local file inclusion', $method); } } + + public function testShouldDisallowsDoctypeInRequestXmlAndReturnFalseOnLoading() + { + $payload = file_get_contents(dirname(__FILE__) . '/_files/ZF12293-request.xml'); + $payload = sprintf($payload, 'file://' . realpath(dirname(__FILE__) . '/_files/ZF12293-payload.txt')); + $this->assertFalse($this->_request->loadXml($payload)); + } } diff --git a/tests/Zend/XmlRpc/ResponseTest.php b/tests/Zend/XmlRpc/ResponseTest.php index ac70087dc7..f6bc7957c3 100644 --- a/tests/Zend/XmlRpc/ResponseTest.php +++ b/tests/Zend/XmlRpc/ResponseTest.php @@ -267,4 +267,11 @@ public function testDoesNotAllowExternalEntities() $this->assertNotContains('Local file inclusion', $value); } } + + public function testShouldDisallowsDoctypeInRequestXmlAndReturnFalseOnLoading() + { + $payload = file_get_contents(dirname(__FILE__) . '/_files/ZF12293-response.xml'); + $payload = sprintf($payload, 'file://' . realpath(dirname(__FILE__) . '/_files/ZF12293-payload.txt')); + $this->assertFalse($this->_response->loadXml($payload)); + } }