| @@ -1,2 +1,7 @@ | |||
| *.egg-info | |||
| MANIFEST.in | |||
| build/ | |||
| dist/ | |||
| setup.cfg | |||
| venv/ | |||
| *.pyc | |||
| @@ -3,6 +3,8 @@ CHANGELOG | |||
| 0.12.6 (unreleased) | |||
| ----------------------- | |||
| - fix cve CVE Request ---- SOAPpy 0.12.5 Multiple Vulnerabilities -- XXE part | |||
| [kiorky] | |||
| - Remove dependency on fpconst. | |||
| - adding maptype [Sandro Knauß] | |||
| - Support / (and other reserved characters) in the password. [Ionut Turturica] | |||
| @@ -0,0 +1,10 @@ | |||
| include *.txt *.cfg *.rst | |||
| recursive-include validate * | |||
| recursive-include contrib * | |||
| recursive-include src * | |||
| recursive-include tests * | |||
| recursive-include tools * | |||
| recursive-include zope * | |||
| recursive-include docs * | |||
| recursive-include bid * | |||
| global-exclude *pyc | |||
| @@ -1,4 +1,5 @@ | |||
| # SOAPpy modules | |||
| import traceback | |||
| from Config import Config | |||
| from Types import * | |||
| from NS import NS | |||
| @@ -7,6 +8,10 @@ from Utilities import * | |||
| import string | |||
| import xml.sax | |||
| from wstools.XMLname import fromXMLname | |||
| try: | |||
| from cStringIO import StringIO | |||
| except ImportError: | |||
| from StringIO import StringIO | |||
| try: from M2Crypto import SSL | |||
| except: pass | |||
| @@ -93,7 +98,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| elif prefix: | |||
| tag = prefix + ":" + tag | |||
| return tag | |||
| # Workaround two sax bugs | |||
| if name[0] == None and name[1][0] == ' ': | |||
| name = (None, name[1][1:]) | |||
| @@ -127,7 +132,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| elif self._next == "": | |||
| raise Error, "expected nothing, " \ | |||
| "got `%s'" % toStr( name ) | |||
| if len(self._stack) == 2: | |||
| rules = self._rules | |||
| @@ -275,7 +280,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| null = 1 | |||
| # check for nil=1, but watch out for string values | |||
| try: | |||
| try: | |||
| null = int(null) | |||
| except ValueError, e: | |||
| if not e[0].startswith("invalid literal for int()"): | |||
| @@ -312,7 +317,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| #print "cur.kind=", cur.kind | |||
| #print "cur.rules=", cur.rules | |||
| #print "\n" | |||
| if cur.rules != None: | |||
| rule = cur.rules | |||
| @@ -374,7 +379,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| # print "ns:", ns | |||
| # print "attrs:", attrs | |||
| # print "kind:", kind | |||
| if kind == None: | |||
| # If the current item's container is an array, it will | |||
| @@ -863,7 +868,7 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| # print " attrs=", attrs | |||
| # print " t[0]=", t[0] | |||
| # print " t[1]=", t[1] | |||
| # print " in?", t[0] in NS.EXSD_L | |||
| if t[0] in NS.EXSD_L: | |||
| @@ -933,11 +938,11 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| elif d == 0: | |||
| if type(self.zerofloatre) == StringType: | |||
| self.zerofloatre = re.compile(self.zerofloatre) | |||
| if self.zerofloatre.search(s): | |||
| raise UnderflowError, "invalid %s: %s" % (t[1], s) | |||
| return d | |||
| if t[1] in ("dateTime", "date", "timeInstant", "time"): | |||
| return self.convertDateTime(d, t[1]) | |||
| if t[1] == "decimal": | |||
| @@ -1031,14 +1036,17 @@ class SOAPParser(xml.sax.handler.ContentHandler): | |||
| ################################################################################ | |||
| # call to SOAPParser that keeps all of the info | |||
| ################################################################################ | |||
| def _parseSOAP(xml_str, rules = None): | |||
| try: | |||
| from cStringIO import StringIO | |||
| except ImportError: | |||
| from StringIO import StringIO | |||
| class EmptyEntityResolver(xml.sax.handler.EntityResolver): | |||
| def resolveEntity(self, publicId, systemId): | |||
| return StringIO("<?xml version='1.0' encoding='UTF-8'?>") | |||
| def _parseSOAP(xml_str, rules = None, ignore_ext=None): | |||
| if ignore_ext is None: | |||
| ignore_ext = False | |||
| parser = xml.sax.make_parser() | |||
| t = SOAPParser(rules = rules) | |||
| t = SOAPParser(rules=rules) | |||
| parser.setContentHandler(t) | |||
| e = xml.sax.handler.ErrorHandler() | |||
| parser.setErrorHandler(e) | |||
| @@ -1046,15 +1054,19 @@ def _parseSOAP(xml_str, rules = None): | |||
| inpsrc = xml.sax.xmlreader.InputSource() | |||
| inpsrc.setByteStream(StringIO(xml_str)) | |||
| # disable by default entity loading on posted content | |||
| if ignore_ext: | |||
| parser.setEntityResolver(EmptyEntityResolver()) | |||
| # turn on namespace mangeling | |||
| parser.setFeature(xml.sax.handler.feature_namespaces,1) | |||
| parser.setFeature(xml.sax.handler.feature_namespaces, 1) | |||
| try: | |||
| parser.parse(inpsrc) | |||
| except xml.sax.SAXParseException, e: | |||
| parser._parser = None | |||
| print traceback.format_exc() | |||
| raise e | |||
| return t | |||
| ################################################################################ | |||
| @@ -1068,9 +1080,9 @@ def parseSOAP(xml_str, attrs = 0): | |||
| return t.body | |||
| def parseSOAPRPC(xml_str, header = 0, body = 0, attrs = 0, rules = None): | |||
| def parseSOAPRPC(xml_str, header = 0, body = 0, attrs = 0, rules = None, ignore_ext=None): | |||
| t = _parseSOAP(xml_str, rules = rules) | |||
| t = _parseSOAP(xml_str, rules = rules, ignore_ext=ignore_ext) | |||
| p = t.body[0] | |||
| # Empty string, for RPC this translates into a void | |||
| @@ -1080,7 +1092,7 @@ def parseSOAPRPC(xml_str, header = 0, body = 0, attrs = 0, rules = None): | |||
| if k[0] != "_": | |||
| name = k | |||
| p = structType(name) | |||
| if header or body or attrs: | |||
| ret = (p,) | |||
| if header : ret += (t.header,) | |||
| @@ -188,8 +188,9 @@ class SOAPServerBase: | |||
| if namespace[0] == ":": namespace = namespace[1:] | |||
| del self.objmap[namespace] | |||
| class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| ignore_ext = True | |||
| def version_string(self): | |||
| return '<a href="http://pywebsvcs.sf.net">' + \ | |||
| 'SOAPpy ' + __version__ + '</a> (Python ' + \ | |||
| @@ -204,7 +205,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| def do_POST(self): | |||
| global _contexts | |||
| status = 500 | |||
| try: | |||
| if self.server.config.dumpHeadersIn: | |||
| @@ -226,7 +227,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| debugFooter(s) | |||
| (r, header, body, attrs) = \ | |||
| parseSOAPRPC(data, header = 1, body = 1, attrs = 1) | |||
| parseSOAPRPC(data, header = 1, body = 1, attrs = 1, ignore_ext=self.ignore_ext) | |||
| method = r._name | |||
| args = r._aslist() | |||
| @@ -252,8 +253,8 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| ordered_args = {} | |||
| named_args = {} | |||
| if Config.specialArgs: | |||
| if Config.specialArgs: | |||
| for (k,v) in kw.items(): | |||
| if k[0]=="v": | |||
| @@ -271,13 +272,13 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| # if r._ns is specified use it, if not check for | |||
| # a path, if it's specified convert it and use it as the | |||
| # namespace. If both are specified, use r._ns. | |||
| ns = r._ns | |||
| if len(self.path) > 1 and not ns: | |||
| ns = self.path.replace("/", ":") | |||
| if ns[0] == ":": ns = ns[1:] | |||
| # authorization method | |||
| a = None | |||
| @@ -291,9 +292,9 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| #print '<-> Argument Matching Yielded:' | |||
| #print '<-> Ordered Arguments:' + str(ordered_args) | |||
| #print '<-> Named Arguments :' + str(named_args) | |||
| resp = "" | |||
| # For fault messages | |||
| if ns: | |||
| nsmethod = "%s:%s" % (ns, method) | |||
| @@ -318,7 +319,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| # there are none, because the split will return | |||
| # [method] | |||
| f = self.server.objmap[ns] | |||
| # Look for the authorization method | |||
| if self.server.config.authMethod != None: | |||
| authmethod = self.server.config.authMethod | |||
| @@ -359,7 +360,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| if "SOAPAction".lower() not in self.headers.keys() or \ | |||
| self.headers["SOAPAction"] == "\"\"": | |||
| self.headers["SOAPAction"] = method | |||
| thread_id = thread.get_ident() | |||
| _contexts[thread_id] = SOAPContext(header, body, | |||
| attrs, data, | |||
| @@ -374,11 +375,11 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| raise faultType("%s:Server" % NS.ENV_T, | |||
| "Authorization failed.", | |||
| "%s" % nsmethod) | |||
| # If it's wrapped, some special action may be needed | |||
| if isinstance(f, MethodSig): | |||
| c = None | |||
| if f.context: # retrieve context object | |||
| c = _contexts[thread_id] | |||
| @@ -389,9 +390,9 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| elif f.keywords: | |||
| # This is lame, but have to de-unicode | |||
| # keywords | |||
| strkw = {} | |||
| for (k, v) in kw.items(): | |||
| strkw[str(k)] = v | |||
| if c: | |||
| @@ -408,7 +409,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| else: | |||
| fr = apply(f, args, {}) | |||
| if type(fr) == type(self) and \ | |||
| isinstance(fr, voidType): | |||
| resp = buildSOAP(kw = {'%sResponse' % method: fr}, | |||
| @@ -423,7 +424,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| # Clean up _contexts | |||
| if _contexts.has_key(thread_id): | |||
| del _contexts[thread_id] | |||
| except Exception, e: | |||
| import traceback | |||
| info = sys.exc_info() | |||
| @@ -558,7 +559,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| self.connection.shutdown(1) | |||
| def do_GET(self): | |||
| #print 'command ', self.command | |||
| #print 'path ', self.path | |||
| #print 'request_version', self.request_version | |||
| @@ -567,7 +568,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| #print ' maintype', self.headers.maintype | |||
| #print ' subtype ', self.headers.subtype | |||
| #print ' params ', self.headers.plist | |||
| path = self.path.lower() | |||
| if path.endswith('wsdl'): | |||
| method = 'wsdl' | |||
| @@ -575,13 +576,13 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| if self.server.funcmap.has_key(namespace) \ | |||
| and self.server.funcmap[namespace].has_key(method): | |||
| function = self.server.funcmap[namespace][method] | |||
| else: | |||
| else: | |||
| if namespace in self.server.objmap.keys(): | |||
| function = self.server.objmap[namespace] | |||
| l = method.split(".") | |||
| for i in l: | |||
| function = getattr(function, i) | |||
| if function: | |||
| self.send_response(200) | |||
| self.send_header("Content-type", 'text/plain') | |||
| @@ -589,7 +590,7 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| response = apply(function, ()) | |||
| self.wfile.write(str(response)) | |||
| return | |||
| # return error | |||
| self.send_response(200) | |||
| self.send_header("Content-type", 'text/html') | |||
| @@ -614,13 +615,17 @@ class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| </body>''') | |||
| def log_message(self, format, *args): | |||
| if self.server.log: | |||
| BaseHTTPServer.BaseHTTPRequestHandler.\ | |||
| log_message (self, format, *args) | |||
| class SOAPInsecureRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||
| '''Request handler that does load POSTed doctypes''' | |||
| ignore_ext = False | |||
| class SOAPServer(SOAPServerBase, SocketServer.TCPServer): | |||
| @@ -679,19 +684,19 @@ class ThreadingSOAPServer(SOAPServerBase, SocketServer.ThreadingTCPServer): | |||
| if hasattr(socket, "AF_UNIX"): | |||
| class SOAPUnixSocketServer(SOAPServerBase, SocketServer.UnixStreamServer): | |||
| def __init__(self, addr = 8000, | |||
| RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', | |||
| config = Config, namespace = None, ssl_context = None): | |||
| # Test the encoding, raising an exception if it's not known | |||
| if encoding != None: | |||
| ''.encode(encoding) | |||
| if ssl_context != None and not config.SSLserver: | |||
| raise AttributeError, \ | |||
| "SSL server not supported by this Python installation" | |||
| self.namespace = namespace | |||
| self.objmap = {} | |||
| self.funcmap = {} | |||
| @@ -699,8 +704,12 @@ if hasattr(socket, "AF_UNIX"): | |||
| self.encoding = encoding | |||
| self.config = config | |||
| self.log = log | |||
| self.allow_reuse_address= 1 | |||
| SocketServer.UnixStreamServer.__init__(self, str(addr), RequestHandler) | |||
| @@ -0,0 +1,11 @@ | |||
| #!/usr/bin/env python | |||
| # -*- coding: utf-8 -*- | |||
| __docformat__ = 'restructuredtext en' | |||
| #!/usr/bin/env python | |||
| # coding:utf-8 | |||
| from SOAPpy import SOAPProxy | |||
| server = SOAPProxy("http://localhost:8080/") | |||
| print server.echo("Hello world") | |||
| # vim:set et sts=4 ts=4 tw=80: | |||
| @@ -0,0 +1,13 @@ | |||
| #!/usr/bin/env python | |||
| # -*- coding: utf-8 -*- | |||
| __docformat__ = 'restructuredtext en' | |||
| #!/usr/bin/env python | |||
| # encoding:utf-8 | |||
| from SOAPpy import SOAPServer | |||
| def echo(s): | |||
| return s # repeats a string twice | |||
| server = SOAPServer(("0.0.0.0", 8080)) | |||
| server.registerFunction(echo) | |||
| server.serve_forever() | |||
| # vim:set et sts=4 ts=4 tw=80: | |||
| @@ -0,0 +1,21 @@ | |||
| POST / HTTP/1.0 | |||
| Host: localhost:8080 | |||
| User-agent: SOAPpy 0.12.0 (pywebsvcs.sf.net) | |||
| Content-type: text/xml; charset="UTF-8" | |||
| Content-length: 10000000 | |||
| SOAPAction: "echo" | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE v1 [ <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]> | |||
| <SOAP-ENV:Envelope | |||
| SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" | |||
| xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" | |||
| xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" | |||
| xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" | |||
| xmlns:xsd="http://www.w3.org/1999/XMLSchema" > | |||
| <SOAP-ENV:Body> | |||
| <echo SOAP-ENC:root="1"> | |||
| <v1 xsi:type="xsd:string">&xxe; aaa</v1> | |||
| </echo> | |||
| </SOAP-ENV:Body> | |||
| </SOAP-ENV:Envelope> | |||
| @@ -0,0 +1,32 @@ | |||
| POST / HTTP/1.0 | |||
| Host: localhost:8080 | |||
| User-agent: SOAPpy 0.12.0 (pywebsvcs.sf.net) | |||
| Content-type: text/xml; charset="UTF-8" | |||
| Content-length: 10000000 | |||
| SOAPAction: "echo" | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE v1 [ | |||
| <!ENTITY lol "lol"> | |||
| <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> | |||
| <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> | |||
| <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> | |||
| <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> | |||
| <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> | |||
| <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> | |||
| <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> | |||
| <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> | |||
| ]> | |||
| <SOAP-ENV:Envelope | |||
| SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" | |||
| xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" | |||
| xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" | |||
| xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" | |||
| xmlns:xsd="http://www.w3.org/1999/XMLSchema" | |||
| > | |||
| <SOAP-ENV:Body> | |||
| <echo SOAP-ENC:root="1"> | |||
| <v1 xsi:type="xsd:string">&lol9;</v1> | |||
| </echo> | |||
| </SOAP-ENV:Body> | |||
| </SOAP-ENV:Envelope> | |||
| @@ -0,0 +1,21 @@ | |||
| POST / HTTP/1.0 | |||
| Host: localhost:8080 | |||
| User-agent: SOAPpy 0.12.0 (pywebsvcs.sf.net) | |||
| Content-type: text/xml; charset="UTF-8" | |||
| Content-length: 484 | |||
| SOAPAction: "echo" | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <SOAP-ENV:Envelope | |||
| SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" | |||
| xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" | |||
| xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" | |||
| xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" | |||
| xmlns:xsd="http://www.w3.org/1999/XMLSchema" | |||
| > | |||
| <SOAP-ENV:Body> | |||
| <echo SOAP-ENC:root="1"> | |||
| <v1 xsi:type="xsd:string">Hello world</v1> | |||
| </echo> | |||
| </SOAP-ENV:Body> | |||
| </SOAP-ENV:Envelope> | |||