Changeset 5285


Ignore:
Timestamp:
14/05/09 11:51:21 (10 years ago)
Author:
pjkersha
Message:
  • Important fixes to PDP.evaluate to ensure all targets yield permit status for an access control decision.
  • additional debug info for WSGI middleware
  • new OpenID Provider AXInterfaceReloginRequired - allows for case where a session is stale
  • ndg.security.test.unit - put unit tests in this package in parallel to the existing integration test package.
Location:
TI12-security/trunk/python
Files:
2 added
6 edited

Legend:

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

    r5280 r5285  
    314314         
    315315        sessionId = subject[Subject.SESSIONID_NS] 
     316         
     317        log.debug("PIP: received attribute query: %r", attributeQuery) 
     318         
    316319        attributeCertificate = self._getAttributeCertificate( 
    317320                                        attributeAuthorityURI, 
     
    395398        ''' 
    396399         
     400        log.debug("PIP._getAttributeCertificateFromSessionManager ...") 
     401         
    397402        try: 
    398403            # Create Session Manager client - if a file path was set, setting 
     
    444449             
    445450    def _getAttributeCertificateFromAttributeAuthority(self, 
    446                                                    attributeAuthorityURI, 
    447                                                    username): 
     451                                                       attributeAuthorityURI, 
     452                                                       username): 
    448453        '''Retrieve an Attribute Certificate direct from an Attribute 
    449454        Authority.  This method is invoked if no session ID or Session  
     
    458463        ''' 
    459464         
     465        log.debug("PIP._getAttributeCertificateFromAttributeAuthority ...") 
     466        
    460467        try: 
    461468            # Create Attribute Authority client - if a file path was set,  
     
    506513        matchingTargets = [target for target in self.policy.targets  
    507514                           if target.regEx.match(resourceURI) is not None] 
    508          
     515        numMatchingTargets = len(matchingTargets) 
     516        if numMatchingTargets == 0: 
     517            log.debug("PDP.evaluate: granting access - no targets matched " 
     518                      "the resource URI path [%s]",  
     519                      resourceURI) 
     520            return Response(status=Response.DECISION_PERMIT) 
     521         
     522        # Iterate through matching targets checking for user access 
    509523        knownAttributeAuthorityURIs = [] 
    510524        request.subject[Subject.ROLES_NS] = [] 
     525        permitForAllTargets = [Response.DECISION_PERMIT]*numMatchingTargets 
     526         
     527        # Keep a look-up of the decisions for each target 
     528        status = [] 
     529         
    511530        for matchingTarget in matchingTargets: 
    512531             
     
    522541                                        matchingTarget.attributeAuthorityURI 
    523542                 
     543                # Exit from function returning indeterminate status if a  
     544                # problem occurs here 
    524545                try: 
    525546                    attributeResponse=self.pip.attributeQuery(attributeQuery) 
    526547                     
    527548                except SubjectRetrievalError, e: 
     549                    # i.e. a defined exception within the scope of this 
     550                    # module 
    528551                    log.exception(e) 
    529552                    return Response(Response.DECISION_INDETERMINATE, 
     
    538561                                        matchingTarget.attributeAuthorityURI) 
    539562                 
     563                # Accumulate attributes retrieved from multiple attribute 
     564                # authorities 
    540565                request.subject[Subject.ROLES_NS] += attributeResponse[ 
    541566                                                            Subject.ROLES_NS] 
    542567                
    543         # Match the subject's attributes against the target 
    544         for attr in matchingTarget.attributes: 
    545             if attr in request.subject[Subject.ROLES_NS]: 
    546                 return Response(Response.DECISION_PERMIT) 
    547              
    548         return Response(Response.DECISION_DENY, 
    549                         message="Insufficient privileges to access the " 
    550                                 "resource") 
    551      
    552  
    553          
     568            # Match the subject's attributes against the target 
     569            # One of any rule - at least one of the subject's attributes 
     570            # must match one of the attributes restricting access to the 
     571            # resource. 
     572            status.append(PDP._match(matchingTarget.attributes,  
     573                                     request.subject[Subject.ROLES_NS])) 
     574             
     575        # All targets must yield permit status for access to be granted 
     576        if status == permitForAllTargets: 
     577            return Response(Response.DECISION_PERMIT) 
     578        else:     
     579            return Response(Response.DECISION_DENY, 
     580                            message="Insufficient privileges to access the " 
     581                                    "resource") 
     582         
     583    @staticmethod 
     584    def _match(resourceAttr, subjectRoleAttr): 
     585        """Helper method to iterate over user and resource attributes 
     586        If one at least one match is found, a permit response is returned 
     587        """ 
     588        for attr in resourceAttr: 
     589            if attr in subjectRoleAttr: 
     590                return Response.DECISION_PERMIT 
     591             
     592        return Response.DECISION_DENY 
     593 
     594         
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authn.py

    r5282 r5285  
    2020    WSGISessionManagerClient 
    2121 
     22#class HTTPBasicAuthNMiddleware(NDGSecurityMiddlewareBase): 
     23#    '''HTTP Basic Authentication Middleware 
     24#     
     25#    TODO: implement authN interface and username/password retrieval from 
     26#    HTTP header.''' 
     27#     
     28#    def __init__(self, app, app_conf, **local_conf): 
     29# 
     30#        super(HTTPBasicAuthentication).__init__(self,  
     31#                                                app,  
     32#                                                app_conf,  
     33#                                                **local_conf) 
     34#         
     35#    def __call__(self, environ, start_response): 
     36#        """Authenticate based HTTP header elements as specified by the HTTP 
     37#        Basic Authentication spec.""" 
     38#        log.debug("HTTPBasicAuthNMiddleware.__call__ ...") 
     39#         
     40#        try: 
     41#            self.authNInterface.logon(username, password) 
     42#                 
     43#        except Exception, e: 
     44#            return self._errorResponse(code=401) 
     45#        else: 
     46#            return self._app(environ, start_response) 
     47             
    2248class HTTPBasicAuthentication(object): 
    23     '''Authkit based HTTP Basic Authentication''' 
     49    '''Authkit based HTTP Basic Authentication.   __call__ defines a  
     50    validation function to fit with the pattern for the AuthKit interface 
     51    ''' 
     52     
    2453    def __init__(self): 
    2554        self._userIn = UserIn([]) 
     
    82111    def __call__(self, environ, start_response): 
    83112        '''Invoke redirect if user is not authenticated''' 
     113         
     114        log.debug("AuthenticationRedirectMiddleware.__call__ ...") 
    84115         
    85116        if not self.isAuthenticated: 
     
    176207    @NDGSecurityMiddlewareBase.initCall 
    177208    def __call__(self, environ, start_response): 
     209         
     210        log.debug("SessionHandlerMiddleware.__call__ ...") 
     211         
    178212        session = environ[self.sessionKey] 
    179213         
    180214        if self.signoutPath and self.pathInfo == self.signoutPath: 
    181             log.debug("SessionHandlerMiddleware: caught signout path [%s]", 
     215            log.debug("SessionHandlerMiddleware: caught sign out path [%s]", 
    182216                      self.signoutPath) 
    183217             
     
    191225                     
    192226            else: 
    193                 log.error('No referer set for redirect following logout') 
     227                log.error('No referrer set for redirect following logout') 
    194228                _start_response = start_response 
    195229                 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authz/__init__.py

    r5280 r5285  
    4747         
    4848        super(PEPResultHandlerMiddleware, self).__init__(app, 
    49                                                            global_conf, 
    50                                                            prefix=prefix, 
    51                                                            **app_conf) 
     49                                                         global_conf, 
     50                                                         prefix=prefix, 
     51                                                         **app_conf) 
    5252                
    5353    @NDGSecurityMiddlewareBase.initCall 
    5454    def __call__(self, environ, start_response): 
     55         
     56        log.debug("PEPResultHandlerMiddleware.__call__ ...") 
     57         
    5558        self.session = self.environ.get(self.sessionKey) 
    5659        if not self.isAuthenticated: 
     
    6164        else: 
    6265            # TODO: refactor to include a call to another interface - possibly 
    63             # - another WSGI to set a user friendly output and include links 
    64             # to enable the user to register for new access privileges 
     66            # - another WSGI app to set a user friendly output and include  
     67            # links to enable the user to register for new access privileges 
    6568             
    6669            # Get response message from PDP recorded by PEP 
     
    123126    @NDGSecurityMiddlewareBase.initCall 
    124127    def __call__(self, environ, start_response): 
     128         
     129        log.debug("PEPFilter.__call__ ...") 
     130         
    125131        session = environ[self.sessionKey] 
    126132        resourceURI = self.pathInfo 
     
    130136        targetMatch = len(matchingTargets) > 0 
    131137        if not targetMatch: 
    132             log.debug("PEPFilter: no matching URI path target was found in " 
    133                       "the policy for URI path [%s]", resourceURI) 
     138            log.info("PEPFilter: granting access - no matching URI path " 
     139                     "target was found in the policy for URI path [%s]",  
     140                     resourceURI) 
    134141            return self._app(environ, start_response)        
    135142 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/__init__.py

    r5280 r5285  
    3030from ndg.security.common.utils.classfactory import instantiateClass 
    3131from ndg.security.server.wsgi import NDGSecurityMiddlewareBase         
    32 from ndg.security.server.wsgi.openid.provider.axinterface import AXInterface 
     32from ndg.security.server.wsgi.openid.provider.axinterface import AXInterface,\ 
     33    MissingRequiredAttrs, AXInterfaceReloginRequired 
    3334 
    3435 
     
    5859    """User has provided incorrect username/password.  Raise from logon""" 
    5960    userMsg = ("Invalid username / password provided.  Please try again.  If " 
    60                "the problem persists please contact your system administrator") 
     61               "the problem persists please contact your system " 
     62               "administrator") 
    6163    errorMsg = "Invalid username/password provided" 
    6264 
     
    175177     
    176178 
    177 from ndg.security.server.wsgi.openid.provider.axinterface import \ 
    178     MissingRequiredAttrs 
    179      
     179# Aliases to AXInterface exception types     
    180180class OpenIDProviderMissingRequiredAXAttrs(MissingRequiredAttrs):  
    181181    """Raise if a Relying Party *requires* one or more attributes via 
    182     the AX interface but this OpenID Provider cannot return them.  This doesn't 
    183     apply to attributes that are optional""" 
    184     
     182    the AX interface but this OpenID Provider cannot return them.  This  
     183    doesn't apply to attributes that are optional""" 
     184 
     185class OpenIDProviderReloginRequired(AXInterfaceReloginRequired): 
     186    pass 
     187 
     188# end aliases to AXInterface exception types 
     189 
    185190class OpenIDProviderMiddlewareError(Exception): 
    186191    """OpenID Provider WSGI Middleware Error""" 
     
    10991104        try: 
    11001105            self.axResponse(ax_req, ax_resp, self._authN) 
    1101              
     1106         
    11021107        except OpenIDProviderMissingRequiredAXAttrs, e: 
    11031108            log.error("OpenID Provider is unable to set the AX attributes " 
    11041109                      "required by the Relying Party's request: %s" % e) 
     1110            raise 
     1111         
     1112        except OpenIDProviderReloginRequired, e: 
     1113            log.exception(e) 
    11051114            raise 
    11061115         
     
    11721181                        'configured to provide.  Please report this fault to ' 
    11731182                        'your site administrator.') 
     1183                    return response 
     1184                     
     1185                except OpenIDProviderReloginRequired, e: 
     1186                    response = self._render.errorPage(environ, start_response, 
     1187                        'An error occurred setting additional parameters ' 
     1188                        'required by the site requesting your ID.  Please ' 
     1189                        'try logging in again.') 
    11741190                    return response 
    11751191                     
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/axinterface/__init__.py

    r5189 r5285  
    1313    """Base class for Attribute Exchange Interface Errors""" 
    1414 
    15 class AXInterfaceConfigError(Exception): 
     15class AXInterfaceConfigError(AXInterfaceError): 
    1616    """Attribute Exchange Interface configuration error""" 
    1717 
     
    2020    requested attributes that this OpenID Provider cannot or is unable to  
    2121    release""" 
     22 
     23class AXInterfaceReloginRequired(AXInterfaceError): 
     24    """Raise from AXInterface.__call__ if re-login is required""" 
    2225     
    2326class AXInterface(object): 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/provider/axinterface/sessionmanager.py

    r5254 r5285  
    8787                                            authNInterface.__class__.__name__) 
    8888                 
     89            # Check for uninitialised session 
     90            if not authNInterface.sessionId: 
     91                raise MissingRequiredAttrs("The Session Manager session ID " 
     92                                           "is not set to a valid session") 
     93                 
     94            # TODO: Check for a stale session ID - would require config params 
     95            # to set-up a Session Manager client 
     96                 
    8997            log.debug("Adding AX parameter %s=%s ...", self.sessionIdTypeURI, 
    9098                                                    authNInterface.sessionId) 
Note: See TracChangeset for help on using the changeset viewer.