source: TI12-security/trunk/ndg_saml/ndg/saml/saml2/binding/soap/client/attributequery.py @ 7322

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/ndg_saml/ndg/saml/saml2/binding/soap/client/attributequery.py@7322
Revision 7322, 6.5 KB checked in by pjkersha, 9 years ago (diff)

Incomplete - task 2: XACML-Security Integration

  • fixes to SOAP client bindings
  • Property svn:keywords set to Id
Line 
1"""SAML 2.0 client 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__ = "http://www.apache.org/licenses/LICENSE-2.0"
9__contact__ = "Philip.Kershaw@stfc.ac.uk"
10__revision__ = '$Id$'
11import re
12import logging
13log = logging.getLogger(__name__)
14
15from M2Crypto.m2urllib2 import HTTPSHandler
16
17from ndg.saml.saml2.core import Attribute, AttributeQuery
18
19from ndg.saml.utils import TypedList
20from ndg.saml.saml2.binding.soap.client.subjectquery import (
21                                                    SubjectQuerySOAPBinding,
22                                                    SubjectQueryResponseError)
23
24# Prevent whole module breaking if this is not available - it's only needed for
25# AttributeQuerySslSOAPBinding
26try:
27    from ndg.saml.utils.m2crypto import SSLContextProxy
28    _sslContextProxySupport = True
29   
30except ImportError:
31    _sslContextProxySupport = False
32
33
34class AttributeQueryResponseError(SubjectQueryResponseError):
35    """SAML Response error from Attribute Query"""
36   
37
38class AttributeQuerySOAPBinding(SubjectQuerySOAPBinding): 
39    """SAML Attribute Query SOAP Binding
40    """
41    QUERY_ATTRIBUTES_ATTRNAME = 'queryAttributes'
42    LEN_QUERY_ATTRIBUTES_ATTRNAME = len(QUERY_ATTRIBUTES_ATTRNAME)
43    QUERY_ATTRIBUTES_PAT = re.compile(',\s*')
44   
45    __PRIVATE_ATTR_PREFIX = "__"
46    __slots__ = ()
47
48    SERIALISE_KW = 'serialise'
49    DESERIALISE_KW = 'deserialise'
50    QUERY_TYPE = AttributeQuery
51   
52    def __init__(self, **kw):
53        '''Create SOAP Client for SAML Attribute Query'''
54       
55        # Default to ElementTree based serialisation/deserialisation
56        if AttributeQuerySOAPBinding.SERIALISE_KW not in kw:
57            from ndg.saml.xml.etree import AttributeQueryElementTree
58            kw[AttributeQuerySOAPBinding.SERIALISE_KW
59               ] = AttributeQueryElementTree.toXML
60               
61        if AttributeQuerySOAPBinding.DESERIALISE_KW not in kw:
62            from ndg.saml.xml.etree import ResponseElementTree
63            kw[AttributeQuerySOAPBinding.DESERIALISE_KW
64               ] = ResponseElementTree.fromXML
65       
66        super(AttributeQuerySOAPBinding, self).__init__(**kw)
67           
68    def __setattr__(self, name, value):
69        """Enable setting of SAML query attribute objects via a comma separated
70        string suitable for use reading from an ini file. 
71        """
72        try:
73            super(AttributeQuerySOAPBinding, self).__setattr__(name, value)
74           
75        except AttributeError:
76            if name.startswith(
77                        AttributeQuerySOAPBinding.QUERY_ATTRIBUTES_ATTRNAME):
78                # Special handler for parsing string format settings
79                if not isinstance(value, basestring):
80                    raise TypeError('Expecting string format for special '
81                                    '%r attribute; got %r instead' %
82                                    (name, type(value)))
83                   
84                pat = AttributeQuerySOAPBinding.QUERY_ATTRIBUTES_PAT
85                attribute = Attribute()
86               
87                (attribute.name, 
88                 attribute.friendlyName, 
89                 attribute.nameFormat) = pat.split(value)
90                 
91                self.queryAttributes.append(attribute)
92            else:
93                raise
94             
95    def _getQueryAttributes(self):
96        return self.query.attributes
97
98    def _setQueryAttributes(self, value):
99        if not isinstance(value, TypedList) and value.elementType != Attribute:
100            raise TypeError('Expecting TypedList(Attribute) type for '
101                            '"queryAttributes"; got %r instead' % type(value))
102       
103        # Remove all previously set items and add new ones
104        del self.query.attributes[:]
105        for attribute in value:
106            self.query.attributes.append(attribute)
107 
108    queryAttributes = property(_getQueryAttributes, 
109                               _setQueryAttributes, 
110                               doc="List of attributes to query from the "
111                                   "Attribute Authority")
112
113   
114class AttributeQuerySslSOAPBinding(AttributeQuerySOAPBinding):
115    """Specialisation of AttributeQuerySOAPbinding taking in the setting of
116    SSL parameters for mutual authentication
117    """
118    SSL_CONTEXT_PROXY_SUPPORT = _sslContextProxySupport
119    __slots__ = ('__sslCtxProxy',)
120   
121    def __init__(self, **kw):
122        if not AttributeQuerySslSOAPBinding.SSL_CONTEXT_PROXY_SUPPORT:
123            raise ImportError("ndg.saml.utils.m2crypto import "
124                              "failed - missing M2Crypto package?")
125       
126        # Miss out default HTTPSHandler and set in send() instead
127        if 'handlers' in kw:
128            raise TypeError("__init__() got an unexpected keyword argument "
129                            "'handlers'")
130           
131        super(AttributeQuerySslSOAPBinding, self).__init__(handlers=(), **kw)
132        self.__sslCtxProxy = SSLContextProxy()
133
134    def send(self, **kw):
135        """Override base class implementation to pass explicit SSL Context
136        """
137        httpsHandler = HTTPSHandler(ssl_context=self.sslCtxProxy.createCtx())
138        self.client.openerDirector.add_handler(httpsHandler)
139        return super(AttributeQuerySslSOAPBinding, self).send(**kw)
140           
141    def _getSslCtxProxy(self):
142        return self.__sslCtxProxy
143   
144    def _setSslCtxProxy(self, value):
145        if not isinstance(value, SSLContextProxy):
146            raise TypeError('Expecting %r type for "sslCtxProxy attribute; got '
147                            '%r' % type(value))
148           
149        self.__sslCtxProxy = value
150           
151    sslCtxProxy = property(fget=_getSslCtxProxy, fset=_setSslCtxProxy,
152                           doc="SSL Context Proxy object used for setting up "
153                               "an SSL Context for queries")
154   
155    def __setattr__(self, name, value):
156        """Enable setting of SSLContextProxy attributes as if they were
157        attributes of this class.  This is intended as a convenience for
158        making settings parameters read from a config file
159        """
160        try:
161            super(AttributeQuerySslSOAPBinding, self).__setattr__(name, value)
162           
163        except AttributeError, e:
164            # Coerce into setting SSL Context Proxy attributes
165            try:
166                setattr(self.sslCtxProxy, name, value)
167            except:
168                raise e
Note: See TracBrowser for help on using the repository browser.