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

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@6567
Revision 6567, 5.9 KB checked in by pjkersha, 10 years ago (diff)

Refactoring SAML SOAP bindings module to include AuthzDecisionQuery?:

  • improved package structure
  • Generic SubjectQuerySOAPBinding type which AuthzDecision? and Attribute query types extend.
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 logging
12log = logging.getLogger(__name__)
13
14from M2Crypto.m2urllib2 import HTTPSHandler
15
16from saml.saml2.core import Attribute, AttributeQuery
17
18from ndg.security.common.utils import TypedList
19from ndg.security.common.sam_utils.binding.soap.subjectquery import (
20                                                    SubjectQuerySOAPBinding,
21                                                    SubjectQueryResponseError)
22
23# Prevent whole module breaking if this is not available - it's only needed for
24# AttributeQuerySslSOAPBinding
25try:
26    from ndg.security.common.utils.m2crypto import SSLContextProxy
27    _sslContextProxySupport = True
28   
29except ImportError:
30    _sslContextProxySupport = False
31
32
33class AttributeQueryResponseError(SubjectQueryResponseError):
34    """SAML Response error from Attribute Query"""
35   
36
37class AttributeQuerySOAPBinding(SubjectQuery): 
38    """SAML Attribute Query SOAP Binding
39    """
40    QUERY_ATTRIBUTES_ATTRNAME = 'queryAttributes'
41    LEN_QUERY_ATTRIBUTES_ATTRNAME = len(QUERY_ATTRIBUTES_ATTRNAME)
42    QUERY_ATTRIBUTES_PAT = re.compile(',\s*')
43   
44    __PRIVATE_ATTR_PREFIX = "__"
45    __slots__ = (__PRIVATE_ATTR_PREFIX + QUERY_ATTRIBUTES_ATTRNAME,)
46
47   
48    def __init__(self, **kw):
49        '''Create SOAP Client for SAML Attribute Query'''
50        self.__queryAttributes = TypedList(Attribute)
51               
52        super(AttributeQuerySOAPBinding, self).__init__(**kw)
53           
54    def __setattr__(self, name, value):
55        """Enable setting of SAML query attribute objects via a comma separated
56        string suitable for use reading from an ini file. 
57        """
58        try:
59            super(AttributeQuerySOAPBinding, self).__setattr__(name, value)
60           
61        except AttributeError:
62            if name.startswith(
63                        AttributeQuerySOAPBinding.QUERY_ATTRIBUTES_ATTRNAME):
64                # Special handler for parsing string format settings
65                if not isinstance(value, basestring):
66                    raise TypeError('Expecting string format for special '
67                                    '%r attribute; got %r instead' %
68                                    (name, type(value)))
69                   
70                pat = AttributeQuerySOAPBinding.QUERY_ATTRIBUTES_PAT
71                attribute = Attribute()
72               
73                (attribute.name, 
74                 attribute.friendlyName, 
75                 attribute.nameFormat) = pat.split(value)
76                 
77                self.queryAttributes.append(attribute)
78            else:
79                raise
80             
81    def _getQueryAttributes(self):
82        return self.__queryAttributes
83
84    def _setQueryAttributes(self, value):
85        if not isinstance(value, TypedList) and value.elementType != Attribute:
86            raise TypeError('Expecting TypedList(Attribute) type for '
87                            '"queryAttributes"; got %r instead' % type(value)) 
88       
89        self.__queryAttributes = value
90   
91    queryAttributes = property(_getQueryAttributes, 
92                               _setQueryAttributes, 
93                               doc="List of attributes to query from the "
94                                   "Attribute Authority")
95
96    def _createQuery(self):
97        """ Create a SAML attribute query"""
98        attributeQuery = super(AttributeQuerySOAPBinding, self)._createQuery(
99                                                    AttributeQuerySOAPBinding)
100        # Add list of attributes to query                     
101        for attribute in self.queryAttributes:
102            attributeQuery.attributes.append(attribute)
103           
104        return attributeQuery
105
106   
107class AttributeQuerySslSOAPBinding(AttributeQuerySOAPBinding):
108    """Specialisation of AttributeQuerySOAPbinding taking in the setting of
109    SSL parameters for mutual authentication
110    """
111    SSL_CONTEXT_PROXY_SUPPORT = _sslContextProxySupport
112    __slots__ = ('__sslCtxProxy',)
113   
114    def __init__(self, **kw):
115        if not AttributeQuerySslSOAPBinding.SSL_CONTEXT_PROXY_SUPPORT:
116            raise ImportError("ndg.security.common.utils.m2crypto import "
117                              "failed - missing M2Crypto package?")
118       
119        # Miss out default HTTPSHandler and set in send() instead
120        if 'handlers' in kw:
121            raise TypeError("__init__() got an unexpected keyword argument "
122                            "'handlers'")
123           
124        super(AttributeQuerySslSOAPBinding, self).__init__(handlers=(), **kw)
125        self.__sslCtxProxy = SSLContextProxy()
126
127    def send(self, **kw):
128        """Override base class implementation to pass explicit SSL Context
129        """
130        httpsHandler = HTTPSHandler(ssl_context=self.sslCtxProxy.createCtx())
131        self.client.openerDirector.add_handler(httpsHandler)
132        return super(AttributeQuerySslSOAPBinding, self).send(**kw)
133       
134    @property
135    def sslCtxProxy(self):
136        """SSL Context Proxy object used for setting up an SSL Context for
137        queries
138        """
139        return self.__sslCtxProxy
140           
141    def __setattr__(self, name, value):
142        """Enable setting of SSLContextProxy attributes as if they were
143        attributes of this class.  This is intended as a convenience for
144        making settings parameters read from a config file
145        """
146        try:
147            super(AttributeQuerySslSOAPBinding, self).__setattr__(name, value)
148           
149        except AttributeError:
150            # Coerce into setting SSL Context Proxy attributes
151            try:
152                setattr(self.sslCtxProxy, name, value)
153            except:
154                raise
Note: See TracBrowser for help on using the repository browser.