source: TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/authz/service.py @ 7330

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

Incomplete - task 2: XACML-Security Integration

  • integrating XACML context handler with authorisation service.
  • Property svn:keywords set to Id
Line 
1"""Authorization service with SAML 2.0 authorisation decision query interface
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "17/02/10"
7__copyright__ = "(C) 2010 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 ndg.security.server.xacml.ctx_handler import saml_ctx_handler
15
16
17class AuthorisationServiceMiddlewareError(Exception):
18    """Authorisation Service generic exception type"""
19   
20
21class AuthorisationServiceMiddlewareConfigError(
22                                        AuthorisationServiceMiddlewareError):
23    """Authorisation Service configuration error"""
24   
25   
26class AuthorisationServiceMiddleware(object):
27    '''WSGI to add an NDG Security Authorization Service in the environ.
28   
29    @cvar PIP_CFG_PREFIX: prefix for Policy Information Point related parameters
30    @type PIP_CFG_PREFIX: string
31    '''
32    DEFAULT_PARAM_PREFIX = 'authorisationService.'
33    DEFAULT_QUERY_IFACE_KEYNAME = \
34                        'ndg.security.server.wsgi.authzservice.queryInterface'
35   
36    ENVIRON_KEYNAME_QUERY_IFACE_OPTNAME = 'queryInterfaceKeyName'
37   
38    XACML_CTX_HANDLER_PARAM_PREFIX = 'ctx_handler.'
39   
40    # For loop based assignment where possible of config options in initialise()
41    AUTHZ_SRVC_OPTION_DEFAULTS = {
42        ENVIRON_KEYNAME_QUERY_IFACE_OPTNAME: DEFAULT_QUERY_IFACE_KEYNAME,
43    }
44   
45    POLICY_FILEPATH_OPTNAME = 'policyFilePath'
46   
47    __slots__ = (
48        '__xacmlCtxHandler',
49        '__queryInterface', 
50        '__' + ENVIRON_KEYNAME_QUERY_IFACE_OPTNAME,
51        '_app',
52    )
53       
54    def __init__(self, app):
55        '''Set-up an Authorisation Service instance
56       
57        @param app: next app/middleware in WSGI stack
58        @type app: callable
59        '''
60        self._app = app
61        self.__xacmlCtxHandler = saml_ctx_handler.SamlCtxHandler()
62        self.__queryInterface = None
63        self.__queryInterfaceKeyName = None
64       
65    def initialise(self, prefix=DEFAULT_PARAM_PREFIX, **app_conf):
66        """Set-up Authorization Service middleware from keyword settings
67       
68        @type prefix: basestring
69        @param prefix: prefix for configuration items
70        @type app_conf: dict       
71        @param app_conf: PasteDeploy application specific configuration
72        dictionary
73        """
74        cls = AuthorisationServiceMiddleware
75       
76        # Loop based assignment where possible
77        for optName, default in cls.AUTHZ_SRVC_OPTION_DEFAULTS.items():
78            value = app_conf.get(prefix + optName, default)
79            setattr(self, optName, value)
80       
81        self.queryInterface = self.createQueryInterface()   
82       
83        # Initialise the XACML Context handler.  This handles PEP requests and
84        # PDP queries to the PIP
85        ctxHandlerPrefix = prefix + cls.XACML_CTX_HANDLER_PARAM_PREFIX
86        self.__xacmlCtxHandler = saml_ctx_handler.SamlCtxHandler.fromKeywords(
87                                                ctxHandlerPrefix, **app_conf)
88           
89        # Initialise the XACML Context handler
90       
91    @classmethod
92    def filter_app_factory(cls, app, global_conf, **app_conf):
93        '''Wrapper to enable instantiation compatible with Paste Deploy
94        filter application factory function signature
95       
96        @type app: callable following WSGI interface
97        @param app: next middleware application in the chain     
98        @type global_conf: dict       
99        @param global_conf: PasteDeploy global configuration dictionary
100        @type prefix: basestring
101        @param prefix: prefix for configuration items
102        @type app_conf: dict       
103        @param app_conf: PasteDeploy application specific configuration
104        dictionary
105        '''
106        app = cls(app)
107        app.initialise(**app_conf)
108       
109        return app
110   
111    def __call__(self, environ, start_response):
112        '''Set the Authorization Decision function in environ
113       
114        @type environ: dict
115        @param environ: WSGI environment variables dictionary
116        @type start_response: function
117        @param start_response: standard WSGI start response function
118        @rtype: iterable
119        @return: next application in the WSGI stack
120        '''
121        environ[self.queryInterfaceKeyName] = self.queryInterface
122        return self._app(environ, start_response)
123
124
125    def _get_queryInterfaceKeyName(self):
126        return self.__queryInterfaceKeyName
127
128    def _set_queryInterfaceKeyName(self, val):
129        if not isinstance(val, basestring):
130            raise TypeError('Expecting %r for "getAuthzDecisionKeyName" '
131                            'attribute; got %r' % (basestring, type(val)))
132        self.__queryInterfaceKeyName = val
133       
134    queryInterfaceKeyName = property(fget=_get_queryInterfaceKeyName, 
135                                     fset=_set_queryInterfaceKeyName, 
136                                     doc="Key name used to index "
137                                         "Authorization Service SAML authz "
138                                         "decision query function in environ "
139                                         "dictionary")
140   
141    def _get_queryInterface(self):
142        return self.__queryInterface
143   
144    def _set_queryInterface(self, value):
145        if isinstance(value, basestring):
146            self.__queryInterface = importModuleObject(value)
147           
148        elif callable(value):
149            self.__queryInterface = value
150        else:
151            raise TypeError('Expecting callable for "queryInterface" '
152                            'attribute; got %r instead.' % type(value))
153   
154    queryInterface = property(_get_queryInterface,
155                              _set_queryInterface,
156                              doc="authorisation decision function set in "
157                                  "environ for downstream SAML Query "
158                                  "middleware to invoke in response to "
159                                  "<authzDecisionQuery>s")
160         
161    def createQueryInterface(self):
162        """Return the authorisation decision function so that __call__ can add
163        it to environ for the SAML Query middleware to pick up and invoke
164       
165        @return: SAML authorisation decision function
166        @rtype: callable
167        """
168       
169        # Nest function within AuthorisationServiceMiddleware method so that
170        # self is in its scope
171        def getAuthzDecision(authzDecisionQuery, samlResponse):
172            """Authorisation decision function accepts a SAML AuthzDecisionQuery
173            and calls the XACML context handler returning a response.  The
174            context handler is an interface to the the XACML Policy Decision
175            Point, XACML polic(y|ies) and Policy Information Point.
176           
177            @type authzDecisionQuery: ndg.saml.saml2.core.AuthzDecisionQuery
178            @param authzDecisionQuery: WSGI environment variables dictionary
179            @rtype: ndg.saml.saml2.core.Response
180            @return: SAML response containing Authorisation Decision Statement
181            """
182            # Create special request object which enables the context handler
183            # to formulate a response from the query and the existing response
184            # object initialised by this object
185            request = saml_ctx_handler.SamlPEPRequest()
186            request.authzDecisionQuery = authzDecisionQuery
187            request.response = samlResponse
188           
189            response = self.__xacmlCtxHandler.handlePEPRequest(request)
190           
191            return response
192           
193        return getAuthzDecision
Note: See TracBrowser for help on using the repository browser.