source: TI12-security/branches/ndg-security-1.5.x/ndg_security_server/ndg/security/server/wsgi/attributeauthority.py @ 7632

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/branches/ndg-security-1.5.x/ndg_security_server/ndg/security/server/wsgi/attributeauthority.py@7632
Revision 7632, 16.3 KB checked in by pjkersha, 10 years ago (diff)

Incomplete - task 15: NDG Security 1.5.8 Branch Release for Questionnaire

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