source: TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/attributeauthority.py @ 6586

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/attributeauthority.py@6586
Revision 6586, 15.9 KB checked in by pjkersha, 10 years ago (diff)

Started ESG Authorisation Service implementation ndg.security.server.wsgi.authorizationservice - SAML SOAP based interface to a Policy Decision Point enabling centralised policy for a range of services.

Line 
1"""WSGI Middleware to set an Attribute Authority instance in tyhe WSGI environ
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "19/08/09"
7__copyright__ = "(C) 2009 Science and Technology Facilities Council"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__revision__ = "$Id: $"
11import logging
12log = logging.getLogger(__name__)
13import os
14
15from ndg.security.server.attributeauthority import AttributeAuthority
16from ndg.security.server.wsgi import NDGSecurityMiddlewareBase
17from ndg.security.server.wsgi.zsi import SOAPBindingMiddleware
18
19
20class AttributeAuthorityMiddleware(NDGSecurityMiddlewareBase):
21    '''WSGI to add an NDG Security Attribute Authority in the environ.  This
22    enables multiple WSGI filters to access the same underlying Attribute
23    Authority instance e.g. provide SAML SOAP and WSDL SOAP based interfaces
24    to the same Attribute Authority
25    '''
26    DEFAULT_KEYNAME = 'ndg.security.server.wsgi.attributeauthority'
27    ENVIRON_KEYNAME_CFG_OPTNAME = 'environKeyName'
28   
29    DEFAULT_ATTR_QUERY_IFACE_KEYNAME = \
30        'ndg.security.server.wsgi.attributeauthority.attributeQuery'
31    ENVIRON_KEYNAME_ATTR_QUERY_IFACE_CFG_OPT_NAME = \
32        'environKeyNameAttributeQueryInterface'
33       
34    def __init__(self, app):
35        '''Set-up an Attribute Authority instance
36        '''
37        # Stop in debugger at beginning of SOAP stub if environment variable
38        # is set
39        self.__debug = bool(os.environ.get('NDGSEC_INT_DEBUG'))
40        if self.__debug:
41            import pdb
42            pdb.set_trace()
43       
44        self._app = app
45        self.__aa = None
46        self.__attributeQuery = None
47        self.__keyName = None
48        self.__attributeQueryKeyName = None
49
50    def initialise(self, global_conf, prefix='attributeauthority.',
51                   **app_conf):
52        """Set-up Attribute authority middleware using a Paste app factory
53        pattern.  Overloaded base class method to enable custom settings from
54        app_conf
55       
56        @type app: callable following WSGI interface
57        @param app: next middleware application in the chain     
58        @type global_conf: dict       
59        @param global_conf: PasteDeploy global configuration dictionary
60        @type prefix: basestring
61        @param prefix: prefix for configuration items
62        @type app_conf: dict       
63        @param app_conf: PasteDeploy application specific configuration
64        dictionary
65        """
66        # Set key name for attribute authority set in environ
67        environKeyOptName = prefix + \
68                    AttributeAuthorityMiddleware.ENVIRON_KEYNAME_CFG_OPTNAME
69                   
70        self.keyName = app_conf.pop(environKeyOptName,
71                                AttributeAuthorityMiddleware.DEFAULT_KEYNAME)
72
73        attrQueryIfaceEnvironKeyOptName = prefix + \
74            AttributeAuthorityMiddleware.\
75            ENVIRON_KEYNAME_ATTR_QUERY_IFACE_CFG_OPT_NAME
76           
77        self.attributeQueryKeyName = app_conf.pop(
78            attrQueryIfaceEnvironKeyOptName,
79            AttributeAuthorityMiddleware.DEFAULT_ATTR_QUERY_IFACE_KEYNAME)
80       
81        self.aa = AttributeAuthority.fromProperties(propPrefix=prefix,
82                                                    **app_conf)
83        self.attributeQuery = self.aa.samlAttributeQueryFactory()
84
85    @classmethod
86    def filter_app_factory(cls, app, global_conf, **app_conf):
87        '''Wrapper to enable instantiation compatible with Paste Deploy
88        filter application factory function signature
89       
90        @type app: callable following WSGI interface
91        @param app: next middleware application in the chain     
92        @type global_conf: dict       
93        @param global_conf: PasteDeploy global configuration dictionary
94        @type prefix: basestring
95        @param prefix: prefix for configuration items
96        @type app_conf: dict       
97        @param app_conf: PasteDeploy application specific configuration
98        dictionary
99        '''
100        app = AttributeAuthorityMiddleware(app)
101        app.initialise(global_conf, **app_conf)
102       
103        return app
104   
105    def __call__(self, environ, start_response):
106        '''Set the Attribute Authority instantiated at initialisation in
107        environ
108       
109        @type environ: dict
110        @param environ: WSGI environment variables dictionary
111        @type start_response: function
112        @param start_response: standard WSGI start response function
113        @rtype: iterable
114        @return: next application in the WSGI stack
115        '''
116        environ[self.keyName] = self.aa
117        environ[self.attributeQueryKeyName] = self.attributeQuery
118        return self._app(environ, start_response)
119   
120    def _get_aa(self):
121        return self.__aa
122   
123    def _set_aa(self, val):
124        if not isinstance(val, AttributeAuthority):
125            raise TypeError('Expecting %r for "aa" attribute; got %r' %
126                            (AttributeAuthority, type(val)))
127        self.__aa = val
128           
129    aa = property(fget=_get_aa,
130                  fset=_set_aa,
131                  doc="Attribute Authority instance")
132
133    def _getKeyName(self):
134        return self.__keyName
135
136    def _setKeyName(self, val):
137        if not isinstance(val, basestring):
138            raise TypeError('Expecting %r for "keyName" attribute; got %r' %
139                            (basestring, type(val)))
140        self.__keyName = val
141       
142    keyName = property(fget=_getKeyName, 
143                       fset=_setKeyName, 
144                       doc="Key name used to index Attribute Authority in "
145                           "environ dictionary")
146
147    def _get_attributeQueryKeyName(self):
148        return self.__attributeQueryKeyName
149
150    def _set_attributeQueryKeyName(self, val):
151        if not isinstance(val, basestring):
152            raise TypeError('Expecting %r for "attributeQueryKeyName" '
153                            'attribute; got %r' % (basestring, type(val)))
154        self.__attributeQueryKeyName = val
155       
156    attributeQueryKeyName = property(fget=_get_attributeQueryKeyName, 
157                                     fset=_set_attributeQueryKeyName, 
158                                     doc="Key name used to index Attribute "
159                                         "Authority SAML attribute query "
160                                         "function in environ dictionary")
161   
162    def _get_attributeQuery(self):
163        return self.__attributeQuery
164
165    def _set_attributeQuery(self, val):
166        if not callable(val):
167            raise TypeError('Expecting a callable for "attributeQuery" '
168                            'attribute; got %r' % type(val))
169        self.__attributeQuery = val
170       
171    attributeQuery = property(fget=_get_attributeQuery, 
172                              fset=_set_attributeQuery, 
173                              doc="Attribute Authority SAML attribute query "
174                                  "function")
175
176
177from ndg.security.server.zsi.attributeauthority import AttributeAuthorityWS
178
179class AttributeAuthoritySOAPBindingMiddlewareConfigError(Exception):
180    """Raise if a configuration problem is found"""
181   
182   
183class AttributeAuthoritySOAPBindingMiddleware(NDGSecurityMiddlewareBase,
184                                              AttributeAuthorityWS):
185    """Inheritance from NDGSecurityMiddlewareBase provides a __call__
186    implementation which sets a reference to environ as an object attribute.
187   
188    Inheritance from AttributeAuthorityWS enables preservation of the same
189    SOAP callbacks but with the
190    ndg.security.server.attributeauthority.AttributeAuthority instance provided
191    from environ
192   
193    @type DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME: basestring
194    @cvar DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME: Key name used to index the
195    ndg.security.server.attributeauthority.AttributeAuthority instance in the
196    environ dictionary
197    @type ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME: basestring
198    @cvar ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME: configuration option name
199    for the attribute authority environ key
200    @type DEFAULT_ENVIRON_KEYNAME: basestring
201    @cvar DEFAULT_ENVIRON_KEYNAME: default value for Key name used to index
202    THIS SOAP Service Binding middleware instance in the environ dictionary
203    @type ENVIRON_KEYNAME_CFG_OPTNAME: basestring
204    @cvar ENVIRON_KEYNAME_CFG_OPTNAME: configuration option name for this
205    middleware's environ key
206    """
207    DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME = \
208                "ndg.security.server.attributeauthority.AttributeAuthority"
209    ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME = \
210                'attributeAuthorityEnvironKeyName'
211   
212    DEFAULT_ENVIRON_KEYNAME = ("ndg.security.server.wsgi.attributeauthority."
213                               "AttributeAuthoritySOAPBindingMiddleware")
214    ENVIRON_KEYNAME_CFG_OPTNAME = 'environKeyName'
215   
216    def __init__(self, app):
217        """Don't call AttributeAuthorityWS.__init__ - AttributeAuthority
218        instance is provided via environ through upstream
219        AttributeAuthorityMiddleware
220        """
221        # Call this base class initialiser to set-up the environ attribute
222        NDGSecurityMiddlewareBase.__init__(self, app, None)
223        AttributeAuthorityWS.__init__(self)
224       
225        self.__keyName = None
226        self.__attributeAuthorityKeyName = None
227       
228    def _getKeyName(self):
229        return self.__keyName
230
231    def _setKeyName(self, val):
232        if not isinstance(val, basestring):
233            raise TypeError('Expecting %r for "keyName" attribute; got %r' %
234                            (basestring, type(val)))
235        self.__keyName = val
236       
237    keyName = property(fget=_getKeyName, 
238                       fset=_setKeyName, 
239                       doc="Key name used to index THIS SOAP Service Binding "
240                           "middleware instance in the environ dictionary")   
241
242    def _getAttributeAuthorityKeyName(self):
243        return self.__attributeAuthorityKeyName
244
245    def _setAttributeAuthorityKeyName(self, val):
246        if not isinstance(val, basestring):
247            raise TypeError('Expecting %r for "attributeAuthorityKeyName" '
248                            'attribute; got %r' %(basestring, type(val)))
249        self.__attributeAuthorityKeyName = val
250       
251    attributeAuthorityKeyName = property(fget=_getAttributeAuthorityKeyName, 
252                                         fset=_setAttributeAuthorityKeyName, 
253                                         doc="Key name used to index the "
254                                             "ndg.security.server.attribute"
255                                             "authority.AttributeAuthority "
256                                             "instance in the environ "
257                                             "dictionary") 
258             
259    @classmethod
260    def filter_app_factory(cls, app, global_conf, 
261        attributeAuthoritySOAPBindingPrefix='attributeauthority.soapbinding.', 
262        **app_conf):
263        """Set-up Attribute Authority SOAP Binding middleware using a Paste app
264        factory pattern.  Overloaded base class method to enable custom
265        settings from app_conf
266       
267        @type app: callable following WSGI interface
268        @param app: next middleware application in the chain     
269        @type global_conf: dict       
270        @param global_conf: PasteDeploy global configuration dictionary
271        @type prefix: basestring
272        @param prefix: prefix for configuration items
273        @type app_conf: dict       
274        @param app_conf: PasteDeploy application specific configuration
275        dictionary
276        """
277        # Generic Binding middleware intercepts the SOAP_ACTION set in environ
278        # and maps it to the matching soap_{SOAP_ACTION} method from this class
279        soapBindingApp = SOAPBindingMiddleware.filter_app_factory(app, 
280                                                                  global_conf,
281                                                                  **app_conf)
282       
283        # Make the SOAP Binding wrapper pick up this Attribute Authority
284        # specific SOAP Binding
285        optName = attributeAuthoritySOAPBindingPrefix + \
286                cls.ENVIRON_KEYNAME_CFG_OPTNAME
287        soapBindingApp.serviceSOAPBindingKeyName = app_conf.get(optName,
288                                                cls.DEFAULT_ENVIRON_KEYNAME)
289       
290        # Instantiate this middleware and copy the environ key name setting for
291        # the Attribute Authority Service SOAP Binding
292        app = cls(soapBindingApp)
293        app.keyName = soapBindingApp.serviceSOAPBindingKeyName
294       
295        # envrion key name for the
296        # ndg.security.server.attributeauthority.AttributeAuthority instance
297        optName = attributeAuthoritySOAPBindingPrefix + \
298                cls.ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME
299               
300        app.attributeAuthorityKeyName = app_conf.get(optName,
301                           cls.DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME)
302
303           
304        # Extract local WS-Security signature verification filter
305        optName = attributeAuthoritySOAPBindingPrefix + \
306                            cls.WSSE_SIGNATURE_VERIFICATION_FILTER_ID_OPTNAME
307        app.wsseSignatureVerificationFilterID = app_conf.pop(optName, None)
308        if app.wsseSignatureVerificationFilterID is None:
309            log.warning('No "%s" option was set in the input config' % 
310                        cls.WSSE_SIGNATURE_VERIFICATION_FILTER_ID_OPTNAME)
311        else:   
312            log.info('Updated setting from "%s" option' % 
313                     cls.WSSE_SIGNATURE_VERIFICATION_FILTER_ID_OPTNAME)
314                   
315        return app
316 
317    @NDGSecurityMiddlewareBase.initCall
318    def __call__(self, environ, start_response):
319        """Set a reference to self in environ for the SOAPBindingMiddleware
320        instance to pick up downstream
321       
322        @type environ: dict
323        @param environ: WSGI environment variables dictionary
324        @type start_response: function
325        @param start_response: standard WSGI start response function
326        """
327
328        environ[self.keyName] = self
329        return self._app(environ, start_response)
330   
331    def soap_getAttCert(self, ps):
332        '''Retrieve an Attribute Certificate
333       
334        @type ps: ZSI ParsedSoap
335        @param ps: client SOAP message
336        @rtype: ndg.security.common.zsi.attributeauthority.AttributeAuthority_services_types.getAttCertResponse_Holder
337        @return: response'''
338        self._setAttributeAuthorityFromEnviron()
339        return AttributeAuthorityWS.soap_getAttCert(self, ps)
340
341    def soap_getHostInfo(self, ps):
342        '''Get information about this host
343               
344        @type ps: ZSI ParsedSoap
345        @param ps: client SOAP message
346        @rtype: response
347        @return: response'''
348        self._setAttributeAuthorityFromEnviron()
349        return AttributeAuthorityWS.soap_getHostInfo(self, ps)
350   
351    def soap_getAllHostsInfo(self, ps):
352        '''Get information about all hosts
353               
354        @type ps: ZSI ParsedSoap
355        @param ps: client SOAP message
356        @rtype: tuple
357        @return: response object'''
358        self._setAttributeAuthorityFromEnviron()
359        return AttributeAuthorityWS.soap_getAllHostsInfo(self, ps)
360   
361    def soap_getTrustedHostInfo(self, ps):
362        '''Get information about other trusted hosts
363               
364        @type ps: ZSI ParsedSoap
365        @param ps: client SOAP message
366        @rtype: tuple
367        @return: response object'''
368        self._setAttributeAuthorityFromEnviron()
369        return AttributeAuthorityWS.soap_getTrustedHostInfo(self, ps)
370   
371    def _setAttributeAuthorityFromEnviron(self):
372        self.aa = self.environ.get(self.attributeAuthorityKeyName)
373        if self.aa is None:
374            raise AttributeAuthoritySOAPBindingMiddlewareConfigError(
375                                            'No "%s" key found in environ' % 
376                                            self.attributeAuthorityKeyName)
Note: See TracBrowser for help on using the repository browser.