Changeset 5521


Ignore:
Timestamp:
27/07/09 12:08:00 (10 years ago)
Author:
pjkersha
Message:

Added urllib2 based SOAP client handler class.

Location:
TI12-security/trunk/python
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap/__init__.py

    r5520 r5521  
    11"""SOAP common package for NDG Security.  See ndg.security.server.wsgi for 
    2 server side specific code 
     2server side specific code. 
     3 
     4Initially for use with SAML SOAP Binding to Attribute Authority.  This itself 
     5uses ElementTree.  This SOAP interface provides an ElementTree interface to 
     6support it 
    37 
    48NERC DataGrid Project 
    59""" 
    610__author__ = "P J Kershaw" 
    7 __date__ = "27/07/09" 
    8 __copyright__ = "" 
     11__date__ = "24/07/09" 
     12__copyright__ = "(C) 2009 Science and Technology Facilities Council" 
    913__license__ = "BSD - see LICENSE file in top-level directory" 
    1014__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    11 __revision__ = '$Id:$' 
     15__revision__ = '$Id$' 
     16import logging 
     17log = logging.getLogger(__name__) 
     18 
     19class SOAPException(Exception): 
     20    """Base SAOP Exception class""" 
     21     
     22class SOAPFault(SOAPException): 
     23    """SOAP Fault""" 
     24     
     25class SOAPObject(object): 
     26    """Base class for SOAP envelope, header and body elements""" 
     27     
     28    ELEMENT_PREFIX = "SOAP-ENV" 
     29    SOAP11_NS = "http://schemas.xmlsoap.org/soap/envelope/" 
     30    SOAP12_NS = "http://www.w3.org/2003/05/soap-envelope" 
     31    DEFAULT_NS = SOAP11_NS 
     32     
     33    def create(self): 
     34        raise NotImplementedError() 
     35     
     36    def parse(self): 
     37        raise NotImplementedError() 
     38     
     39    def serialize(self): 
     40        raise NotImplementedError() 
     41     
     42    def prettyPrint(self): 
     43        raise NotImplementedError() 
     44   
     45     
     46class SOAPEnvelopeBase(SOAPObject): 
     47    """SOAP Envelope""" 
     48     
     49    DEFAULT_ELEMENT_LOCAL_NAME = "Envelope" 
     50    DEFAULT_ELEMENT_NS = SOAPObject.DEFAULT_NS 
     51    DEFAULT_ELEMENT_NS_PREFIX = SOAPObject.ELEMENT_PREFIX 
     52     
     53    soapHeader = property() 
     54    soapBody = property() 
     55     
     56     
     57class SOAPHeaderBase(SOAPObject): 
     58    """SOAP Header base class""" 
     59     
     60    DEFAULT_ELEMENT_LOCAL_NAME = "Header" 
     61    DEFAULT_ELEMENT_NS = SOAPObject.DEFAULT_NS 
     62    DEFAULT_ELEMENT_NS_PREFIX = SOAPObject.ELEMENT_PREFIX     
     63         
     64class SOAPBodyBase(SOAPObject): 
     65    """SOAP Body base class""" 
     66     
     67    DEFAULT_ELEMENT_LOCAL_NAME = "Body" 
     68    DEFAULT_ELEMENT_NS = SOAPObject.DEFAULT_NS 
     69    DEFAULT_ELEMENT_NS_PREFIX = SOAPObject.ELEMENT_PREFIX 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap/client.py

    r5520 r5521  
    1010__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1111__revision__ = '$Id:$' 
     12 
     13from ndg.security.common.soap import SOAPEnvelopeBase 
     14 
     15class SOAPClientBase(object): 
     16    """Handle client request to a SOAP Service""" 
     17    def __init__(self): 
     18        self.__soapClass = None 
     19 
     20    def _getSoapClass(self): 
     21        return self.__soapClass 
     22 
     23    def _setSoapClass(self, value): 
     24        if not isinstance(value, SOAPEnvelopeBase): 
     25            raise TypeError("Setting SOAP class: expecting %r, got %r" % 
     26                            (SOAPEnvelopeBase, value.__class__)) 
     27        self.__soapClass = value 
     28 
     29    soapClass = property(fget=_getSoapClass,  
     30                         fset=_setSoapClass,  
     31                         doc="Set the SOAP class for handling requests and " 
     32                             " responses") 
     33      
     34    def makeRequest(self, url, soapRequest): 
     35        raise NotImplementedError() 
     36 
     37 
     38import urllib2 
     39from cStringIO import StringIO 
     40 
     41class UrlLib2SOAPClient(SOAPClientBase): 
     42    """urllib2 based SOAP Client""" 
     43     
     44    def __init__(self, soapClass=None): 
     45        self.__openerDirector = urllib2.OpenerDirector() 
     46        self.__timeout = None 
     47         
     48        if soapClass is not None: 
     49            self.soapClass = soapClass 
     50 
     51    def _getTimeout(self): 
     52        return self.__timeout 
     53 
     54    def _setTimeout(self, value): 
     55        if not isinstance(value, (int, float)): 
     56            raise TypeError("Setting request timeout: got %r, expecting int " 
     57                            "float type" % type(value)) 
     58        self.__timeout = value 
     59 
     60    timeout = property(fget=_getTimeout,  
     61                       fset=_setTimeout,  
     62                       doc="Timeout (seconds) for requests") 
     63 
     64    def _getOpenerDirector(self): 
     65        return self.__openerDirector 
     66 
     67    def _setOpenerDirector(self, value): 
     68        """This shouldn't need to be used much in practice because __init__ 
     69        creates one""" 
     70        if not isinstance(value, urllib2.OpenerDirector): 
     71            raise TypeError("Setting opener: expecting %r; got %r" %  
     72                            (urllib2.OpenerDirector, value.__class__)) 
     73        self.__openerDirector = value 
     74 
     75    openerDirector = property(fget=_getOpenerDirector,  
     76                              fset=_setOpenerDirector,  
     77                              doc="urllib2.OpenerDirector defines the " 
     78                                  "opener(s) for handling requests") 
     79     
     80    def makeRequest(self, url, soapRequest): 
     81        """Make a request to the given URL with a SOAP Request object""" 
     82         
     83        if not isinstance(soapRequest, self.soapClass): 
     84            raise TypeError('Request to "%s", expecting %r derived type for ' 
     85                            'SOAP request, got %r' % (url, self.soapClass, 
     86                                                      soapRequest.__class__)) 
     87                             
     88        if self.timeout is not None: 
     89            arg = (self.timeout,) 
     90        else: 
     91            arg = () 
     92             
     93        result = self.__openerDirector.open(url, soapRequest, *arg) 
     94         
     95        resultStream = StringIO() 
     96        resultStream.write(result) 
     97        resultStream.seek(0) 
     98         
     99        soapResponse = self.soapClass()         
     100        soapResponse.parse(resultStream) 
     101         
     102        return soapResponse 
     103 
     104         
     105     
     106     
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap/etree.py

    r5520 r5521  
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = '$Id:$' 
     11import logging 
     12log = logging.getLogger(__name__) 
     13     
     14try: # python 2.5 
     15    from xml.etree import cElementTree as ElementTree 
     16except ImportError: 
     17    # if you've installed it yourself it comes this way 
     18    import cElementTree as ElementTree 
     19 
     20# ElementTree helper functions 
     21from ndg.security.common.utils import QName, canonicalize, getLocalName 
     22 
     23from ndg.security.common.soap import SOAPObject, SOAPEnvelopeBase, \ 
     24    SOAPHeaderBase, SOAPBodyBase 
     25 
     26class ETreeSOAPExtensions(object):   
     27    """Utility to enable addition of core ElementTree specific attributes and 
     28    methods for ElementTree SOAP implementation 
     29    """ 
     30    def __init__(self): 
     31        self.__qname = None 
     32        self.__elem = None 
     33 
     34    def _getQname(self): 
     35        return self.__qname 
     36 
     37    def _setQname(self, value): 
     38        if not isinstance(value, QName): 
     39            raise TypeError('Expecting %r for "qname" attribute; got %r' % 
     40                            (QName, type(value))) 
     41        self.__qname = value 
     42 
     43    def _getElem(self): 
     44        return self.__elem 
     45 
     46    def _setElem(self, value): 
     47        if not ElementTree.iselement(value): 
     48            raise TypeError('Expecting %r for "elem" attribute; got %r' % 
     49                            (ElementTree.Element, type(value))) 
     50        self.__elem = value 
     51         
     52    qname = property(_getQname, _setQname, None, "Qualified name object") 
     53    elem = property(_getElem, _setElem, None, "Root element") 
     54     
     55    @staticmethod 
     56    def _serialize(elem): 
     57        """Serialise element tree into string""" 
     58         
     59        # Make a basic check for the SOAP name space declaration, if the 
     60        # element is constructed from a call to ElementTree.parse it may not 
     61        # be present  
     62        namespaceDeclarationFound = False 
     63        soapElemNsDeclaration = ( 
     64            'xmlns:%s' % SOAPObject.ELEMENT_PREFIX,  
     65            SOAPObject.DEFAULT_NS 
     66        ) 
     67        if soapElemNsDeclaration[0] not in elem.attrib: 
     68            log.warning("No SOAP namespace declaration found - adding one in") 
     69            elem.set(*soapElemNsDeclaration) 
     70         
     71        return canonicalize(elem) 
     72     
     73    @classmethod 
     74    def _prettyPrint(cls, elem): 
     75        """Basic pretty printing separating each element on to a new line""" 
     76        xml = cls._serialize(elem) 
     77        xml = ">\n".join(xml.split(">")) 
     78        xml = "\n<".join(xml.split("<")) 
     79        xml = '\n'.join(xml.split('\n\n')) 
     80        return xml 
     81 
     82    def _parse(self, source): 
     83        """Read in the XML from source 
     84        @type source: basestring/file 
     85        @param source: file path to XML file or file object 
     86        """ 
     87        tree = ElementTree.parse(source) 
     88        elem = tree.getroot() 
     89         
     90        return elem         
     91 
     92 
     93class SOAPHeader(SOAPHeaderBase, ETreeSOAPExtensions): 
     94    """ElementTree implementation of SOAP Header object""" 
     95     
     96    DEFAULT_ELEMENT_NAME = QName(SOAPHeaderBase.DEFAULT_ELEMENT_NS, 
     97                               tag=SOAPHeaderBase.DEFAULT_ELEMENT_LOCAL_NAME, 
     98                               prefix=SOAPHeaderBase.DEFAULT_ELEMENT_NS_PREFIX) 
     99     
     100    def __init__(self): 
     101        SOAPHeaderBase.__init__(self) 
     102        ETreeSOAPExtensions.__init__(self) 
     103         
     104        self.qname = QName(SOAPHeaderBase.DEFAULT_ELEMENT_NS,  
     105                           tag=SOAPHeaderBase.DEFAULT_ELEMENT_LOCAL_NAME,  
     106                           prefix=SOAPHeaderBase.DEFAULT_ELEMENT_NS_PREFIX) 
     107 
     108    def create(self, makeNsDeclaration=True): 
     109        """Create header ElementTree element""" 
     110         
     111        self.elem = ElementTree.Element(str(self.qname)) 
     112        if makeNsDeclaration: 
     113            self.elem.set( 
     114                    "xmlns:%s" % SOAPHeaderBase.DEFAULT_ELEMENT_NS_PREFIX, 
     115                    SOAPHeaderBase.DEFAULT_ELEMENT_NS) 
     116     
     117    def serialize(self): 
     118        """Serialise element tree into string""" 
     119        return ETreeSOAPExtensions._serialize(self.elem) 
     120     
     121    def prettyPrint(self): 
     122        """Basic pretty printing separating each element on to a new line""" 
     123        return ETreeSOAPExtensions._prettyPrint(self.elem) 
     124 
     125 
     126class SOAPBody(SOAPBodyBase, ETreeSOAPExtensions): 
     127    """ElementTree based implementation for SOAP Body object""" 
     128     
     129    DEFAULT_ELEMENT_NAME = QName(SOAPBodyBase.DEFAULT_ELEMENT_NS, 
     130                                 tag=SOAPBodyBase.DEFAULT_ELEMENT_LOCAL_NAME, 
     131                                 prefix=SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX) 
     132     
     133    def __init__(self): 
     134        SOAPBodyBase.__init__(self) 
     135        ETreeSOAPExtensions.__init__(self) 
     136         
     137        self.qname = QName(SOAPBodyBase.DEFAULT_ELEMENT_NS,  
     138                           tag=SOAPBodyBase.DEFAULT_ELEMENT_LOCAL_NAME,  
     139                           prefix=SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX) 
     140         
     141    def create(self, makeNsDeclaration=True): 
     142        """Create header ElementTree element""" 
     143         
     144        self.elem = ElementTree.Element(str(self.qname)) 
     145        if makeNsDeclaration: 
     146            self.elem.set("xmlns:%s" % SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX, 
     147                          SOAPBodyBase.DEFAULT_ELEMENT_NS) 
     148     
     149    def serialize(self): 
     150        """Serialise element tree into string""" 
     151        return ETreeSOAPExtensions._serialize(self.elem) 
     152     
     153    def prettyPrint(self): 
     154        """Basic pretty printing separating each element on to a new line""" 
     155        return ETreeSOAPExtensions._prettyPrint(self.elem) 
     156     
     157 
     158class SOAPEnvelope(SOAPEnvelopeBase, ETreeSOAPExtensions): 
     159    """ElementTree based SOAP implementation""" 
     160    DEFAULT_ELEMENT_NAME = QName(SOAPEnvelopeBase.DEFAULT_ELEMENT_NS, 
     161                             tag=SOAPEnvelopeBase.DEFAULT_ELEMENT_LOCAL_NAME, 
     162                             prefix=SOAPEnvelopeBase.DEFAULT_ELEMENT_NS_PREFIX) 
     163 
     164    def __init__(self): 
     165        SOAPEnvelopeBase.__init__(self) 
     166        ETreeSOAPExtensions.__init__(self) 
     167         
     168        self.qname = QName(SOAPEnvelopeBase.DEFAULT_ELEMENT_NS,  
     169                             tag=SOAPEnvelopeBase.DEFAULT_ELEMENT_LOCAL_NAME,  
     170                             prefix=SOAPEnvelopeBase.DEFAULT_ELEMENT_NS_PREFIX) 
     171        self.__header = SOAPHeader() 
     172        self.__body = SOAPBody() 
     173 
     174    def _getHeader(self): 
     175        return self.__header 
     176 
     177    def _setHeader(self, value): 
     178        if not isinstance(value, SOAPHeader): 
     179            raise TypeError('Expecting %r for "header" attribute; got %r' % 
     180                            (SOAPHeader, type(value))) 
     181        self.__header = value 
     182 
     183    def _getBody(self): 
     184        return self.__body 
     185 
     186    def _setBody(self, value): 
     187        if not isinstance(value, SOAPBody): 
     188            raise TypeError('Expecting %r for "header" attribute; got %r' % 
     189                            (SOAPBody, type(value))) 
     190        self.__body = value 
     191 
     192    header = property(_getHeader, _setHeader, None, "SOAP header object") 
     193    body = property(_getBody, _setBody, None, "SOAP body object") 
     194 
     195    def create(self, makeNsDeclaration=True): 
     196        """Create SOAP Envelope with header and body""" 
     197         
     198        self.elem = ElementTree.Element(str(self.qname)) 
     199        if makeNsDeclaration: 
     200            self.elem.set("xmlns:%s" % SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX, 
     201                          SOAPBodyBase.DEFAULT_ELEMENT_NS) 
     202             
     203        self.header.create(makeNsDeclaration=False) 
     204        self.elem.append(self.header.elem) 
     205         
     206        self.body.create(makeNsDeclaration=False) 
     207        self.elem.append(self.body.elem) 
     208     
     209    def serialize(self): 
     210        """Serialise element tree into string""" 
     211        return ETreeSOAPExtensions._serialize(self.elem) 
     212     
     213    def prettyPrint(self): 
     214        """Basic pretty printing separating each element onto a new line""" 
     215        return ETreeSOAPExtensions._prettyPrint(self.elem) 
     216     
     217    def parse(self, source): 
     218        self.elem = ETreeSOAPExtensions._parse(self, source)  
     219         
     220        for elem in self.elem: 
     221            localName = getLocalName(elem) 
     222            if localName == SOAPHeader.DEFAULT_ELEMENT_LOCAL_NAME: 
     223                self.header.elem = elem 
     224                 
     225            elif localName == SOAPBody.DEFAULT_ELEMENT_LOCAL_NAME: 
     226                self.body.elem = elem 
     227                 
     228            else: 
     229                raise SOAPFault('Invalid child element in SOAP Envelope "%s" ' 
     230                                'for source %r' % (localName, source)) 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/soap/test_soap.py

    r5519 r5521  
    1717import paste.fixture 
    1818 
    19 from ndg.security.common.soap import SOAPEnvelope 
     19from ndg.security.common.soap.etree import SOAPEnvelope 
    2020 
    2121class SOAPBindingMiddleware(object): 
Note: See TracChangeset for help on using the changeset viewer.