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

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

Modified apply and match classes to use a FunctionMap? class singleton to enable easy addition of new function types.

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