source: TI12-security/trunk/python/ndg_security_common/ndg/security/common/saml/bindings.py @ 5681

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg_security_common/ndg/security/common/saml/bindings.py@5681
Revision 5681, 5.6 KB checked in by pjkersha, 12 years ago (diff)

Integrated SOAP SAML Attribute Query interface into Attribute Authority Client unit tests.

Line 
1"""SAML 2.0 bindings module implements SOAP binding for attribute query
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "02/09/09"
7__copyright__ = "(C) 2009 Science and Technology Facilities Council"
8__license__ = "BSD - see LICENSE file in top-level directory"
9__contact__ = "Philip.Kershaw@stfc.ac.uk"
10__revision__ = '$Id$'
11from M2Crypto.m2urllib2 import HTTPSHandler
12
13from saml.saml2.core import Response, AttributeQuery
14from saml.xml.etree import AttributeQueryElementTree, ResponseElementTree
15
16from ndg.security.common.utils.etree import QName
17from ndg.security.common.soap import SOAPEnvelopeBase
18from ndg.security.common.soap.etree import SOAPEnvelope
19from ndg.security.common.soap.client import UrlLib2SOAPClient, \
20    UrlLib2SOAPRequest
21
22
23class SOAPBindingError(Exception):
24    '''Base exception type for client SAML SOAP Binding for Attribute Query'''
25
26
27class SOAPBindingInvalidResponse(SOAPBindingError):
28    '''Raise if the response is invalid'''
29   
30   
31_isIterable = lambda obj: getattr(obj, '__iter__', False) 
32   
33   
34class SOAPBinding(object):
35    '''Client SAML SOAP Binding for Attribute Query'''
36   
37    isIterable = staticmethod(_isIterable)
38   
39    def __init__(self, 
40                 requestEnvelopeClass=SOAPEnvelope,
41                 responseEnvelopeClass=SOAPEnvelope,
42                 handlers=(HTTPSHandler,)):
43        '''Create SOAP Client'''
44        self.__client = None
45         
46        self.client = UrlLib2SOAPClient()
47       
48        # ElementTree based envelope class
49        self.requestEnvelopeClass = requestEnvelopeClass
50        self.client.responseEnvelopeClass = responseEnvelopeClass
51
52        if not SOAPBinding.isIterable(handlers):
53            raise TypeError('Expecting iterable for "handlers" keyword; got %r'
54                            % type(handlers))
55           
56        for handler in handlers:
57            self.client.openerDirector.add_handler(handler())
58           
59        self.serialise = AttributeQueryElementTree.toXML
60        self.deserialise = ResponseElementTree.fromXML
61
62    def _getSerialise(self):
63        return self.__serialise
64
65    def _setSerialise(self, value):
66        if not callable(value):
67            raise TypeError('Expecting callable for "serialise"; got %r' % 
68                            value)
69        self.__serialise = value
70
71    serialise = property(_getSerialise, _setSerialise, 
72                         doc="callable to serialise request into XML type")
73
74    def _getDeserialise(self):
75        return self.__deserialise
76
77    def _setDeserialise(self, value):
78        if not callable(value):
79            raise TypeError('Expecting callable for "deserialise"; got %r' % 
80                            value)
81        self.__deserialise = value
82
83    deserialise = property(_getDeserialise, 
84                           _setDeserialise, 
85                           doc="callable to de-serialise response from XML "
86                               "type")
87
88    def _getRequestEnvelopeClass(self):
89        return self.__requestEnvelopeClass
90
91    def _setRequestEnvelopeClass(self, value):
92        if not issubclass(value, SOAPEnvelopeBase):
93            raise TypeError('Expecting %r for "requestEnvelopeClass"; got %r'% 
94                            (SOAPEnvelopeBase, value))
95       
96        self.__requestEnvelopeClass = value
97
98    requestEnvelopeClass = property(_getRequestEnvelopeClass, 
99                                    _setRequestEnvelopeClass, 
100                                    doc="SOAP Envelope Request Class")
101
102    def _getClient(self):
103        return self.__client
104
105    def _setClient(self, value):     
106        if not isinstance(value, UrlLib2SOAPClient):
107            raise TypeError('Expecting %r for "client"; got %r'% 
108                            (UrlLib2SOAPClient, type(value)))
109        self.__client = value
110
111    client = property(_getClient, _setClient, 
112                      doc="SOAP Client object")   
113         
114    def attributeQuery(self, attributeQuery, uri=None, request=None):
115        '''Make an attribute query to a remote SAML service
116       
117        @type attributeQuery: saml.saml2.core.AttributeQuery
118        @param attributeQuery: attribute query
119        @type uri: basestring
120        @param uri: uri of service.  May be omitted if set from request.url
121        @type request: ndg.security.common.soap.UrlLib2SOAPRequest
122        @param request: SOAP request object to which query will be attached
123        defaults to ndg.security.common.soap.client.UrlLib2SOAPRequest
124        '''
125        if not isinstance(attributeQuery, AttributeQuery):
126            raise TypeError('Expecting %r for input attribute query; got %r'
127                            % (AttributeQuery, type(attributeQuery)))
128           
129        if request is None:
130            request = UrlLib2SOAPRequest()           
131            request.envelope = self.requestEnvelopeClass()
132            request.envelope.create()
133           
134        if uri is not None:
135            request.url = uri
136       
137        attributeQueryElem = self.serialise(attributeQuery)
138
139        # Attach query to SOAP body
140        request.envelope.body.elem.append(attributeQueryElem)
141        response = self.client.send(request)
142       
143        if len(response.envelope.body.elem) != 1:
144            raise SOAPBindingInvalidResponse("Expecting single child element "
145                                             "is SOAP body")
146           
147        if QName.getLocalPart(response.envelope.body.elem[0].tag)!='Response':
148            raise SOAPBindingInvalidResponse('Expecting "Response" element in '
149                                             'SOAP body')
150           
151        response = self.deserialise(response.envelope.body.elem[0])
152       
153        return response
154
Note: See TracBrowser for help on using the repository browser.