source: TI12-security/trunk/NDG_XACML/ndg/xacml/core/match.py @ 7072

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDG_XACML/ndg/xacml/core/match.py@7072
Revision 7072, 10.9 KB checked in by pjkersha, 9 years ago (diff)

Incomplete - task 2: XACML-Security Integration

  • Major cleanup of function factories for efficiency. Only the required factories and function classes are loaded and any loaded classes are cached for future calls. All unit tests pass.
  • Property svn:keywords set to Id
Line 
1"""NDG Security Match type definition
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "25/02/10"
7__copyright__ = "(C) 2010 Science and Technology Facilities Council"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = "$Id$"
12import logging
13log = logging.getLogger(__name__)
14
15from ndg.xacml.core import XacmlCoreBase
16from ndg.xacml.core.attributevalue import AttributeValue
17from ndg.xacml.core.attributedesignator import AttributeDesignator
18from ndg.xacml.core.attributeselector import AttributeSelector
19from ndg.xacml.core.functions import FunctionMap
20from ndg.xacml.core.context.exceptions import XacmlContextError
21from ndg.xacml.core.exceptions import (UnsupportedStdFunctionError,
22                                       UnsupportedFunctionError)
23
24
25class MatchBase(XacmlCoreBase):
26    """Base class for representation of SubjectMatch, ResourceMatch,
27    ActionMatch and EnvironmentMatch Target elements
28    """
29    ELEMENT_LOCAL_NAME = None
30    MATCH_ID_ATTRIB_NAME = 'MatchId'
31    ATTRIBUTE_VALUE_ELEMENT_LOCAL_NAME = 'AttributeValue'
32
33    __slots__ = (
34        '__attributeValue', 
35        '__attributeDesignator', 
36        '__attributeSelector',
37        '__matchId',
38        '__function', 
39        '__functionMap',
40        '__loadFunctionFromId',
41    )
42   
43    def __init__(self):
44        """Initial attributes corresponding to the equivalent XACML schema type
45        and also create a function map to map functions from MatchIds
46        """
47        self.__attributeValue = None
48         
49        # Either/or in schema
50        self.__attributeDesignator = None
51        self.__attributeSelector = None
52       
53        self.__matchId = None
54       
55        self.__function = None
56        self.__functionMap = FunctionMap()
57        self.__loadFunctionFromId = True
58       
59    @property
60    def attributeValue(self):
61        """Match attribute value"""
62        return self.__attributeValue
63   
64    @attributeValue.setter
65    def attributeValue(self, value):
66        """Set match attribute value.
67        """
68        if not isinstance(value, AttributeValue):
69            raise TypeError('Expecting %r type for "matchId" '
70                            'attribute; got %r' % 
71                            (AttributeValue, type(value)))
72           
73        self.__attributeValue = value
74       
75    @property
76    def attributeDesignator(self):
77        return self.__attributeDesignator
78   
79    @attributeDesignator.setter
80    def attributeDesignator(self, value):
81        """Set match attribute designator.  Match may have an
82        attributeDesignator or an attributeSelector setting a designator DELETES
83        any attributeSelector previously set
84        """
85        if not isinstance(value, AttributeDesignator):
86            raise TypeError('Expecting %r type for "attributeDesignator" '
87                            'attribute; got %r' % 
88                            (AttributeDesignator, type(value)))
89           
90        self.__attributeDesignator = value
91        self.__attributeSelector = None
92 
93    @property
94    def attributeSelector(self):
95        return self.__attributeSelector
96   
97    @attributeSelector.setter
98    def attributeSelector(self, value):
99        """Set match attribute selector.  Match may have an
100        attributeDesignator or an attributeSelector setting a selector DELETES
101        any attributeDesignator previously set
102        """
103        if not isinstance(value, AttributeSelector):
104            raise TypeError('Expecting %r type for "matchId" '
105                            'attribute; got %r' % 
106                            (AttributeSelector, type(value)))
107           
108        self.__attributeSelector = value
109        self.__attributeDesignator = None
110                       
111    def _getMatchId(self):
112        """Match identifier for match function"""
113        return self.__matchId
114
115    def _setMatchId(self, value):
116        """Match identifier for match function"""
117        if not isinstance(value, basestring):
118            raise TypeError('Expecting string type for "matchId" '
119                            'attribute; got %r' % type(value))
120           
121        self.__matchId = value
122       
123        # Also retrieve function for this match ID if a map has been set
124        if self.__loadFunctionFromId:
125            self.setFunctionFromMap(self.__functionMap)   
126
127    matchId = property(_getMatchId, _setMatchId, None, 
128                       "Match identifier for match function")
129     
130    @property
131    def loadFunctionFromId(self):
132        """Set to False to stop the functionId property set method automatically
133        trying to load the corresponding function for the given functionId""" 
134        return self.__loadFunctionFromId
135   
136    @loadFunctionFromId.setter
137    def loadFunctionFromId(self, value):
138        if not isinstance(value, bool):
139            raise TypeError('Expecting %r type for "loadFunctionFromId" '
140                            'attribute; got %r' % (bool, type(value)))
141           
142        self.__loadFunctionFromId = value
143       
144    def setFunctionFromMap(self, functionMap):
145        """Set the function from a function map - a dictionary of function ID to
146        function mappings.  The function is looked up based on the "functionId"
147        attribute.  This method is automatically called when the functionId set
148        property method is invoked.  To switch off this behaviour set
149       
150        loadFunctionFromId = False
151       
152        @raise UnsupportedStdFunctionError: policy references a function type
153        which is in the XACML spec. but is not supported by this implementation
154        @raise UnsupportedFunctionError: policy references a function type which
155        is not supported by this implementation
156        """
157        if self.matchId is None:
158            raise AttributeError('"functionId" attribute must be set in order '
159                                 'to retrieve the required function')
160           
161        # Get function class for this <Apply> statement         
162        functionClass = functionMap.get(self.matchId)
163        if functionClass is NotImplemented:
164            raise UnsupportedStdFunctionError('No match function class '
165                                              'implemented for MatchId="%s"' % 
166                                              self.matchId)
167        elif functionClass is None:
168            raise UnsupportedFunctionError('<Apply> function namespace %r is '
169                                           'not recognised' % 
170                                           self.matchId) 
171           
172        self.__function = functionClass()
173   
174    @property
175    def functionMap(self):
176        """functionMap object for PDP to retrieve functions from given XACML
177        function URNs"""
178        return self.__functionMap
179   
180    @functionMap.setter
181    def functionMap(self, value):
182        '''functionMap object for PDP to retrieve functions from given XACML
183        function URNs'''
184        if not isinstance(value, FunctionMap):
185            raise TypeError('Expecting %r derived type for "functionMap" '
186                            'input; got %r instead' % (FunctionMap, 
187                                                       type(value)))
188        self.__functionMap = value
189         
190    @property 
191    def function(self):
192        "Function for this <Apply> instance"
193        return self.__function
194       
195    def evaluate(self, context):
196        """Evaluate the match object against the relevant element in the request
197        context
198        """
199       
200        # Create a match function based on the presence or absence of an
201        # AttributeDesignator or AttributeSelector
202        if self.attributeDesignator is not None:
203            requestAttributeValues = self.attributeDesignator.evaluate(context)
204           
205        elif self.attributeSelector is not None:
206            # Nb. Evaluation is not currently supported.  This will require that
207            # the request provide a reference to it's XML representation and an
208            # abstraction of the XML parser for executing XPath searches into
209            # that representation
210            requestAttributeValues = self.attributeSelector.evaluate(context)
211        else:
212            raise XacmlContextError('No attribute designator or selector set '
213                                    'for Target Match element %r with MatchId '
214                                    '= %r and attributeValue = %r' %
215                                    (self.__class__.ELEMENT_LOCAL_NAME,
216                                     self.matchId,
217                                     self.attributeValue))
218           
219        # Iterate through each attribute in the request in turn matching it
220        # against the target using the generated _attributeMatch function
221        #
222        # Any Match element NOT matching will result in an overall status of
223        # no match.
224        #
225        # Continue iterating through the whole list even if a False status
226        # is found.  The other attributes need to be checked in case an
227        # error occurs.  In this case the top-level PDP exception handling
228        # block will catch it and set an overall decision of INDETERMINATE
229        attrMatchStatusValues = [False]*len(requestAttributeValues)
230        matchFunction = self.function
231        matchAttributeValue = self.attributeValue
232       
233        for i, requestAttributeValue in enumerate(requestAttributeValues):
234           
235            attrMatchStatusValues[i] = matchFunction.evaluate(
236                                                         matchAttributeValue,
237                                                         requestAttributeValue)
238            if attrMatchStatusValues[i] == True:
239                if log.getEffectiveLevel() <= logging.DEBUG:
240                    log.debug('Target attribute value %r matches request '
241                              'attribute value %r matches using match '
242                              'function Id %r',
243                              matchAttributeValue,
244                              requestAttributeValue,
245                              self.matchId)
246       
247        # Need check for len() because any([]) yields True!           
248        matchStatus = (len(attrMatchStatusValues) > 0 and 
249                       all(attrMatchStatusValues))
250       
251        return matchStatus
252   
253   
254class SubjectMatch(MatchBase):
255    "Subject Match Type"
256    ELEMENT_LOCAL_NAME = 'SubjectMatch'
257    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'SubjectAttributeDesignator'   
258   
259   
260class ResourceMatch(MatchBase):
261    "Resource Match"
262    ELEMENT_LOCAL_NAME = 'ResourceMatch'
263    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'ResourceAttributeDesignator'
264   
265   
266class ActionMatch(MatchBase):
267    "Action match"
268    ELEMENT_LOCAL_NAME = 'ActionMatch'
269    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'ActionAttributeDesignator'   
270   
271   
272class EnvironmentMatch(MatchBase):
273    "Environment Match"
274    ELEMENT_LOCAL_NAME = 'EnvironmentMatch'
275    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'EnvironmentAttributeDesignator'
Note: See TracBrowser for help on using the repository browser.