Changeset 5280


Ignore:
Timestamp:
13/05/09 15:00:34 (10 years ago)
Author:
pjkersha
Message:

Further improvements to the authorization middleware:

  • PEPFilter no longer explicitly calls the PEPResultHandlerMiddleware (This latter class is the WSGI component which handles the access denied response that the server returns). This is not necessary as it can set a 403 response in order to trigger multiHandlerIntercept callback function set in the MultiHandler? instance. This responds to all 403 type status codes by invoking the PEPResultHandlerMiddleware.
  • ndg.security.common.authz.msi: improvements to the PDP, PIP and Response classes.
  • ndg.security.test.integration.dap: added integration test for secured pyDAP service
Location:
TI12-security/trunk/python
Files:
26 added
9 edited

Legend:

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

    r5273 r5280  
    146146 
    147147class Response(object): 
    148  
     148    '''Response from a PDP''' 
    149149    decisionValues = range(4) 
    150150    (DECISION_PERMIT, 
     
    156156    DECISIONS = ("Permit", "Deny", "Indeterminate", "NotApplicable") 
    157157     
     158    decisionValue2String = dict(zip(decisionValues, DECISIONS)) 
     159     
    158160    def __init__(self, status, message=None): 
     161         
     162        self.status = status 
     163        self.message = message 
     164 
     165    def _setStatus(self, status): 
    159166        if status not in Response.decisionValues: 
    160167            raise TypeError("Status %s not recognised" % status) 
    161168         
    162         self.status = status 
    163         self.message = message 
    164   
     169        self._status = status 
     170         
     171    def _getStatus(self): 
     172        return getattr(self, '_status', Response.DECISION_INDETERMINATE) 
     173     
     174    status = property(fget=_getStatus, 
     175                      fset=_setStatus, 
     176                      doc="Integer response code; one of %r" % decisionValues) 
    165177         
    166178from ndg.security.common.AttCert import AttCertInvalidSignature, \ 
     
    260272    """Policy Information Point - this implementation enables the PDP to  
    261273    retrieve attributes about the Subject""" 
    262  
     274    wsseSectionName = 'wssecurity' 
     275     
    263276    def __init__(self, prefix='', **cfg): 
    264277        '''Set-up WS-Security and SSL settings for connection to an 
     
    272285        ''' 
    273286        self.wssecurityCfg = WSSecurityConfig() 
    274         wssePrefix = prefix + 'wssecurity' 
     287        wssePrefix = prefix + PIP.wsseSectionName 
    275288        self.wssecurityCfg.update(cfg, prefix=wssePrefix) 
    276289                  
    277290        # List of CA certificates used to verify peer certificate with SSL 
    278291        # connections to Attribute Authority 
    279         self.sslCACertFilePathList = cfg.get(prefix + 'sslCACertFilePathList', []) 
     292        self.sslCACertFilePathList=cfg.get(prefix+'sslCACertFilePathList', []) 
    280293         
    281294        # List of CA certificates used to verify the signatures of  
     
    495508         
    496509        knownAttributeAuthorityURIs = [] 
     510        request.subject[Subject.ROLES_NS] = [] 
    497511        for matchingTarget in matchingTargets: 
    498512             
     
    524538                                        matchingTarget.attributeAuthorityURI) 
    525539                 
    526                 request.subject[Subject.ROLES_NS] = attributeResponse[ 
     540                request.subject[Subject.ROLES_NS] += attributeResponse[ 
    527541                                                            Subject.ROLES_NS] 
    528542                
     
    532546                return Response(Response.DECISION_PERMIT) 
    533547             
    534         return Response(Response.DECISION_DENY) 
    535      
    536  
    537          
     548        return Response(Response.DECISION_DENY, 
     549                        message="Insufficient privileges to access the " 
     550                                "resource") 
     551     
     552 
     553         
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/wssecurity/signaturehandler/__init__.py

    r5182 r5280  
    447447        @return: certificate object 
    448448        ''' 
    449         log.debug("Getting verifying cert") 
    450449        return self._verifyingCert 
    451450 
     
    453452    def _setVerifyingCert(self, verifyingCert): 
    454453        "Set property method for X.509 cert. used to verify a signature" 
    455         log.debug("Setting verifying cert") 
    456454        self._verifyingCert = self._setCert(verifyingCert) 
     455         
    457456        # Reset file path as it may no longer apply 
    458457        self._verifyingCertFilePath = None 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/__init__.py

    r5091 r5280  
    9191            return self._app(environ, start_response) 
    9292        else: 
    93             return self._setErrorResponse(environ,  
    94                                           start_response,  
     93            return self._setErrorResponse(start_response=start_response,  
    9594                                          msg=notFoundMsg, 
    9695                                          code=404, 
    9796                                          contentType=notFoundMsgContentType) 
    9897             
    99     def _setErrorResponse(self, environ=None, start_response=None, msg=None,  
     98    def _setErrorResponse(self, start_response=None, msg=None,  
    10099                          code=500, contentType=None): 
    101100        '''Convenience method to set a simple error response 
    102101         
    103         @type environ: dict 
    104         @param environ: standard WSGI environ parameter 
    105         @type start_response: builtin_function_or_method 
     102        @type start_response: function 
    106103        @param start_response: standard WSGI callable to set the HTTP header 
    107104        @type msg: basestring 
     
    112109        @param contentType: set 'Content-type' HTTP header field - defaults to 
    113110        'text/plain' 
    114         ''' 
    115         if environ is None: 
    116             environ = self.environ 
    117              
     111        '''             
    118112        if start_response is None: 
    119113            start_response = self.start_response 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authn.py

    r5279 r5280  
    146146        HTTP 401 Unauthorized response detected in the middleware chain 
    147147        """ 
    148         log.debug("%s.checker received status %r, " 
    149                   "headers %r", cls.__name__, status, headers) 
    150          
    151148        if status.startswith(cls.triggerStatus): 
    152149            log.debug("%s.checker caught status %s: invoking authentication " 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authz/__init__.py

    r5279 r5280  
    1111import logging 
    1212log = logging.getLogger(__name__) 
     13from time import time 
    1314import httplib 
    1415 
     
    5455        self.session = self.environ.get(self.sessionKey) 
    5556        if not self.isAuthenticated: 
    56             response = "Not authenticated" 
    57             start_response(self.__class__.getStatusMessage(401), 
    58                            [('Content-type', 'text/plain') , 
    59                             ('Content-length', str(len(response)))]) 
    60             return response 
     57            # This condition should be caught be the PEPFilter 
     58            log.warning("PEPResultHandlerMiddleware: user is not " 
     59                        "authenticated - setting HTTP 401 response") 
     60            return self._setErrorResponse(code=401) 
    6161        else: 
    6262            # TODO: refactor to include a call to another interface - possibly 
    6363            # - another WSGI to set a user friendly output and include links 
    6464            # to enable the user to register for new access privileges 
    65             response = ("Access is forbidden for this resource.\n\nPlease " 
    66                         "check with your site administrator that you have " 
    67                         "the required access privileges") 
    68             start_response(self.__class__.getStatusMessage(403), 
    69                            [('Content-type', 'text/plain') , 
    70                             ('Content-length', str(len(response)))]) 
    71             return response 
     65             
     66            # Get response message from PDP recorded by PEP 
     67            msg = getattr(self.session.get('pepCtx', {}).get('response'), 
     68                          'message', '') 
     69                 
     70            response = \ 
     71"""Access is forbidden for this resource: 
     72%s 
     73Please check with your site administrator that you have the required access privileges. 
     74""" % msg.join('\n'*2) 
     75 
     76            return self._setErrorResponse(code=401, msg=response) 
    7277 
    7378 
     
    137142        if not self.isAuthenticated: 
    138143            log.info("PEPFilter: user is not authenticated") 
    139             return self.authZResult(environ, start_response) 
     144             
     145            # Set a 401 response for an authentication handler to capture 
     146            return self._setErrorResponse(code=401) 
    140147         
    141148        # Make a request object to pass to the PDP 
     
    153160                                                        'sessionManagerURI') 
    154161        request.resource[Resource.URI_NS] = resourceURI 
    155              
    156         response = self.pdp.evaluate(request) 
    157         permit = response.status == Response.DECISION_PERMIT 
    158         if permit: 
    159             log.info("PEPFilter: PDP using policy [%s] denied access for " 
    160                      "uri path [%s]", self.policyFilePath, resourceURI) 
     162 
     163         
     164        # Call the PDP 
     165        response = self.pdp.evaluate(request)         
     166         
     167        # Record the result in the user's session to enable later  
     168        # interrogation by the AuthZResultHandlerMiddleware 
     169        session['pepCtx'] = {'request': request, 'response': response, 
     170                             'timestamp': time()} 
     171        session.save() 
     172         
     173        if response.status == Response.DECISION_PERMIT: 
     174            log.debug("PEPFilter: PDP granted access for URI path [%s] " 
     175                      "using policy [%s]", resourceURI, self.policyFilePath) 
    161176             
    162177            return self._app(environ, start_response) 
    163178        else: 
    164             log.debug("PEPFilter: PDP using policy [%s] granted access for " 
    165                       "uri path [%s]", self.policyFilePath, resourceURI) 
    166             return self.authZResult(environ, start_response) 
    167  
    168     def _setAuthZResult(self, val): 
    169         if not isinstance(val, PEPResultHandlerMiddleware): 
    170             raise TypeError("Expecting AuthZResultMiddleware type; got %r" % 
    171                             val) 
    172         self._authZResult = val 
    173          
    174     def _getAuthZResult(self): 
    175         return getattr(self, '_authZResult', None) 
    176      
    177     authZResult = property(fget=_getAuthZResult, 
    178                            fset=_setAuthZResult, 
    179                            doc="middleware object to handle access denied " 
    180                                "response from PDP") 
    181      
     179            log.info("PEPFilter: PDP returned a status of [%s] " 
     180                     "denying access for URI path [%s] using policy [%s]",  
     181                     response.decisionValue2String[response.status], 
     182                     resourceURI, 
     183                     self.policyFilePath)  
     184             
     185            # Trigger AuthZResultHandlerMiddleware by setting a response  
     186            # with HTTP status code equal to the triggerStatus class attribute 
     187            # value 
     188            return self._setErrorResponse(code=int(PEPFilter.triggerStatus)) 
     189 
    182190    def _getMatchingTargets(self): 
    183191        """This method may only be called following __call__ as __call__ 
     
    214222            @type headers: list 
    215223            @param headers: HTTP response header content""" 
     224             
    216225            if status.startswith(PEPFilter.triggerStatus): 
    217                 log.info("Policy Enforcement Point found [%s] status for URI " 
    218                          "path [%s]: invoking access denied response", 
     226                log.info("PEPFilter: found [%s] status for URI path [%s]: " 
     227                         "invoking access denied response", 
    219228                         PEPFilter.triggerStatus, 
    220229                         environ['PATH_INFO']) 
     
    222231            else: 
    223232                # No match - it's publicly accessible 
    224                 log.debug("Policy Enforcement Point: the return status [%s] " 
    225                           "for this URI path [%s] didn't match the trigger " 
    226                           "status [%s]", 
     233                log.debug("PEPFilter: the return status [%s] for this URI " 
     234                          "path [%s] didn't match the trigger status [%s]", 
    227235                          status, 
    228236                          environ['PATH_INFO'], 
     
    272280         
    273281        app.add_checker(PEPFilter.id, pepInterceptFunc)                 
    274         pepFilter.authZResult = app.binding[PEPFilter.id] 
    275282         
    276283        super(AuthorizationMiddleware, self).__init__(app, 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/__init__.py

    r5254 r5280  
    12511251        """Do a HTTP 302 redirect 
    12521252         
    1253         @type start_response: builtin_function_or_method 
     1253        @type start_response: function 
    12541254        @param start_response: WSGI start response callable 
    12551255        @type url: basestring 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/authninterface/basic.py

    r5254 r5280  
    182182            self._client.environ = environ 
    183183            connectResp = self._client.connect(username, passphrase=password) 
    184             log.debug("Connected to Session Manager with: %s", connectResp) 
    185              
    186184            self.sessionId = connectResp[-1] 
    187              
     185            log.debug("Connected to Session Manager with session ID: %s",  
     186                      self.sessionId) 
     187 
    188188        except AuthNServiceInvalidCredentials, e: 
    189189            log.exception(e) 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/relyingparty/__init__.py

    r5154 r5280  
    124124        @type environ: dict 
    125125        @param environ: WSGI environment variables dictionary 
    126         @type start_response: builtin_function_or_method 
     126        @type start_response: function 
    127127        @param start_response: standard WSGI start response function 
    128128        ''' 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/ssl.py

    r4863 r5280  
    8686        elif not self.isSSLClientCertSet: 
    8787            log.error("No SSL Client path set for request to [%s]" % self.path) 
    88             return self._setErrorResponse(environ, start_response, 
     88            return self._setErrorResponse(start_response=start_response, 
    8989                                          msg='No client SSL Certificate set') 
    9090             
     
    9292            return self._setResponse(environ, start_response) 
    9393        else: 
    94             return self._setErrorResponse(environ, start_response) 
     94            return self._setErrorResponse(start_response=start_response) 
    9595             
    9696    def _setResponse(self,  
     
    100100                                 'SSLClientAuthNMiddleware'): 
    101101        return super(SSLClientAuthNMiddleware, self)._setResponse(environ,  
    102                                                        start_response, 
    103                                                        notFoundMsg=notFoundMsg) 
     102                                                    start_response, 
     103                                                    notFoundMsg=notFoundMsg) 
    104104 
    105105    def _setErrorResponse(self,  
    106                           environ,  
    107106                          start_response, 
    108107                          msg='Invalid SSL client certificate'): 
    109         return super(SSLClientAuthNMiddleware, self)._setResponse(environ,  
    110                                                    start_response, 
    111                                                    msg=msg, 
    112                                                    code=self.errorResponseCode) 
     108        return super(SSLClientAuthNMiddleware, self)._setResponse( 
     109                                                start_response=start_response, 
     110                                                msg=msg, 
     111                                                code=self.errorResponseCode) 
    113112 
    114113    def isValidClientCert(self, environ): 
Note: See TracChangeset for help on using the changeset viewer.