source: TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/attributequery.py @ 6572

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/attributequery.py@6572
Revision 6572, 6.5 KB checked in by pjkersha, 11 years ago (diff)

Working refactored 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: $'
11import re
12import logging
13log = logging.getLogger(__name__)
14
15from M2Crypto.m2urllib2 import HTTPSHandler
16
17from saml.saml2.core import Attribute, AttributeQuery
18
19from ndg.security.common.utils import TypedList
20from ndg.security.common.saml_utils.binding.soap.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.security.common.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__ = (__PRIVATE_ATTR_PREFIX + QUERY_ATTRIBUTES_ATTRNAME,)
47
48    SERIALISE_KW = 'serialise'
49    DESERIALISE_KW = 'deserialise'
50   
51    def __init__(self, **kw):
52        '''Create SOAP Client for SAML Attribute Query'''
53        self.__queryAttributes = TypedList(Attribute)
54       
55        # Default to ElementTree based serialisation/deserialisation
56        if AttributeQuerySOAPBinding.SERIALISE_KW not in kw:
57            from saml.xml.etree import AttributeQueryElementTree
58            kw[AttributeQuerySOAPBinding.SERIALISE_KW
59               ] = AttributeQueryElementTree.toXML
60               
61        if AttributeQuerySOAPBinding.DESERIALISE_KW not in kw:
62            from 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.__queryAttributes
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        self.__queryAttributes = value
104   
105    queryAttributes = property(_getQueryAttributes, 
106                               _setQueryAttributes, 
107                               doc="List of attributes to query from the "
108                                   "Attribute Authority")
109
110    def _createQuery(self):
111        """ Create a SAML attribute query"""
112        attributeQuery = super(AttributeQuerySOAPBinding, self)._createQuery(
113                                                                AttributeQuery)
114        # Add list of attributes to query                     
115        for attribute in self.queryAttributes:
116            attributeQuery.attributes.append(attribute)
117           
118        return attributeQuery
119
120   
121class AttributeQuerySslSOAPBinding(AttributeQuerySOAPBinding):
122    """Specialisation of AttributeQuerySOAPbinding taking in the setting of
123    SSL parameters for mutual authentication
124    """
125    SSL_CONTEXT_PROXY_SUPPORT = _sslContextProxySupport
126    __slots__ = ('__sslCtxProxy',)
127   
128    def __init__(self, **kw):
129        if not AttributeQuerySslSOAPBinding.SSL_CONTEXT_PROXY_SUPPORT:
130            raise ImportError("ndg.security.common.utils.m2crypto import "
131                              "failed - missing M2Crypto package?")
132       
133        # Miss out default HTTPSHandler and set in send() instead
134        if 'handlers' in kw:
135            raise TypeError("__init__() got an unexpected keyword argument "
136                            "'handlers'")
137           
138        super(AttributeQuerySslSOAPBinding, self).__init__(handlers=(), **kw)
139        self.__sslCtxProxy = SSLContextProxy()
140
141    def send(self, **kw):
142        """Override base class implementation to pass explicit SSL Context
143        """
144        httpsHandler = HTTPSHandler(ssl_context=self.sslCtxProxy.createCtx())
145        self.client.openerDirector.add_handler(httpsHandler)
146        return super(AttributeQuerySslSOAPBinding, self).send(**kw)
147       
148    @property
149    def sslCtxProxy(self):
150        """SSL Context Proxy object used for setting up an SSL Context for
151        queries
152        """
153        return self.__sslCtxProxy
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.