source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap.py @ 5516

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/soap.py@5516
Revision 5516, 9.2 KB checked in by pjkersha, 11 years ago (diff)

Started work on SAML Attribute Interface SOAP Binding

  • added new ndg.security.common.soap module for ElementTree based SOAP handling. This will allow easy integration with ElementTree based SAML implementation.
Line 
1"""SOAP implementation
2
3Initially for use with SAML SOAP Binding to Attribute Authority.  This itself
4uses ElementTree.  This SOAP interface provides an ElementTree interface to
5support it
6
7NERC DataGrid Project"""
8__author__ = "P J Kershaw"
9__date__ = "24/07/09"
10__copyright__ = "(C) 2009 Science and Technology Facilities Council"
11__license__ = "BSD - see LICENSE file in top-level directory"
12__contact__ = "Philip.Kershaw@stfc.ac.uk"
13__revision__ = '$Id$'
14import logging
15log = logging.getLogger(__name__)
16
17from ndg.security.common.utils import QName
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    DEFAULT_ELEMENT_NAME = QName(DEFAULT_ELEMENT_NS,
53                                 tag=DEFAULT_ELEMENT_LOCAL_NAME,
54                                 prefix=DEFAULT_ELEMENT_NS_PREFIX)
55   
56    soapHeader = property()
57    soapBody = property()
58   
59   
60class SOAPHeaderBase(SOAPObject):
61    """SOAP Header base class"""
62   
63    DEFAULT_ELEMENT_LOCAL_NAME = "Header"
64    DEFAULT_ELEMENT_NS = SOAPObject.DEFAULT_NS
65    DEFAULT_ELEMENT_NS_PREFIX = SOAPObject.ELEMENT_PREFIX
66    DEFAULT_ELEMENT_NAME = QName(DEFAULT_ELEMENT_NS,
67                                 tag=DEFAULT_ELEMENT_LOCAL_NAME,
68                                 prefix=DEFAULT_ELEMENT_NS_PREFIX)
69   
70       
71class SOAPBodyBase(SOAPObject):
72    """SOAP Body base class"""
73   
74    DEFAULT_ELEMENT_LOCAL_NAME = "Body"
75    DEFAULT_ELEMENT_NS = SOAPObject.DEFAULT_NS
76    DEFAULT_ELEMENT_NS_PREFIX = SOAPObject.ELEMENT_PREFIX
77    DEFAULT_ELEMENT_NAME = QName(DEFAULT_ELEMENT_NS,
78                                 tag=DEFAULT_ELEMENT_LOCAL_NAME,
79                                 prefix=DEFAULT_ELEMENT_NS_PREFIX)
80   
81   
82# ElementTree Specific implementations start here
83# TODO: refactor into a separate module
84try: # python 2.5
85    from xml.etree import cElementTree as ElementTree
86except ImportError:
87    # if you've installed it yourself it comes this way
88    import cElementTree as ElementTree
89
90from ndg.security.common.utils import canonicalize, getLocalName
91
92
93class ETreeSOAPExtensions(object): 
94    """Utility to enable addition of core ElementTree specific attributes and
95    methods for ElementTree SOAP implementation
96    """
97    def __init__(self):
98        self.__qname = None
99        self.__elem = None
100
101    def _getQname(self):
102        return self.__qname
103
104    def _setQname(self, value):
105        if not isinstance(value, QName):
106            raise TypeError('Expecting %r for "qname" attribute; got %r' %
107                            (QName, type(value)))
108        self.__qname = value
109
110    def _getElem(self):
111        return self.__elem
112
113    def _setElem(self, value):
114        if not ElementTree.iselement(value):
115            raise TypeError('Expecting %r for "elem" attribute; got %r' %
116                            (ElementTree.Element, type(value)))
117        self.__elem = value
118       
119    qname = property(_getQname, _setQname, None, "Qualified name object")
120    elem = property(_getElem, _setElem, None, "Root element")
121   
122    @staticmethod
123    def _serialize(elem):
124        """Serialise element tree into string"""
125        return canonicalize(elem)
126   
127    @classmethod
128    def _prettyPrint(cls, elem):
129        """Basic pretty printing separating each element on to a new line"""
130        xml = cls._serialize(elem)
131        xml = ">\n".join(xml.split(">"))
132        xml = "\n<".join(xml.split("<"))
133        xml = '\n'.join(xml.split('\n\n'))
134        return xml
135
136    def _parse(self, source):
137        """Read in the XML from source
138        @type source: basestring/file
139        @param source: file path to XML file or file object
140        """
141        tree = ElementTree.parse(source)
142        elem = tree.getroot()
143       
144        return elem       
145
146
147class SOAPHeader(SOAPHeaderBase, ETreeSOAPExtensions):
148    """ElementTree implementation of SOAP Header object"""
149   
150    def __init__(self):
151        SOAPHeaderBase.__init__(self)
152        ETreeSOAPExtensions.__init__(self)
153       
154        self.qname = QName(SOAPHeaderBase.DEFAULT_ELEMENT_NS, 
155                           tag=SOAPHeaderBase.DEFAULT_ELEMENT_LOCAL_NAME, 
156                           prefix=SOAPHeaderBase.DEFAULT_ELEMENT_NS_PREFIX)
157
158    def create(self, makeNsDeclaration=True):
159        """Create header ElementTree element"""
160       
161        self.elem = ElementTree.Element(str(self.qname))
162        if makeNsDeclaration:
163            self.elem.set(
164                    "xmlns:%s" % SOAPHeaderBase.DEFAULT_ELEMENT_NS_PREFIX,
165                    SOAPHeaderBase.DEFAULT_ELEMENT_NS)
166   
167    def serialize(self):
168        """Serialise element tree into string"""
169        return ETreeSOAPExtensions._serialize(self.elem)
170   
171    def prettyPrint(self):
172        """Basic pretty printing separating each element on to a new line"""
173        return ETreeSOAPExtensions._prettyPrint(self.elem)
174
175
176class SOAPBody(SOAPBodyBase, ETreeSOAPExtensions):
177    """ElementTree based implementation for SOAP Body object"""
178   
179    def __init__(self):
180        SOAPBodyBase.__init__(self)
181        ETreeSOAPExtensions.__init__(self)
182       
183        self.qname = QName(SOAPBodyBase.DEFAULT_ELEMENT_NS, 
184                           tag=SOAPBodyBase.DEFAULT_ELEMENT_LOCAL_NAME, 
185                           prefix=SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX)
186       
187    def create(self, makeNsDeclaration=True):
188        """Create header ElementTree element"""
189       
190        self.elem = ElementTree.Element(str(self.qname))
191        if makeNsDeclaration:
192            self.elem.set("xmlns:%s" % SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX,
193                          SOAPBodyBase.DEFAULT_ELEMENT_NS)
194   
195    def serialize(self):
196        """Serialise element tree into string"""
197        return ETreeSOAPExtensions._serialize(self.elem)
198   
199    def prettyPrint(self):
200        """Basic pretty printing separating each element on to a new line"""
201        return ETreeSOAPExtensions._prettyPrint(self.elem)
202   
203
204class SOAPEnvelope(SOAPEnvelopeBase, ETreeSOAPExtensions):
205    """ElementTree based SOAP implementation"""
206
207    def __init__(self):
208        SOAPEnvelopeBase.__init__(self)
209        ETreeSOAPExtensions.__init__(self)
210       
211        self.qname = QName(SOAPEnvelopeBase.DEFAULT_ELEMENT_NS, 
212                             tag=SOAPEnvelopeBase.DEFAULT_ELEMENT_LOCAL_NAME, 
213                             prefix=SOAPEnvelopeBase.DEFAULT_ELEMENT_NS_PREFIX)
214        self.__header = SOAPHeader()
215        self.__body = SOAPBody()
216
217    def _getHeader(self):
218        return self.__header
219
220    def _setHeader(self, value):
221        if not isinstance(value, SOAPHeader):
222            raise TypeError('Expecting %r for "header" attribute; got %r' %
223                            (SOAPHeader, type(value)))
224        self.__header = value
225
226    def _getBody(self):
227        return self.__body
228
229    def _setBody(self, value):
230        if not isinstance(value, SOAPBody):
231            raise TypeError('Expecting %r for "header" attribute; got %r' %
232                            (SOAPBody, type(value)))
233        self.__body = value
234
235    header = property(_getHeader, _setHeader, None, "SOAP header object")
236    body = property(_getBody, _setBody, None, "SOAP body object")
237
238    def create(self, makeNsDeclaration=True):
239        """Create SOAP Envelope with header and body"""
240       
241        self.elem = ElementTree.Element(str(self.qname))
242        if makeNsDeclaration:
243            self.elem.set("xmlns:%s" % SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX,
244                          SOAPBodyBase.DEFAULT_ELEMENT_NS)
245           
246        self.header.create(makeNsDeclaration=False)
247        self.elem.append(self.header.elem)
248       
249        self.body.create(makeNsDeclaration=False)
250        self.elem.append(self.body.elem)
251   
252    def serialize(self):
253        """Serialise element tree into string"""
254        return ETreeSOAPExtensions._serialize(self.elem)
255   
256    def prettyPrint(self):
257        """Basic pretty printing separating each element on to a new line"""
258        return ETreeSOAPExtensions._prettyPrint(self.elem)
259   
260    def parse(self, source):
261        self.elem = ETreeSOAPExtensions._parse(self, source) 
262       
263        for elem in self.elem:
264            localName = getLocalName(elem)
265            if localName == SOAPHeader.DEFAULT_ELEMENT_LOCAL_NAME:
266                self.header.elem = elem
267               
268            elif localName == SOAPBody.DEFAULT_ELEMENT_LOCAL_NAME:
269                self.body.elem = elem
270               
271            else:
272                raise SOAPFault('Invalid child element in SOAP Envelope "%s" '
273                                'for source %r' % (localName, source))
Note: See TracBrowser for help on using the repository browser.