Changeset 6776 for TI12-security/trunk


Ignore:
Timestamp:
25/03/10 16:41:14 (10 years ago)
Author:
pjkersha
Message:

Moved PDPInterface into separate module. Extensive additions to unit tests. PDP class now in pdp module in context package.

Location:
TI12-security/trunk/NDG_XACML/ndg/xacml
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/NDG_XACML/ndg/xacml/core/context/__init__.py

    r6771 r6776  
    1212__revision__ = "$Id: $" 
    1313from ndg.xacml.utils import TypedList 
     14from ndg.xacml.core.attribute import Attribute 
     15 
    1416 
    1517class XacmlContextBase(object): 
     
    3133    def __init__(self): 
    3234        self.__attributes = TypedList(Attribute) 
     35         
     36    @property 
     37    def attributes(self): 
     38        """XACML Context subject attributes""" 
     39        return self.__attributes 
    3340     
  • TI12-security/trunk/NDG_XACML/ndg/xacml/core/context/handler.py

    r6771 r6776  
    1111__revision__ = "$Id: $" 
    1212from abc import ABCMeta, abstractmethod 
     13from ndg.xacml.core.context.pdpinterface import PDPInterface 
    1314 
    1415 
    15 class PEPInterface: 
     16class PEPInterface(object): 
    1617    """Policy Enforcement Point Interface""" 
    1718    __metaclass__ = ABCMeta 
     
    3940        
    4041        
    41 class AbstractContextHandler(object): 
     42class AbstractContextHandler(PEPInterface): 
    4243    """Context Handler Abstract Base class""" 
    4344    __metaclass__ = ABCMeta 
     
    6566        if not isinstance(value, PDPInterface): 
    6667            raise TypeError('Expecting %r derived type for "pdp" attribute; ' 
    67                             'got %r' % (PDPInterface, type(pdp)) 
     68                            'got %r' % (PDPInterface, type(pdp))) 
    6869         
    6970        self.__pdp = value 
  • TI12-security/trunk/NDG_XACML/ndg/xacml/core/context/pdp.py

    r6775 r6776  
    1010__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1111__revision__ = "$Id: $" 
    12 from abc import ABCMeta, abstractmethod 
     12import logging 
     13log = logging.getLogger(__name__) 
     14 
     15import traceback 
     16 
     17from ndg.xacml.core.context.pdpinterface import PDPInterface 
     18from ndg.xacml.core.policy import Policy 
    1319from ndg.xacml.core.context.request import Request 
    14  
    15  
    16 class PDPInterface: 
    17     __metaclass__ = ABCmeta 
    18      
     20from ndg.xacml.core.context.response import Response 
     21from ndg.xacml.core.context.result import Result, Decision 
     22from ndg.xacml.parsers import AbstractReader 
     23                             
     24         
     25class PDP(PDPInterface): 
     26    """A XACML Policy Decision Point implementation.  It supports the use of a  
     27    single policy but not policy sets 
     28    """ 
     29    __slots__ = ('__policy',) 
     30    TARGET_CHILD_ATTRS = ('subjects', 'resources', 'actions', 'environments') 
     31     
     32    def __init__(self, policy=None): 
     33        """ 
     34        @param policy: policy object for PDP to use to apply access control 
     35        decisions, may be omitted. 
     36        @type policy: ndg.xacml.core.policy.Policy / None 
     37        """ 
     38        self.__policy = None 
     39        if policy is not None: 
     40            self.policy = policy 
     41         
    1942    @classmethod 
    20     def __subclasshook__(cls, C): 
    21         """Derived class must implement __call__""" 
    22         if cls is PDPInterface: 
    23             if any("evaluate" in B.__dict__ for B in C.__mro__): 
    24                 return True 
    25              
    26         return NotImplemented 
    27  
    28     @abstractmethod 
     43    def fromPolicy(cls, source, reader): 
     44        """Create a new PDP instance with a given policy 
     45        @param source: source for policy 
     46        @type source: type (dependent on the reader set, it could be for example 
     47        a file path string, file object, XML element instance) 
     48        @param reader: the reader instance to use to read this policy 
     49        @type reader: ndg.xacml.parsers.AbstractReader derived type 
     50        """ 
     51        if not isinstance(reader, AbstractReader): 
     52            raise TypeError('Expecting %r derived type for "reader" input; got ' 
     53                            '%r instead' % (AbstractReader, type(reader))) 
     54             
     55        pdp = cls() 
     56        pdp.policy = reader.parse(source) 
     57        return pdp 
     58     
     59    @property 
     60    def policy(self): 
     61        """policy object for PDP to use to apply access control decisions""" 
     62        return self.__policy 
     63     
     64    @policy.setter 
     65    def policy(self, value): 
     66        '''policy object for PDP to use to apply access control decisions''' 
     67        if not isinstance(value, Policy): 
     68            raise TypeError('Expecting %r derived type for "policy" input; got ' 
     69                            '%r instead' % (Policy, type(value))) 
     70        self.__policy = value 
     71                     
    2972    def evaluate(self, request): 
    30         '''evaluate the input request and return an access control decision 
    31         in the returned response 
    32          
    33         @param request: XACML context request 
     73        """Make an access control decision for the given request based on the 
     74        policy set 
     75         
     76        @param request: XACML request context 
    3477        @type request: ndg.xacml.core.context.request.Request 
    35         @return: XACML context response 
     78        @return: XACML response instance 
    3679        @rtype: ndg.xacml.core.context.response.Response 
    37         ''' 
     80        """ 
     81        response = Response 
     82        result = Result() 
     83        response.results.append(result) 
     84        result.decision = Decision.NOT_APPLICABLE 
     85         
    3886        if not isinstance(request, Request): 
    39             raise TypeError('Expecting %r type for input request; got %r ' 
    40                             'instead' % (Request, type(request)) 
    41                              
    42  
     87            log.error('Expecting %r derived type for "reader" input; got ' 
     88                      '%r instead' % Request, type(request)) 
     89            result.decision = Decision.INDETERMINATE 
     90            return response 
     91             
     92        # Exception block around all rule processing in order to set 
     93        # INDETERMINATE response from any exceptions raised 
     94        try: 
     95            log.debug('Checking policy target for match...') 
     96             
     97            if not self.matchTarget(self.policy.target, request): 
     98                log.debug('No match for policy target setting Decision=%r', 
     99                          Decision.NOT_APPLICABLE_STR) 
     100                 
     101                result.decision = Decision.NOT_APPLICABLE 
     102                return response 
     103             
     104            # Check rules 
     105            for rule in self.policy.rules: 
     106                log.debug('Checking policy rule %r for match...', rule.id) 
     107                if not self.matchTarget(rule.target, request): 
     108                    log.debug('No match to request context for target in rule ' 
     109                              '%r', rule.id) 
     110                    continue          
     111        except: 
     112            log.error('Exception raised evaluating request context, returning ' 
     113                      'Decision=%r:%s',  
     114                      Decision.INDETERMINATE_STR,  
     115                      traceback.format_exc()) 
     116            result.decision = Decision.INDETERMINATE 
     117             
     118        return response 
     119             
     120    def matchTarget(self, target, request): 
     121        """Generic method to match a <Target> element to the request context 
     122         
     123        @param target: XACML target element 
     124        @type target: ndg.xacml.core.target.Target 
     125        @param request: XACML request context 
     126        @type request: ndg.xacml.core.context.request.Request 
     127        @return: True if request context matches the given target,  
     128        False otherwise 
     129        @rtype: bool 
     130        """ 
     131        if target is None: 
     132            log.debug('No target set so no match with request context') 
     133            return False 
     134         
     135        # From section 5.5 of the XACML 2.0 Core Spec: 
     136        # 
     137        # For the parent of the <Target> element to be applicable to the  
     138        # decision request, there MUST be at least one positive match between  
     139        # each section of the <Target> element and the corresponding section of  
     140        # the <xacml-context:Request> element.        
     141        for i in self.__class__.TARGET_CHILD_ATTRS: 
     142            for targetChild in getattr(target, i): 
     143                for requestChild in getattr(request, i): 
     144                    if self.matchTargetChild(targetChild, requestChild): 
     145                        return True 
     146  
     147        return False 
     148     
     149    @classmethod 
     150    def matchTargetChild(cls, targetChild, requestChild): 
     151        """Match a child (Subject, Resource, Action or Environment) from the  
     152        request context with a given target's child 
     153         
     154        @param targetChild: Target Subject, Resource, Action or Environment 
     155        object 
     156        @type targetChild: ndg.xacml.core.TargetChildBase 
     157        @param requestChild: Request Subject, Resource, Action or Environment 
     158        object 
     159        @type requestChild: ndg.xacml.core.context.RequestChildBase 
     160        @return: True if request context matches something in the target 
     161        @rtype: bool 
     162        @raise NotImplementedError: AttributeSelector processing is not  
     163        currently supported.  If an AttributeSelector is found in the policy, 
     164        this exception will be raised. 
     165        """ 
     166        if targetChild is None: 
     167            # Default if target child is not set is to match all children 
     168            return True 
     169         
     170        for childMatch in targetChild.matches: 
     171            attributeValue = childMatch.attributeValue 
     172             
     173            # Create a match function based on the presence or absence of an 
     174            # AttributeDesignator or AttributeSelector 
     175            if childMatch.attributeDesignator is not None: 
     176                attributeId = childMatch.attributeDesignator.attributeId 
     177                dataType = childMatch.attributeDesignator.dataType 
     178                 
     179                _attributeMatch = lambda requestChildAttribute: ( 
     180                    requestChildAttribute.attributeValue == attributeValue and 
     181                    requestChildAttribute.attributeId == attributeId and 
     182                    requestChildAttribute.dataType == dataType  
     183                ) 
     184                 
     185            elif childMatch.attributeSelector is not None: 
     186                # Nb. This will require that the request provide a reference to 
     187                # it's XML representation and an abstraction of the XML parser 
     188                # for executing XPath searches into that representation 
     189                raise NotImplementedError('This PDP implementation does not ' 
     190                                          'support <AttributeSelector> ' 
     191                                          'elements') 
     192            else: 
     193                _attributeMatch = lambda requestChildAttribute: ( 
     194                    requestChildAttribute.attributeValue == attributeValue 
     195                ) 
     196                 
     197            for attribute in requestChild.attributes: 
     198                if _attributeMatch(attribute): 
     199                    return True 
     200                     
     201        return False 
     202 
  • TI12-security/trunk/NDG_XACML/ndg/xacml/core/context/request.py

    r6766 r6776  
    3434    def subjects(self): 
    3535        """Request subjects""" 
    36         return self.__subject 
     36        return self.__subjects 
    3737         
    3838    @property 
  • TI12-security/trunk/NDG_XACML/ndg/xacml/core/context/response.py

    r6770 r6776  
    1515from ndg.xacml.utils import TypedList 
    1616from ndg.xacml.core.context import XacmlContextBase 
    17 from ndg.xacml.core.context import Result 
     17from ndg.xacml.core.context.result import Result 
    1818 
    1919 
  • TI12-security/trunk/NDG_XACML/ndg/xacml/test/test_xacml.py

    r6775 r6776  
    2020from ndg.xacml.parsers.etree.factory import ReaderFactory 
    2121 
     22from ndg.xacml.core.context.pdpinterface import PDPInterface 
     23from ndg.xacml.core.context.pdp import PDP 
     24from ndg.xacml.core.context.handler import AbstractContextHandler 
    2225from ndg.xacml.core.attribute import Attribute 
     26from ndg.xacml.core.attributevalue import AttributeValue 
    2327from ndg.xacml.core.context.request import Request 
    2428from ndg.xacml.core.context.response import Response 
     
    2933 
    3034THIS_DIR = path.dirname(__file__) 
     35XACML_NDGTEST1_FILENAME = "ndg1.xml" 
     36XACML_NDGTEST1_FILEPATH = path.join(THIS_DIR, XACML_NDGTEST1_FILENAME) 
    3137 
    3238 
     
    4046    XACML_TEST4_FILENAME = "rule4.xml" 
    4147    XACML_TEST4_FILEPATH = path.join(THIS_DIR, XACML_TEST4_FILENAME) 
    42     XACML_NDGTEST1_FILENAME = "ndg1.xml" 
    43     XACML_NDGTEST1_FILEPATH = path.join(THIS_DIR, XACML_NDGTEST1_FILENAME) 
    4448    
    4549    def test01ETreeParseRule1Policy(self): 
     
    261265        # resources for NDG 
    262266        PolicyReader = ReaderFactory.getReader(Policy) 
    263         policy = PolicyReader.parse(XACMLPolicyTestCase.XACML_NDGTEST1_FILEPATH) 
    264         self.assert_(policy) 
    265          
    266          
    267 class PDP(PDPInterface): 
    268     """A XACML Policy Decision Point implementation.  It supports the use of a  
    269     single policy but not policy sets""" 
    270     __slots__ = ('__policy',) 
    271      
    272     def __init__(self, policy=None): 
    273         """ 
    274         @param policy: policy object for PDP to use to apply access control 
    275         decisions, may be omitted. 
    276         @type policy: ndg.xacml.core.policy.Policy / None 
    277         """ 
    278         self.__policy = None 
    279         if policy is not None: 
    280             self.policy = policy 
    281          
    282     @classmethod 
    283     def fromPolicy(cls, source, reader): 
    284         """Create a new PDP instance with a given policy 
    285         @param source: source for policy 
    286         @type source: type (dependent on the reader set, it could be for example 
    287         a file path string, file object, XML element instance) 
    288         @param reader: the reader instance to use to read this policy 
    289         @type reader: ndg.xacml.parsers.AbstractReader derived type 
    290         """ 
    291         if not isinstance(reader, AbstractReader): 
    292             raise TypeError('Expecting %r derived type for "reader" input; got ' 
    293                             '%r instead' % (AbstractReader, type(reader))) 
    294              
    295         pdp = cls() 
    296         pdp.policy = reader.parse(source) 
    297         return policy 
    298      
    299     @property 
    300     def policy(self): 
    301         """policy object for PDP to use to apply access control decisions""" 
    302         return self.__policy 
    303      
    304     @policy.setter 
    305     def policy(self, value): 
    306         '''policy object for PDP to use to apply access control decisions''' 
    307         if not isinstance(value, Policy): 
    308             raise TypeError('Expecting %r derived type for "policy" input; got ' 
    309                             '%r instead' % (Policy, type(value))) 
    310         self.__policy = value 
    311                      
    312     def evaluate(self, request): 
    313         """Make an access control decision for the given request based on the 
    314         policy set 
    315          
    316         @param request: XACML request context 
    317         @type request: ndg.xacml.core.context.request.Request 
    318         @return: XACML response instance 
    319         @rtype: ndg.xacml.core.context.response.Response 
    320         """ 
    321         response = Response 
    322         result = Result() 
    323         response.results.append(result) 
    324         result.decision = Decision.NOT_APPLICABLE 
    325          
    326         if not isinstance(request, Request): 
    327              log.error('Expecting %r derived type for "reader" input; got ' 
    328                        '%r instead' % Request, type(request)) 
    329              result.decision = Decision.INDETERMINATE 
    330              return response 
    331              
    332         # Exception block around all rule processing in order to set 
    333         # INDETERMINATE response from any exceptions raised 
    334         try:  
    335                   
    336             # Check policy target for match 
    337             log.debug('Checking policy target for match...') 
    338              
    339             if not self.matchTarget(self.policy.target, request): 
    340                 log.debug('No match for policy target setting Decision=%r', 
    341                           Decision.NOT_APPLICABLE_STR) 
    342                  
    343                 result.decision = Decision.NOT_APPLICABLE 
    344                 return response 
    345              
    346             # Check rules 
    347             for rule in self.policy.rules: 
    348                 log.debug('Checking policy rule %r for match...', rule.id) 
    349                 if not self.matchTarget(rule.target, request): 
    350                     log.debug('No match to request context for target in rule ' 
    351                               '%r', rule.id) 
    352                     continue          
    353         except: 
    354             log.error('Exception raised evaluating request context, returning ' 
    355                       'Decision=%r:%s',  
    356                       Decision.INDETERMINATE_STR,  
    357                       traceback.format_exc()) 
    358             result.decision = Decision.INDETERMINATE 
    359              
    360         return response 
    361              
    362      
    363     def matchTarget(self, target, request): 
    364         if target is None: 
    365             log.debug('No target set so no match with request context') 
    366             return False 
    367          
    368         # From section 5.5 of the XACML 2.0 Core Spec: 
    369         # 
    370         # For the parent of the <Target> element to be applicable to the  
    371         # decision request, there MUST be at least one positive match between  
    372         # each section of the <Target> element and the corresponding section of  
    373         # the <xacml-context:Request> element.        
    374         for i in ('subjects', 'resources', 'actions', 'environments'): 
    375             for targetChild in getattr(target, i): 
    376                 for requestChild in getattr(request, i): 
    377                     if self.matchTargetChild(targetChild, requestChild): 
    378                         return True 
    379                  
    380          
    381                  
    382         return False 
    383      
    384     @classmethod 
    385     def matchTargetChild(cls, targetChild, requestChild): 
    386         """Match a child (Subject, Resource, Action or Environment) from the  
    387         request context with a given target's child 
    388          
    389         @param targetChild: Target Subject, Resource, Action or Environment 
    390         object 
    391         @type targetChild: ndg.xacml.core.TargetChildBase 
    392         @param requestChild: Request Subject, Resource, Action or Environment 
    393         object 
    394         @type requestChild: ndg.xacml.core.context.RequestChildBase 
    395         @return: True if request context matches something in the target 
    396         @rtype: bool 
    397         @raise NotImplementedError: AttributeSelector processing is not  
    398         currently supported.  If an AttributeSelector is found in the policy, 
    399         this exception will be raised. 
    400         """ 
    401         if targetChild is None: 
    402             # Default if target child is not set is to match all children 
    403             return True 
    404          
    405         for childMatch in targetChild.matches: 
    406             attributeValue = childMatch.attributeValue 
    407              
    408             # Create a match function based on the presence or absence of an 
    409             # AttributeDesignator or AttributeSelector 
    410             if childMatch.attributeDesignator is not None: 
    411                 attributeId = childMatch.attributeDesignator.attributeId 
    412                 dataType = childMatch.attributeDesignator.dataType 
    413                  
    414                 _attributeMatch = lambda requestChildAttribute: ( 
    415                     requestChildAttribute.attributeValue == attributeValue and 
    416                     requestChildAttribute.attributeId == attributeId and 
    417                     requestChildAttribute.dataType == dataType  
    418                 ) 
    419                  
    420             elif childMatch.attributeSelector is not None: 
    421                 # Nb. This will require that the request provide a reference to 
    422                 # it's XML representation and an abstraction of the XML parser 
    423                 # for executing XPath searches into that representation 
    424                 raise NotImplementedError('This PDP implementation does not ' 
    425                                           'support <AttributeSelector> ' 
    426                                           'elements') 
    427             else: 
    428                 _attributeMatch = lambda requestChildAttribute: ( 
    429                     requestChildAttribute.attributeValue == attributeValue 
    430                 ) 
    431                  
    432             for attribute in requestChild.attributes: 
    433                 if _attributeMatch(attribute): 
    434                     return True 
    435                      
    436         return False 
    437      
     267        policy = PolicyReader.parse(XACML_NDGTEST1_FILEPATH) 
     268        self.assert_(policy)     
    438269                 
    439270class TestContextHandler(AbstractContextHandler): 
     
    463294    """Test PDP, PAP, PIP and Context handler""" 
    464295     
    465     def test01CreateRequest(self): 
     296    def _createRequestCtx(self): 
    466297        request = Request() 
    467298         
     
    473304        subjectAttribute.dataType = \ 
    474305                            "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name" 
    475         subjectAttribute.attributeValue = 'bs@simpsons.com' 
     306        subjectAttribute.attributeValue = AttributeValue() 
     307        subjectAttribute.attributeValue.value = 'bs@simpsons.com' 
    476308         
    477309        request.subjects.append(subject) 
     
    499331        requestAttribute.attributeValue = 'read' 
    500332         
     333        return request 
     334     
     335    def test01CreateRequest(self): 
     336        requestCtx = self._createRequestCtx() 
     337        self.assert_(requestCtx) 
     338         
    501339    def test02CreateResponse(self): 
    502340        response = Response() 
     
    505343        result.decision = Decision.value = Decision.NOT_APPLICABLE 
    506344         
    507     def test03CreateContextHandler(self): 
    508  
     345    def test03AbstractCtxHandler(self): 
     346        self.assertRaises(AbstractContextHandler(), NotImplementedError) 
     347         
     348    def test04CreateCtxHandler(self): 
     349        ctxHandler = TestContextHandler() 
     350         
     351    def test04PDPInterface(self): 
     352        self.assertRaises(PDPInterface(), NotImplementedError) 
     353         
     354    def test05CreatePDP(self): 
     355        pdp = PDP() 
     356        self.assert_(pdp) 
     357         
     358    def _createPDPfromPolicy(self): 
     359        pdp = PDP.fromPolicy(XACML_NDGTEST1_FILEPATH) 
     360        return pdp 
     361         
     362    def test06CreatePDPfromPolicy(self): 
     363        pdp = self._createPDPfromPolicy() 
     364        self.assert_(pdp) 
     365         
     366    def test07EvaluatePDP(self): 
     367        request = self._createRequestCtx() 
     368        response = pdp.evaluate(request) 
     369        self.assert_(response) 
     370         
    509371         
    510372 
Note: See TracChangeset for help on using the changeset viewer.