Changeset 4975


Ignore:
Timestamp:
13/02/09 16:40:02 (11 years ago)
Author:
pjkersha
Message:
  • Refactored ndg.security.server.wsgi.pdp integrating authkit MultiHandler? and added stub for XACML PDP call
  • Added ndg.security.common.authz.pdp.xacml module: a first stab at incorporating some of the principles of XACML into the code base
Location:
TI12-security/trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/pdp/__init__.py

    r4840 r4975  
    5656    """PEP (Gatekeeper) abstract interface to a Policy Decision Point 
    5757     
    58     PDPs must adhere to this interface by subclassing from it""" 
     58    PDPs must adhere to this interface by sub-classing from it""" 
    5959     
    6060    def __init__(self,  
     
    115115    # Alias for convenience 
    116116    __call__ = accessPermitted 
     117     
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/pdp.py

    r4909 r4975  
    1313import httplib 
    1414 
     15from ndg.security.common.authz.pdp.xacml import PDP 
     16 
    1517from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \ 
    1618    NDGSecurityMiddlewareConfigError 
     
    2022 
    2123class PDPMiddleware(NDGSecurityMiddlewareBase): 
    22     '''Policy Decision Point WSGI middleware - traps 403 Forbidden HTTP codes 
    23     and checks user authorisation credentials''' 
    24     propertyDefaults = { 
    25         'forbidden403MsgURI': None, 
    26     } 
    27     propertyDefaults.update(NDGSecurityMiddlewareBase.propertyDefaults) 
     24    forbiddenStatus = '403' 
     25    id = 'forbidden' 
    2826     
    29     def __init__(self, *arg, **kw): 
    30         super(PDPMiddleware, self).__init__(*arg, **kw) 
    31 #        if not getattr(self, 'forbidden403MsgURI', None): 
    32 #            raise PDPMiddlewareConfigError('"forbidden403MsgURI" parameter ' 
    33 #                                           'must be set so that if access is ' 
    34 #                                           'denied to a URI, then a message ' 
    35 #                                           'can be displayed') 
     27    _isAuthenticated = lambda self: 'REMOTE_USER' in environ 
     28    isAuthenticated = property(fget=_isAuthenticated, 
     29                               doc='boolean for is user logged in') 
     30 
     31    def __init__(self, app, global_conf, **app_conf): 
     32        super(PDPMiddleware, self).__init__(app, global_conf, **app_conf) 
     33        self.pdp = PDP() 
     34         
     35    @PDPMiddleware.initCall 
     36    def __call__(self, environ, start_response): 
     37        if self.isAuthenticated: 
     38            if self.isAuthorized(): 
     39                # Return next layer in stack 
     40                return self._app(environ, start_response) 
     41            else: 
     42                return self.accessDeniedResponse() 
     43        else: 
     44            response = "Not authenticated" 
     45            start_response(PDPMiddleware.getStatusMessage(401),  
     46                           [('Content-type', 'text/plain') , 
     47                            ('Content-length', str(len(response)))]) 
     48            return response             
    3649             
    37     @NDGSecurityMiddlewareBase.initCall 
    38     def __call__(self, environ, start_response): 
    39         log.debug("PDPMiddleware.__call__ ...") 
     50    def isAuthorized(self): 
     51        '''Check constraints on the requested URI and return boolean - access 
     52        allowed/denied''' 
     53        status = self.pdp(subject, resource, action, environ) 
     54        return status 
     55     
     56    def accessDeniedResponse(self): 
     57        '''Break out of the WSGI stack and set a error message for the user 
     58        403 status is still set to enable programmatic handling of this  
     59        response''' 
     60        response = "Access Denied" 
     61        start_response(PDPMiddleware.getStatusMessage(403),  
     62                       [('Content-type', 'text/plain') , 
     63                        ('Content-length', str(len(response)))]) 
     64        return response             
     65    
     66    @classmethod 
     67    def checker(cls, environ, status, headers): 
     68        """Set the trigger for calling this middleware.  In this case, it's a 
     69        HTTP 403 Forbidden response detected in the middleware chain 
     70        """ 
     71        log.debug("PDPMiddleware.checker received status %r, headers " 
     72                  "%r", status, headers) 
    4073         
    41         forbidden403HandlerApp = None 
    42          
    43         def app(environ, start_response): 
    44             def _start_response(status, header, exc_info=None): 
    45                 if status.startswith('403'): 
    46                     forbidden403HandlerApp = Forbidden403HandlerApp(environ,  
    47                                                                 start_response) 
    48             return self._app(environ, _start_response)  
    49                 
    50 #        def _start_response(status, header, exc_info=None): 
    51 #            '''alter start_response to return unauthorised status 
    52 #             
    53 #            @type status: str 
    54 #            @param status: HTTP status code and status message 
    55 #            @type header: list 
    56 #            @param header: list of field, value tuple HTTP header content 
    57 #            @type exc_info: Exception 
    58 #            @param exc_info: exception info 
    59 #            ''' 
    60 #            log.debug('PDP start response...') 
    61 #             
    62 #            if status.startswith('403'): 
    63 #                log.debug("Trapped 403 status...") 
    64 #                 
    65 #                if 'REMOTE_USER' in environ: 
    66 #                    # TODO: Should carry out authorisation check here - leave  
    67 #                    # as authentication check only for now 
    68 #                    log.debug("User is logged in: checking authorisation " 
    69 #                              "credentials...") 
    70 ##                    self._redirect(self.forbidden403MsgURI, 
    71 ##                                   start_response=start_response) 
    72 #                else: 
    73 #                    log.debug("User is not logged in: setting 401 response...") 
    74 #                    code = 401 
    75 #                        
    76 #            return start_response(status, header, exc_info) 
     74        if status.startswith(cls.forbiddenStatus): 
     75            log.debug("PDPMiddleware.checker returning True") 
     76            return True 
     77        else: 
     78            log.debug("PDPMiddleware.checker returning False") 
     79            return False 
    7780 
    78         _app = app(environ, start_response) 
    79         if forbidden403HandlerApp is not None: 
    80             return forbidden403HandlerApp 
    81         else: 
    82             return _app 
    83             
    84     def _checkAccess(self, environ, start_response): 
    85         if 'REMOTE_USER' in environ: 
    86             # TODO: Check authorization credentials 
    87             code = 200 
    88         else: 
    89             code = 401 
    90              
    91         return PDPMiddleware.getStatusMessage(code) 
    92  
    93 def Forbidden403HandlerApp(environ, start_response): 
    94     response = "Access Denied" 
    95     start_response('403 Forbidden',  
    96                    [('Content-type', 'text/plain') , 
    97                     ('Content-length', str(len(response)))]) 
    98     return response 
    99  
    100 def Forbidden403HandlerAppFactory(app, global_conf, **app_conf): 
    101     return Forbidden403HandlerApp 
    102         
    10381from authkit.authenticate.multi import MultiHandler 
    10482 
    105 def forbidden403Checker(environ, status, headers): 
    106     """ 
    107     Used by AuthKit to intercept statuses specified in the config file  
    108     option ``authkit.intercept``. 
    109     """ 
    110     log.debug( 
    111         "forbidden403Checker received status %r, headers %r, intercept %r",  
    112         status,  
    113         headers,  
    114         '403') 
     83class PDPHandlerMiddleware(MultiHandler, NDGSecurityMiddlewareBase): 
     84    '''Handler to call Policy Decision Point middleware and intercept 
     85    authorisation requests.  Add THIS class to any middleware chain and NOT 
     86    PDPMiddleware which it wraps. 
     87    ''' 
     88    def __init__(self, app, global_conf, **app_conf): 
     89        MultiHandler.__init__(self, app) 
     90 
     91        self.add_method(PDPMiddleware.id,  
     92                        PDPMiddleware.filter_app_factory,  
     93                        global_conf, 
     94                        **app_conf) 
     95         
     96        self.add_checker(PDPMiddleware.id, PDPMiddleware.checker) 
    11597     
    116     if str(status[:3]) == '403': 
    117         log.debug("forbidden403Checker returning True") 
    118         return True 
    119      
    120     log.debug("forbidden403Checker returning False") 
    121     return False 
    122  
    123 def PDPMiddlewareAppFactory(app, global_conf, **app_conf): 
    124     app = MultiHandler(app) 
    125     app.add_method("forbidden", Forbidden403HandlerAppFactory, global_conf, **app_conf) 
    126     app.add_checker("forbidden", forbidden403Checker) 
    127      
    128     return app 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/integration/authz/services.ini

    r4909 r4975  
    4747paste.filter_app_factory=ndg.security.server.wsgi.pep:PEPMiddleware.filter_app_factory 
    4848prefix = pep. 
    49 pep.pathMatchList = /test_403, /test_securedURI 
     49pep.pathMatchList = /test_securedURI 
    5050 
    5151[filter:PDPMiddlewareFilter] 
    5252#paste.filter_app_factory=ndg.security.server.wsgi.pdp:PDPMiddleware.filter_app_factory 
    5353#prefix = pdp. 
    54 #pdp.forbidden403MsgURI = /accessdenied 
    55 paste.filter_app_factory = ndg.security.server.wsgi.pdp:PDPMiddlewareAppFactory 
     54#paste.filter_app_factory = ndg.security.server.wsgi.pdp:PDPMiddlewareAppFactory 
     55paste.filter_app_factory = ndg.security.server.wsgi.pdp:PDPHandlerMiddleware.filter_app_factory 
    5656 
    5757#______________________________________________________________________________ 
Note: See TracChangeset for help on using the changeset viewer.