Changeset 5330


Ignore:
Timestamp:
22/05/09 10:11:16 (10 years ago)
Author:
pjkersha
Message:

Completed AuthorizationMiddleware? unit tests ndg.security.test.unit.wsgi.authz:

  • Test 8, 'test08AccessDeniedForAdminQueryArg' tries out the use case for a URI which can display additional content for users with admin privileges. The caller needs to be able to display the correct content according to whether the user has admin rights or not:
    1. the caller invokes /securedURI?admin=1
    2. if the user has admin, rights the PDP will grant access and the PEP will deliver this URI.
    3. if the user doesn't have admin rights, a special overloaded PEP result handler class detects that access was denied for the admin URI and redirects the user to a modified URI subtracting the admin flag. The application code can then deliver the appropriate content minus admin privileges.
Location:
TI12-security/trunk/python
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/utils/classfactory.py

    r5322 r5330  
    1919        Exception.__init__(self, msg) 
    2020 
    21 def importClass(moduleName, className=None): 
     21def importClass(moduleName, className=None, objectType=None): 
    2222    '''Import a class from a string module name and class name. 
    2323     
     
    4141 
    4242    importedClass = getattr(module, className) 
     43 
     44    # Check class inherits from a base class 
     45    if objectType and not issubclass(importedClass, objectType): 
     46        raise TypeError("Specified class %s must be derived from %s; got %s" % 
     47                        (className, objectType, importedClass)) 
    4348     
    4449    log.info('Imported "%s" class from module, "%s"', className, moduleName) 
     
    9297             
    9398            # Import module name specified in properties file 
    94             importedClass = importClass(moduleName, className=className) 
     99            importedClass = importClass(moduleName,  
     100                                        className=className, 
     101                                        objectType=objectType) 
    95102        finally: 
    96103            # revert back to original sys path, if necessary 
     
    104111                  (moduleName, e.__class__, e)) 
    105112        raise  
    106  
    107     # Check class inherits from a base class 
    108     if objectType and not issubclass(importedClass, objectType): 
    109         raise ClassFactoryError("Specified class %s must be derived from %s" % 
    110                                 (className, objectType)) 
    111113 
    112114    # Instantiate class 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/__init__.py

    r5290 r5330  
    266266         
    267267         
    268     def _redirect(self, url, start_response=None): 
     268    def redirect(self, url, start_response=None): 
    269269        """Do a HTTP 302 redirect 
    270270         
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authn.py

    r5317 r5330  
    162162                redirectURI += '?' + return2URIQueryArg 
    163163                 
    164         return self._redirect(redirectURI) 
     164        return self.redirect(redirectURI) 
    165165         
    166166    @classmethod 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authz.py

    r5329 r5330  
    1212log = logging.getLogger(__name__) 
    1313from time import time 
    14 import httplib 
     14from urlparse import urlunsplit 
    1515 
    1616from ndg.security.server.wsgi import NDGSecurityPathFilter 
     
    3333    implemented in the AuthorizationHandler.  See below ... 
    3434     
    35     TODO: possible refactor to incorporate user role registration interface. 
    36     For ESG collaboration, the scenario following access denied is to g""" 
     35    This class can be overridden to define custom behaviour for the access 
     36    denied response e.g. include an interface to enable users to register for 
     37    the dataset from which they have been denied access.  See  
     38    AuthorizationMiddleware pepResultHandler keyword 
     39    """ 
    3740    propertyDefaults = { 
    3841        'sessionKey': 'beaker.session.ndg.security' 
     
    6467            return self._setErrorResponse(code=401) 
    6568        else: 
    66             # TODO: refactor to include a call to another interface - possibly 
    67             # - another WSGI app to set a user friendly output and include  
    68             # links to enable the user to register for new access privileges 
    69              
    7069            # Get response message from PDP recorded by PEP 
    71             msg = getattr(self.session.get('pepCtx', {}).get('response'), 
    72                           'message', '') 
     70            pepCtx = self.session.get('pepCtx', {}) 
     71            pdpResponse = pepCtx.get('response') 
     72            msg = getattr(pdpResponse, 'message', '') 
    7373                 
    7474            response = \ 
     
    140140                                       'environ' % self.sessionKey) 
    141141             
    142         resourceURI = self.pathInfo 
     142        queryString = environ.get('QUERY_STRING', '') 
     143        resourceURI = urlunsplit(('', '', self.pathInfo, queryString, '')) 
    143144         
    144145        # Check for a secured resource 
    145         matchingTargets = self._getMatchingTargets() 
     146        matchingTargets = self._getMatchingTargets(resourceURI) 
    146147        targetMatch = len(matchingTargets) > 0 
    147148        if not targetMatch: 
     
    209210            return self._setErrorResponse(code=int(PEPFilter.triggerStatus)) 
    210211 
    211     def _getMatchingTargets(self): 
     212    def _getMatchingTargets(self, resourceURI): 
    212213        """This method may only be called following __call__ as __call__ 
    213214        updates the pathInfo property 
    214215         
     216        @type resourceURI: basestring 
     217        @param resourceURI: the URI of the requested resource 
    215218        @rtype: list 
    216219        @return: return list of policy target objects matching the current  
    217220        path  
    218221        """ 
    219         resourceURI = self.pathInfo 
    220222        matchingTargets = [target for target in self.policy.targets  
    221223                           if target.regEx.match(resourceURI) is not None] 
     
    304306        app = MultiHandler(pepFilter) 
    305307         
    306         pepResultHandlerClassName = app_conf.pop(prefix+"pep.resultHandler",  
     308        pepResultHandlerClassName = app_conf.pop(prefix+"pepResultHandler",  
    307309                                                 None)  
    308310        if pepResultHandlerClassName is None: 
    309311            pepResultHandler = PEPResultHandlerMiddleware 
    310312        else: 
    311             pepResultHandler = importClass(pepResultHandlerClassName) 
    312             if not isinstance(pepResultHandler, PEPResultHandlerMiddleware): 
    313                 raise AuthorizationMiddlewareConfigError("Expecting " 
    314                     "PEPResultHandlerMiddleware derived class for " 
    315                     "pepResultHandler setting; got %s" % pepResultHandler) 
     313            pepResultHandler = importClass(pepResultHandlerClassName, 
     314                                        objectType=PEPResultHandlerMiddleware) 
    316315             
    317316        app.add_method(PEPFilter.id, 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/wsgi/authz/policy.xml

    r5329 r5330  
    44     
    55    <Target> 
    6         <URIPattern>^/test_accessGrantedToSecuredURI*$</URIPattern> 
     6        <URIPattern>^/test_accessGrantedToSecuredURI$</URIPattern> 
    77        <Attributes> 
    88            <Attribute>urn:siteA:security:authz:1.0:attr:staff</Attribute> 
     
    2222        </AttributeAuthority> 
    2323    </Target> 
     24    <Target> 
     25        <!--  
     26            Special extra target puts additional restriction in place if 
     27            admin query argument is set 
     28        --> 
     29        <URIPattern>^/test_accessGrantedToSecuredURI\?admin=1$</URIPattern> 
     30        <Attributes> 
     31            <Attribute>urn:siteA:security:authz:1.0:attr:admin</Attribute> 
     32        </Attributes> 
     33        <AttributeAuthority> 
     34            <uri>http://localhost:5000/AttributeAuthority</uri> 
     35        </AttributeAuthority> 
     36    </Target> 
    2437</Policy> 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/wsgi/authz/test.ini

    r5329 r5330  
    2222prefix = authz. 
    2323policy.filePath = %(here)s/policy.xml 
     24 
     25authz.pepResultHandler = ndg.security.test.unit.wsgi.authz.test_authz.RedirectFollowingAccessDenied 
    2426 
    2527# Settings for Policy Information Point used by the Policy Decision Point to 
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/unit/wsgi/authz/test_authz.py

    r5329 r5330  
    1515import unittest 
    1616import os 
    17 import sys 
    18 import getpass 
    19 import re 
    20 import base64 
    21 import urllib2 
     17from urlparse import urlunsplit 
    2218 
    2319from os.path import expandvars as xpdVars 
     
    2824import paste.fixture 
    2925from paste.deploy import loadapp 
    30 from ndg.security.server.wsgi.authz import PEPFilterConfigError 
    31  
     26from ndg.security.server.wsgi import NDGSecurityMiddlewareBase 
     27from ndg.security.server.wsgi.authz import PEPFilterConfigError, \ 
     28    PEPResultHandlerMiddleware 
     29from ndg.security.common.authz.msi import Response 
     30 
     31class RedirectFollowingAccessDenied(PEPResultHandlerMiddleware): 
     32     
     33    @NDGSecurityMiddlewareBase.initCall 
     34    def __call__(self, environ, start_response): 
     35         
     36        queryString = environ.get('QUERY_STRING', '') 
     37        if 'admin=1' in queryString: 
     38            # User has been rejected access to a URI requiring admin rights, 
     39            # try redirect to the same URI minus the admin query arg, this 
     40            # request will pass because admin rights aren't needed 
     41            queryArgs = queryString.split('&') 
     42            queryList = [arg for arg in queryArgs if arg != 'admin=1'] 
     43            editedQuery = '&'.join(queryList) 
     44            redirectURI = urlunsplit(('', '', self.pathInfo, editedQuery, '')) 
     45            return self.redirect(redirectURI) 
     46        else: 
     47            return super(RedirectFollowingAccessDenied, self).__call__( 
     48                                                            environ, 
     49                                                            start_response) 
     50         
    3251class TestAuthZMiddleware(object): 
    3352    '''Test Application for the Authentication handler to protect''' 
     
    145164                                extra_environ=extra_environ, 
    146165                                status=403) 
    147         self.assert_( 
    148                 "Insufficient privileges to access the resource" in response) 
     166        self.failIf( 
     167            "Insufficient privileges to access the resource" not in response) 
    149168        print response 
    150169         
     
    159178                                extra_environ=extra_environ, 
    160179                                status=200) 
     180        self.failIf(TestAuthZMiddleware.response not in response) 
     181        print response 
     182 
     183    def test07AccessGrantedForSecuredURI(self): 
     184         
     185        # User is logged in and has credentials for access to a URI secured 
     186        # by the policy file 
     187        extra_environ={'beaker.session.ndg.security': 
     188                       BeakerSessionStub(username='testuser')} 
     189         
     190        response = self.app.get('/test_accessGrantedToSecuredURI', 
     191                                extra_environ=extra_environ, 
     192                                status=200) 
    161193        self.assert_(TestAuthZMiddleware.response in response) 
     194        print response 
     195 
     196    def test08AccessDeniedForAdminQueryArg(self): 
     197         
     198        # User is logged in but doesn't have the required credentials for  
     199        # access 
     200        extra_environ={'beaker.session.ndg.security': 
     201                       BeakerSessionStub(username='testuser')} 
     202         
     203        # Try this URI with the query arg admin=1.  This will be picked up 
     204        # by the policy as a request requiring admin rights.  The request is 
     205        # denied as the user doesn't have these rights but this then calls 
     206        # into play the PEP result handler defined in this module, 
     207        # RedirectFollowingAccessDenied.  This class reinvokes the request 
     208        # but without the admin query argument.  Access is then granted for 
     209        # the redirected request 
     210        response = self.app.get('/test_accessGrantedToSecuredURI', 
     211                                params={'admin': 1}, 
     212                                extra_environ=extra_environ, 
     213                                status=302) 
     214        try: 
     215            redirectResponse = response.follow(extra_environ=extra_environ) 
     216        except paste.fixture.AppError, e: 
     217            self.failIf(TestAuthZMiddleware.response not in response) 
    162218        print response 
    163219 
Note: See TracChangeset for help on using the changeset viewer.