source: TI12-security/trunk/ndg_xacml/ndg/xacml/core/match.py @ 7351

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

Incomplete - task 2: XACML-Security Integration

  • important fix to ndg.xacml.core.rule.Rule.evaluate: return NotApplicable? where Target matches but Condition does not match
  • optimised ndg.xacml.core.functions.v1.at_least_one_member_of.AtLeastOneMemberOfBase? to use set and '&' operator for this function.
  • fix to ndg.xacml.core.functions.FunctionMap?.loadFunction to catch function namespace not recognised.
  • Property svn:keywords set to Id
Line 
1"""NDG Security Match type definition
2
3NERC DataGrid
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, UnsupportedStdFunctionError,
20                                      UnsupportedFunctionError)
21from ndg.xacml.core.context.exceptions import XacmlContextError
22
23
24class MatchBase(XacmlCoreBase):
25    """Base class for representation of SubjectMatch, ResourceMatch,
26    ActionMatch and EnvironmentMatch Target elements
27   
28    @cvar ELEMENT_LOCAL_NAME: XML Local Name of this element
29    @type ELEMENT_LOCAL_NAME: string
30   
31    @cvar MATCH_ID_ATTRIB_NAME: XML attribute name for match ID
32    @type MATCH_ID_ATTRIB_NAME: string
33   
34    @cvar ATTRIBUTE_VALUE_ELEMENT_LOCAL_NAME: XML Local Name of attribute value
35    child element
36    @type ATTRIBUTE_VALUE_ELEMENT_LOCAL_NAME: string
37
38    @ivar __attributeValue: attribute value associated with this match
39    @type __attributeValue: ndg.xacml.core.attributevalue.AttributeValue
40    @ivar __attributeDesignator: attribute designator - only a designator or
41    selector may be set for a given instance not both
42    @type __attributeDesignator: ndg.xacml.core.attributedesignator.AttributeDesignator
43    @ivar __attributeSelector: attribute selector - only a designator or
44    selector may be set for a given instance not both
45    @type __attributeSelector: ndg.xacml.core.attributeselector.AttributeSelector
46    @ivar __matchId: match identifier
47    @type __matchId: NoneType / basestring
48    @ivar __function: function to be applied
49    @type __function: ndg.xacml.core.functions.AbstractFunction derived type
50    @ivar __functionMap: function mapping object to map URNs to function class
51    implementations
52    @type __functionMap: ndg.xacml.core.functions.FunctionMap
53    @ivar __loadFunctionFromId: boolean determines whether or not to load
54    function classes for given function URN in functionId set property method
55    @type __loadFunctionFromId: bool
56    """
57    ELEMENT_LOCAL_NAME = None
58    MATCH_ID_ATTRIB_NAME = 'MatchId'
59    ATTRIBUTE_VALUE_ELEMENT_LOCAL_NAME = 'AttributeValue'
60
61    __slots__ = (
62        '__attributeValue', 
63        '__attributeDesignator', 
64        '__attributeSelector',
65        '__matchId',
66        '__function', 
67        '__functionMap',
68        '__loadFunctionFromId',
69    )
70   
71    def __init__(self):
72        """Initial attributes corresponding to the equivalent XACML schema type
73        and also create a function map to map functions from MatchIds
74        """
75        self.__attributeValue = None
76         
77        # Either/or in schema
78        self.__attributeDesignator = None
79        self.__attributeSelector = None
80       
81        self.__matchId = None
82       
83        self.__function = None
84        self.__functionMap = FunctionMap()
85        self.__loadFunctionFromId = True
86       
87    @property
88    def attributeValue(self):
89        """Match attribute value
90       
91        @return: attribute value
92        @rtype: ndg.xacml.core.attributevalue.Attribute"""
93        return self.__attributeValue
94   
95    @attributeValue.setter
96    def attributeValue(self, value):
97        """Set match attribute value.
98        @param value: attribute value
99        @type value: ndg.xacml.core.attributevalue.AttributeValue
100        @raise TypeError: incorrect type set
101        """
102        if not isinstance(value, AttributeValue):
103            raise TypeError('Expecting %r type for "matchId" '
104                            'attribute; got %r' % 
105                            (AttributeValue, type(value)))
106           
107        self.__attributeValue = value
108       
109    @property
110    def attributeDesignator(self):
111        """@return: attribute designator - only a designator or
112        selector may be set for a given instance not both
113        @rtype: ndg.xacml.core.attributedesignator.AttributeDesignator
114        """
115        return self.__attributeDesignator
116   
117    @attributeDesignator.setter
118    def attributeDesignator(self, value):
119        """Set match attribute designator.  Match may have an
120        attributeDesignator or an attributeSelector setting a designator DELETES
121        any attributeSelector previously set
122       
123        @param value: attribute selector - only a designator or
124        selector may be set for a given instance not both
125        @type value: ndg.xacml.core.attributeselector.AttributeSelector 
126        @raise TypeError: incorrect type for input value     
127        """
128        if not isinstance(value, AttributeDesignator):
129            raise TypeError('Expecting %r type for "attributeDesignator" '
130                            'attribute; got %r' % 
131                            (AttributeDesignator, type(value)))
132           
133        self.__attributeDesignator = value
134        self.__attributeSelector = None
135 
136    @property
137    def attributeSelector(self):
138        '''
139        @return: attribute selector
140        @rtype: ndg.xacml.core.attributeselector.AttributeSelector
141        '''
142        return self.__attributeSelector
143   
144    @attributeSelector.setter
145    def attributeSelector(self, value):
146        """Set match attribute selector.  Match may have an
147        attributeDesignator or an attributeSelector setting a selector DELETES
148        any attributeDesignator previously set
149       
150        @param value: attribute selector
151        @type value: ndg.xacml.core.attributeselector.AttributeSelector
152        """
153        if not isinstance(value, AttributeSelector):
154            raise TypeError('Expecting %r type for "matchId" '
155                            'attribute; got %r' % 
156                            (AttributeSelector, type(value)))
157           
158        self.__attributeSelector = value
159        self.__attributeDesignator = None
160                       
161    def _getMatchId(self):
162        """Match identifier for match function
163        @return: match identifier
164        @rtype: NoneType / basestring
165        """
166        return self.__matchId
167
168    def _setMatchId(self, value):
169        """Match identifier for match function
170        @param value: match identifier
171        @type value: basestring
172        @raise TypeError: if incorrect input type
173        """
174        if not isinstance(value, basestring):
175            raise TypeError('Expecting string type for "matchId" '
176                            'attribute; got %r' % type(value))
177           
178        self.__matchId = value
179       
180        # Also retrieve function for this match ID if a map has been set
181        if self.__loadFunctionFromId:
182            self.setFunctionFromMap(self.__functionMap)   
183
184    matchId = property(_getMatchId, _setMatchId, None, 
185                       "Match identifier for match function")
186     
187    @property
188    def loadFunctionFromId(self):
189        """Set to False to stop the functionId property set method automatically
190        trying to load the corresponding function for the given functionId
191
192        @return: boolean determines whether or not to load
193        function classes for given function URN in functionId set property
194        method
195        @rtype: bool
196        """
197        return self.__loadFunctionFromId
198   
199    @loadFunctionFromId.setter
200    def loadFunctionFromId(self, value):
201        """
202        @param value: boolean determines whether or not to load
203        function classes for given function URN in functionId set property
204        method
205        @type value: bool
206        """
207        if not isinstance(value, bool):
208            raise TypeError('Expecting %r type for "loadFunctionFromId" '
209                            'attribute; got %r' % (bool, type(value)))
210           
211        self.__loadFunctionFromId = value
212       
213    def setFunctionFromMap(self, functionMap):
214        """Set the function from a function map - a dictionary of function ID to
215        function mappings.  The function is looked up based on the "functionId"
216        attribute.  This method is automatically called when the functionId set
217        property method is invoked.  To switch off this behaviour set
218       
219        loadFunctionFromId = False
220       
221        @param functionMap: mapping of function URNs to function classes
222        @type functionMap: dict like object
223        @raise UnsupportedStdFunctionError: policy references a function type
224        which is in the XACML spec. but is not supported by this implementation
225        @raise UnsupportedFunctionError: policy references a function type which
226        is not supported by this implementation
227        """
228        if self.matchId is None:
229            raise AttributeError('"functionId" attribute must be set in order '
230                                 'to retrieve the required function')
231           
232        # Get function class for this <Apply> statement         
233        functionClass = functionMap.get(self.matchId)
234        if functionClass is NotImplemented:
235            raise UnsupportedStdFunctionError('No match function class '
236                                              'implemented for MatchId="%s"' % 
237                                              self.matchId)
238        elif functionClass is None:
239            raise UnsupportedFunctionError('<Apply> function namespace %r is '
240                                           'not recognised' % 
241                                           self.matchId) 
242           
243        self.__function = functionClass()
244   
245    @property
246    def functionMap(self):
247        """functionMap object for PDP to retrieve functions from given XACML
248        function URNs
249        @return: function mapping object to map URNs to function
250        class implementations
251        @rtype: ndg.xacml.core.functions.FunctionMap
252        """
253        return self.__functionMap
254   
255    @functionMap.setter
256    def functionMap(self, value):
257        '''functionMap object for PDP to retrieve functions from given XACML
258        function URNs
259       
260        @param value: function mapping object to map URNs to function class
261        implementations
262        @type value: ndg.xacml.core.functions.FunctionMap
263        @raise TypeError: raise if input value is incorrect type
264        '''
265        if not isinstance(value, FunctionMap):
266            raise TypeError('Expecting %r derived type for "functionMap" '
267                            'input; got %r instead' % (FunctionMap, 
268                                                       type(value)))
269        self.__functionMap = value
270         
271    @property 
272    def function(self):
273        """Function for this <Apply> instance
274        @return: function to be applied
275        @rtype: ndg.xacml.core.functions.AbstractFunction derived type
276        """
277        return self.__function
278       
279    def evaluate(self, context):
280        """Evaluate the match object against the relevant element in the request
281        context
282       
283        @param context: the request context
284        @type context: ndg.xacml.core.context.request.Request
285        @return: match status
286        @rtype: bool
287        """
288       
289        # Create a match function based on the presence or absence of an
290        # AttributeDesignator or AttributeSelector
291        if self.attributeDesignator is not None:
292            requestAttributeValues = self.attributeDesignator.evaluate(context)
293           
294        elif self.attributeSelector is not None:
295            # Nb. Evaluation is not currently supported.  This will require that
296            # the request provide a reference to it's XML representation and an
297            # abstraction of the XML parser for executing XPath searches into
298            # that representation
299            requestAttributeValues = self.attributeSelector.evaluate(context)
300        else:
301            raise XacmlContextError('No attribute designator or selector set '
302                                    'for Target Match element %r with MatchId '
303                                    '= %r and attributeValue = %r' %
304                                    (self.__class__.ELEMENT_LOCAL_NAME,
305                                     self.matchId,
306                                     self.attributeValue))
307           
308        # Iterate through each attribute in the request in turn matching it
309        # against the target using the generated _attributeMatch function
310        #
311        # Any Match element NOT matching will result in an overall status of
312        # no match.
313        #
314        # Continue iterating through the whole list even if a False status
315        # is found.  The other attributes need to be checked in case an
316        # error occurs.  In this case the top-level PDP exception handling
317        # block will catch it and set an overall decision of INDETERMINATE
318        attrMatchStatusValues = [False]*len(requestAttributeValues)
319        matchFunction = self.function
320        matchAttributeValue = self.attributeValue
321       
322        for i, requestAttributeValue in enumerate(requestAttributeValues):
323           
324            attrMatchStatusValues[i] = matchFunction.evaluate(
325                                                         matchAttributeValue,
326                                                         requestAttributeValue)
327            if attrMatchStatusValues[i] == True:
328                if log.getEffectiveLevel() <= logging.DEBUG:
329                    log.debug('Target attribute value %r matches request '
330                              'attribute value %r matches using match '
331                              'function Id %r',
332                              matchAttributeValue,
333                              requestAttributeValue,
334                              self.matchId)
335       
336        # Need check for len() because all([]) yields True!           
337        matchStatus = (len(attrMatchStatusValues) > 0 and 
338                       all(attrMatchStatusValues))
339       
340        return matchStatus
341   
342   
343class SubjectMatch(MatchBase):
344    "Subject Match Type"
345    ELEMENT_LOCAL_NAME = 'SubjectMatch'
346    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'SubjectAttributeDesignator'   
347   
348   
349class ResourceMatch(MatchBase):
350    "Resource Match"
351    ELEMENT_LOCAL_NAME = 'ResourceMatch'
352    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'ResourceAttributeDesignator'
353   
354   
355class ActionMatch(MatchBase):
356    "Action match"
357    ELEMENT_LOCAL_NAME = 'ActionMatch'
358    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'ActionAttributeDesignator'   
359   
360   
361class EnvironmentMatch(MatchBase):
362    "Environment Match"
363    ELEMENT_LOCAL_NAME = 'EnvironmentMatch'
364    ATTRIBUTE_DESIGNATOR_ELEMENT_LOCAL_NAME = 'EnvironmentAttributeDesignator'
Note: See TracBrowser for help on using the repository browser.