source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authz/__init__.py @ 5181

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authz/__init__.py@5181
Revision 5181, 5.8 KB checked in by pjkersha, 11 years ago (diff)

Added a Policy Information Point to encapsulate subject attribute retrieval.

Line 
1"""WSGI Policy Enforcement Point Package
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "16/01/2009"
7__copyright__ = "(C) 2009 Science and Technology Facilities Council"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__revision__ = "$Id$"
10__license__ = "BSD - see LICENSE file in top-levle directory"
11import logging
12log = logging.getLogger(__name__)
13import httplib
14
15from ndg.security.server.wsgi import NDGSecurityPathFilter
16from ndg.security.common.X509 import X500DN
17from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \
18    NDGSecurityMiddlewareConfigError
19
20from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \
21    NDGSecurityMiddlewareConfigError
22
23from ndg.security.common.authz.msi import PIP, PDP, Request, Response, \
24    Resource, Subject
25
26class PEPMiddleware(NDGSecurityPathFilter):
27    triggerStatus = '403'
28    id = 'forbidden'
29   
30    propertyDefaults = {
31        'sessionKey': 'beaker.session'
32    }
33
34    _isAuthenticated = lambda self: \
35                            'username' in self.environ.get(self.sessionKey, ())
36    isAuthenticated = property(fget=_isAuthenticated,
37                               doc='boolean to indicate is user logged in')
38
39    def __init__(self, app, global_conf, prefix='', **app_conf):
40       
41        # Policy Enforcement Point
42        pipCfg = PEPMiddleware._filterKeywords(app_conf, 'pip.')
43        pip = PIP(**pipCfg)
44
45        # Policy Decision Point
46        pdpCfg = PEPMiddleware._filterKeywords(app_conf, 'pdp.')
47        self.pdp = PDP(pip=pip, **pdpCfg)
48       
49        super(PEPMiddleware, self).__init__(app,
50                                            global_conf,
51                                            prefix=prefix,
52                                            **app_conf)
53
54    @staticmethod
55    def _filterKeywords(conf, prefix):
56        filteredConf = {}
57        prefixLen = len(prefix)
58        for k, v in conf.items():
59            if k.startswith(prefix):
60                filteredConf[k[prefixLen:]] = conf.pop(k)
61               
62        return filteredConf
63               
64    @NDGSecurityPathFilter.initCall
65    def __call__(self, environ, start_response):
66        self.session = self.environ.get(self.sessionKey)
67        if self.isAuthenticated:
68            if self.isAuthorized():
69                # Return next layer in stack
70                return self._app(environ, start_response)
71            else:
72                return self.accessDeniedResponse()
73        else:
74            response = "Not authenticated"
75            start_response(PEPMiddleware.getStatusMessage(401),
76                           [('Content-type', 'text/plain') ,
77                            ('Content-length', str(len(response)))])
78            return response                   
79       
80    def isAuthorized(self):
81        '''Check constraints on the requested URI and return boolean - access
82        allowed/denied'''
83        environ = self.environ
84       
85        # Make a request object to pass to the PDP
86        request = Request()
87        request.subject[Subject.USERID_NS] = self.session['username']
88        request.subject[Subject.SESSIONID_NS] = self.session['sessionId']
89        request.subject[Subject.SESSIONMANAGERURI_NS] = self.session[
90                                                        'sessionManagerURI']
91       
92        resourceURI = self.environ.get('ndg.security.server.wsgi.pep.resource')
93        request.resource[Resource.URI_NS] = resourceURI or self.pathInfo
94           
95        response = self.pdp.evaluate(request)
96        return response.status == Response.DECISION_PERMIT
97   
98    def accessDeniedResponse(self):
99        '''Break out of the WSGI stack and set a error message for the user
100        403 status is still set to enable programmatic handling of this
101        response'''
102        response = "Access Denied"
103        self.start_response(PEPMiddleware.getStatusMessage(403),
104                            [('Content-type', 'text/plain') ,
105                             ('Content-length', str(len(response)))])
106        return response           
107   
108    @classmethod
109    def checker(cls, environ, status, headers):
110        """Set the trigger for calling this middleware.  In this case, it's a
111        HTTP 403 Forbidden response detected in the middleware chain
112        """
113        log.debug("PEPMiddleware.checker received status %r, headers "
114                  "%r", status, headers)
115       
116        if status.startswith(cls.triggerStatus) or environ['PATH_INFO'] == '/test_securedURI':
117#            environ['ndg.security.server.wsgi.pep.resource'] = Resource(environ['PATH_INFO'])
118            log.debug("PEPMiddleware.checker returning True")
119            return True
120        else:
121            log.debug("PEPMiddleware.checker returning False")
122            return False
123
124from authkit.authenticate.multi import MultiHandler
125
126class AuthorizationMiddleware(NDGSecurityMiddlewareBase):
127    '''Handler to call Policy Decision Point middleware and intercept
128    authorisation requests.  Add THIS class to any middleware chain and NOT
129    PEPMiddleware which it wraps.
130    '''
131    resourceKeyName = 'ndg.security.server.wsgi.pep.resource'
132   
133    def __init__(self, app, global_conf, prefix='', **app_conf):
134                       
135        app = MultiHandler(app)
136                           
137        app.add_method(PEPMiddleware.id,
138                       PEPMiddleware.filter_app_factory,
139                       global_conf,
140                       prefix=prefix,
141                       **app_conf)
142       
143        app.add_checker(PEPMiddleware.id, PEPMiddleware.checker)
144               
145       
146        super(AuthorizationMiddleware, self).__init__(app,
147                                                      global_conf,
148                                                      prefix=prefix,
149                                                      **app_conf)
150       
Note: See TracBrowser for help on using the repository browser.