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

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@6570
Revision 6570, 5.9 KB checked in by pjkersha, 11 years ago (diff)
  • Refactored classfactory module as a more generic factory for importing any module object
  • Started unit tests with refactored SAML SOAP bindings.
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   
49    def __init__(self, **kw):
50        '''Create SOAP Client for SAML Attribute Query'''
51        self.__queryAttributes = TypedList(Attribute)
52               
53        super(AttributeQuerySOAPBinding, self).__init__(**kw)
54           
55    def __setattr__(self, name, value):
56        """Enable setting of SAML query attribute objects via a comma separated
57        string suitable for use reading from an ini file. 
58        """
59        try:
60            super(AttributeQuerySOAPBinding, self).__setattr__(name, value)
61           
62        except AttributeError:
63            if name.startswith(
64                        AttributeQuerySOAPBinding.QUERY_ATTRIBUTES_ATTRNAME):
65                # Special handler for parsing string format settings
66                if not isinstance(value, basestring):
67                    raise TypeError('Expecting string format for special '
68                                    '%r attribute; got %r instead' %
69                                    (name, type(value)))
70                   
71                pat = AttributeQuerySOAPBinding.QUERY_ATTRIBUTES_PAT
72                attribute = Attribute()
73               
74                (attribute.name, 
75                 attribute.friendlyName, 
76                 attribute.nameFormat) = pat.split(value)
77                 
78                self.queryAttributes.append(attribute)
79            else:
80                raise
81             
82    def _getQueryAttributes(self):
83        return self.__queryAttributes
84
85    def _setQueryAttributes(self, value):
86        if not isinstance(value, TypedList) and value.elementType != Attribute:
87            raise TypeError('Expecting TypedList(Attribute) type for '
88                            '"queryAttributes"; got %r instead' % type(value)) 
89       
90        self.__queryAttributes = value
91   
92    queryAttributes = property(_getQueryAttributes, 
93                               _setQueryAttributes, 
94                               doc="List of attributes to query from the "
95                                   "Attribute Authority")
96
97    def _createQuery(self):
98        """ Create a SAML attribute query"""
99        attributeQuery = super(AttributeQuerySOAPBinding, self)._createQuery(
100                                                                AttributeQuery)
101        # Add list of attributes to query                     
102        for attribute in self.queryAttributes:
103            attributeQuery.attributes.append(attribute)
104           
105        return attributeQuery
106
107   
108class AttributeQuerySslSOAPBinding(AttributeQuerySOAPBinding):
109    """Specialisation of AttributeQuerySOAPbinding taking in the setting of
110    SSL parameters for mutual authentication
111    """
112    SSL_CONTEXT_PROXY_SUPPORT = _sslContextProxySupport
113    __slots__ = ('__sslCtxProxy',)
114   
115    def __init__(self, **kw):
116        if not AttributeQuerySslSOAPBinding.SSL_CONTEXT_PROXY_SUPPORT:
117            raise ImportError("ndg.security.common.utils.m2crypto import "
118                              "failed - missing M2Crypto package?")
119       
120        # Miss out default HTTPSHandler and set in send() instead
121        if 'handlers' in kw:
122            raise TypeError("__init__() got an unexpected keyword argument "
123                            "'handlers'")
124           
125        super(AttributeQuerySslSOAPBinding, self).__init__(handlers=(), **kw)
126        self.__sslCtxProxy = SSLContextProxy()
127
128    def send(self, **kw):
129        """Override base class implementation to pass explicit SSL Context
130        """
131        httpsHandler = HTTPSHandler(ssl_context=self.sslCtxProxy.createCtx())
132        self.client.openerDirector.add_handler(httpsHandler)
133        return super(AttributeQuerySslSOAPBinding, self).send(**kw)
134       
135    @property
136    def sslCtxProxy(self):
137        """SSL Context Proxy object used for setting up an SSL Context for
138        queries
139        """
140        return self.__sslCtxProxy
141           
142    def __setattr__(self, name, value):
143        """Enable setting of SSLContextProxy attributes as if they were
144        attributes of this class.  This is intended as a convenience for
145        making settings parameters read from a config file
146        """
147        try:
148            super(AttributeQuerySslSOAPBinding, self).__setattr__(name, value)
149           
150        except AttributeError:
151            # Coerce into setting SSL Context Proxy attributes
152            try:
153                setattr(self.sslCtxProxy, name, value)
154            except:
155                raise
Note: See TracBrowser for help on using the repository browser.