source: TI12-security/trunk/ndg_xacml/ndg/xacml/core/policy.py @ 7109

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

Incomplete - task 2: XACML-Security Integration

  • updating epydoc ready for release.
  • Property svn:keywords set to Id
Line 
1"""NDG Security Policy type definition
2
3NERC DataGrid
4"""
5__author__ = "P J Kershaw"
6__date__ = "24/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 traceback
13import logging
14log = logging.getLogger(__name__)
15
16from ndg.xacml.utils import TypedList
17from ndg.xacml.parsers import AbstractReaderFactory, AbstractReader
18from ndg.xacml.core import XacmlCoreBase
19from ndg.xacml.core.policydefaults import PolicyDefaults
20from ndg.xacml.core.target import Target
21from ndg.xacml.core.rule import Rule
22from ndg.xacml.core.obligation import Obligation
23from ndg.xacml.core.rule_combining_alg import (RuleCombiningAlgClassFactory,
24                                               RuleCombiningAlgInterface)
25from ndg.xacml.core.exceptions import (UnsupportedStdFunctionError,
26                                       UnsupportedFunctionError)
27
28# Evaluation of a request context
29from ndg.xacml.core.context.response import Response
30from ndg.xacml.core.context.result import Result, Decision, StatusCode
31from ndg.xacml.core.context.exceptions import XacmlContextError
32
33
34class PolicyParseError(Exception):
35    """Error reading policy attributes from file"""
36
37
38class InvalidPolicyXmlNsError(PolicyParseError):
39    """Invalid XML namespace for policy document"""
40
41
42class Policy(XacmlCoreBase):
43    """XACML Policy
44   
45    @cvar DEFAULT_XACML_VERSION: default is 2.0
46    @type DEFAULT_XACML_VERSION: string
47    @cvar ELEMENT_LOCAL_NAME: XML local name for this element
48    @type ELEMENT_LOCAL_NAME: string
49    @cvar POLICY_ID_ATTRIB_NAME: policy id XML attribute name
50    @type POLICY_ID_ATTRIB_NAME: string
51    @cvar RULE_COMBINING_ALG_ID_ATTRIB_NAME: rule combining algorithm id XML
52    attribute name
53    @type RULE_COMBINING_ALG_ID_ATTRIB_NAME: string
54    @cvar VERSION_ATTRIB_NAME: version XML attribute name
55    @type VERSION_ATTRIB_NAME: string
56    @cvar DESCRIPTION_LOCAL_NAME: description XML element local name
57    @type DESCRIPTION_LOCAL_NAME: string
58    @cvar POLICY_DEFAULTS_LOCAL_NAME: policy defaults XML element local name
59    @type POLICY_DEFAULTS_LOCAL_NAME: string
60    @cvar COMBINER_PARAMETERS_LOCAL_NAME: combiner parameter XML element local
61    name
62    @type COMBINER_PARAMETERS_LOCAL_NAME: string
63    @cvar RULE_COMBINER_PARAMETERS_LOCAL_NAME: rule combiner parameter XML
64    element local name
65    @type RULE_COMBINER_PARAMETERS_LOCAL_NAME: string
66    @cvar OBLIGATIONS_LOCAL_NAME: obligations XML element local name
67    @type OBLIGATIONS_LOCAL_NAME: string
68   
69    @ivar __policyId: policy id
70    @type __policyId: NoneType / basestring
71    @ivar __version: policy version
72    @type __version: NoneType / basestring
73    @ivar __ruleCombiningAlgId: rule combining algorithm ID
74    @type __ruleCombiningAlgId: NoneType / basestring
75    @ivar __description: policy decription text
76    @type __description: NoneType / basestring
77    @ivar __target: target element
78    @type __target: NoneType / ndg.xacml.core.target.Target
79    @ivar __attr: list of rules
80    @type __attr: ndg.xacml.utils.TypedList
81    @ivar __obligations: obligations
82    @type __obligations: ndg.xacml.utils.TypedList
83    @ivar __ruleCombiningAlgFactory: rule combining algorithm factory
84    @type __ruleCombiningAlgFactory: ndg.xacml.core.rule_combining_alg.RuleCombiningAlgClassFactory
85    @ivar __ruleCombiningAlg: rule combining algorithm
86    @type __ruleCombiningAlg: NoneType / ndg.xacml.core.rule_combining_alg.RuleCombiningAlgInterface
87    """ 
88    DEFAULT_XACML_VERSION = "2.0"
89    ELEMENT_LOCAL_NAME = "Policy"
90    POLICY_ID_ATTRIB_NAME = "PolicyId"
91    RULE_COMBINING_ALG_ID_ATTRIB_NAME = "RuleCombiningAlgId"
92    VERSION_ATTRIB_NAME = "Version"
93
94    DESCRIPTION_LOCAL_NAME = "Description"
95    POLICY_DEFAULTS_LOCAL_NAME = "PolicyDefaults"
96    COMBINER_PARAMETERS_LOCAL_NAME = "CombinerParameters"
97    RULE_COMBINER_PARAMETERS_LOCAL_NAME = "RuleCombinerParameters"
98    OBLIGATIONS_LOCAL_NAME = "Obligations"
99   
100    __slots__ = (
101        '__policyId',
102        '__version',
103        '__ruleCombiningAlgId',
104        '__description',
105        '__policyDefaults',
106        '__target',
107        '__attr',
108        '__obligations',
109        '__ruleCombiningAlgFactory',
110        '__ruleCombiningAlg'
111    )
112   
113    def __init__(self, ruleCombiningAlgFactory=None):
114        """Customise rule combining behaviour by passing in a custom combining
115        algorithm factory.  This is invoked when the combining algorithm Id
116        property is set in order to create the corresponding combining algorithm
117        object
118       
119        @param ruleCombiningAlgFactory: factory object for return a rule
120        combining algorithm class for a given URI.  Defaults to
121        @type ruleCombiningAlgFactory: NoneType / defaults to
122        ndg.xacml.core.rule_combining_alg.RuleCombiningAlgClassFactory
123        """
124        super(Policy, self).__init__()
125        self.__policyId = None
126        self.__version = None
127        self.__ruleCombiningAlgId = None
128        self.__description = None
129        self.__target = None
130        self.__policyDefaults = None
131       
132        # Attr should eventually allow a choice of Rule, CombinerParameter,
133        # RuleCombinerParameter and VariableDefinition but only Rule type is
134        # currently supported
135        self.__attr = TypedList(Rule)
136       
137        self.__obligations = TypedList(Obligation)
138       
139        self.__ruleCombiningAlgFactory = None
140        if ruleCombiningAlgFactory is None:
141            self.ruleCombiningAlgFactory = RuleCombiningAlgClassFactory()
142        else:
143            self.ruleCombiningAlgFactory = ruleCombiningAlgFactory
144
145        self.__ruleCombiningAlg = None
146
147    def _getRuleCombiningAlgFactory(self):
148        """
149        @return: rule combining algorithm factory
150        @rtype: NoneType / ndg.xacml.core.rule_combining_alg.RuleCombiningAlgClassFactory
151        """
152        return self.__ruleCombiningAlgFactory
153
154    def _setRuleCombiningAlgFactory(self, value):
155        """
156        @param value: rule combining algorithm factory
157        @type value: ndg.xacml.core.rule_combining_alg.RuleCombiningAlgClassFactory
158        @raise TypeError: incorrect input type
159        """
160        if not isinstance(value, RuleCombiningAlgClassFactory):
161            raise TypeError('Expecting %r derived type for '
162                            '"ruleCombiningAlgFactory" attibute; got %r' % 
163                            (RuleCombiningAlgClassFactory, type(value)))
164           
165        self.__ruleCombiningAlgFactory = value
166
167    ruleCombiningAlgFactory = property(_getRuleCombiningAlgFactory, 
168                                       _setRuleCombiningAlgFactory, 
169                                       doc="Rule Combining Algorithm Factory")
170   
171    @property
172    def ruleCombiningAlg(self):
173        """Rule Combining algorithm
174        @return: rule combining algorithm class instance
175        @rtype: ndg.xacml.core.rule_combining_alg.RuleCombiningAlgInterface
176        derived type
177        """
178        return self.__ruleCombiningAlg
179   
180    @classmethod
181    def fromSource(cls, source, readerFactory):
182        """Create a new policy from the input source parsing it using a
183        reader from the required reader factory e.g. ETreeReaderFactory to use
184        ElementTree based parsing
185       
186        @param source: source from which to read the policy - file path,
187        file object, XML node or other dependent on the reader factory selected
188        @type source: string, file, XML node type
189        @param readerFactory: factory class returns reader class used to parse
190        the policy
191        @type readerFactory: ndg.xacml.parsers.AbstractReaderFactory
192        @return: new policy instance
193        @rtype: ndg.xacml.core.policy.Policy
194        """
195        if not issubclass(readerFactory, AbstractReaderFactory):
196            raise TypeError('Expecting %r derived class for reader factory '
197                            'method; got %r' % (AbstractReaderFactory, 
198                                                readerFactory))
199           
200        reader = readerFactory.getReader(cls)
201        if not issubclass(reader, AbstractReader):
202            raise TypeError('Expecting %r derived class for reader class; '
203                            'got %r' % (AbstractReader, reader))
204           
205        return reader.parse(source)
206       
207    def _getPolicyId(self):
208        '''
209        @return: policy id
210        @rtype: NoneType / basestring
211        '''
212        return self.__policyId
213
214    def _setPolicyId(self, value):
215        '''@param value: policy id
216        @type value: basestring
217        @raise TypeError: incorrect input type
218        '''
219        if not isinstance(value, basestring):
220            raise TypeError('Expecting string type for "policyId" '
221                            'attribute; got %r' % type(value))
222           
223        self.__policyId = value
224
225    policyId = property(_getPolicyId, _setPolicyId, None, "Policy Id")
226
227    def _getVersion(self):
228        '''@return: policy version
229        @rtype: NoneType / basestring
230        '''
231        return self.__version
232
233    def _setVersion(self, value):
234        '''@param value: policy version
235        @type value: basestring
236        @raise TypeError: incorrect input type
237        '''
238        if not isinstance(value, basestring):
239            raise TypeError('Expecting string type for "version" '
240                            'attribute; got %r' % type(value))
241           
242        self.__version = value
243
244    version = property(_getVersion, _setVersion, None, "Policy Version")
245
246    def _getRuleCombiningAlgId(self):
247        '''@return: rule combining algorithm ID
248        @rtype: NoneType / basestring
249        '''
250        return self.__ruleCombiningAlgId
251
252    def _setRuleCombiningAlgId(self, value):
253        '''@param value: rule combining algorithm ID
254        @type value: NoneType / basestring
255        @raise TypeError: incorrect input type
256        '''
257        if not isinstance(value, basestring):
258            raise TypeError('Expecting string type for "ruleCombiningAlgId" '
259                            'attribute; got %r' % type(value))
260           
261        self.__ruleCombiningAlgId = value
262        self._setRuleCombiningAlgFromId()
263       
264    def _setRuleCombiningAlgFromId(self):
265        """Set the rule combining algorithm implementation from the Id set in
266        __ruleCombiningAlgId the attribute
267       
268        @raise TypeError: incorrect input type
269        @raise UnsupportedStdFunctionError: no implementation is avaliable for
270        this XACML rule combining algorithm
271        @raise UnsupportedFunctionError: the rule combining algorithm is not
272        recognised as a standard XACML one
273        """
274        # Look-up rule combining algorithm
275        ruleCombiningAlgClass = self.__ruleCombiningAlgFactory(
276                                                    self.__ruleCombiningAlgId)
277        if (not isinstance(ruleCombiningAlgClass, type) or 
278            not issubclass(ruleCombiningAlgClass, RuleCombiningAlgInterface)):
279            raise TypeError('Expecting %r derived type for rule combining '
280                            'algorithm class; got %r type' %
281                            (RuleCombiningAlgInterface, ruleCombiningAlgClass))
282           
283        self.__ruleCombiningAlg = ruleCombiningAlgClass()
284        if self.__ruleCombiningAlg is NotImplemented:
285            raise UnsupportedStdFunctionError('The rule combining algorithm %r '
286                                              'is not currently implemented' % 
287                                              self.__ruleCombiningAlgId)
288           
289        elif self.__ruleCombiningAlg is None:
290            raise UnsupportedFunctionError('%r is not recognised as a valid '
291                                           'XACML rule combining algorithm' % 
292                                           self.__ruleCombiningAlgId) 
293
294    ruleCombiningAlgId = property(_getRuleCombiningAlgId, 
295                                  _setRuleCombiningAlgId, None, 
296                                  doc="Rule Combining Algorithm Id")
297
298    @property
299    def combinerParameters(self):
300        """@raise NotImplementedError: combiner parameters property is not
301        currently implemented
302        """
303        raise NotImplementedError()
304   
305    @property
306    def ruleCombinerParameters(self):
307        """@raise NotImplementedError: rule combiner parameters property is not
308        currently implemented
309        """
310        raise NotImplementedError()
311   
312    @property
313    def variableDefinitions(self):
314        """@raise NotImplementedError: variable definitions parameters property
315        is not currently implemented
316        """
317        raise NotImplementedError()
318   
319    @property
320    def rules(self):
321        """Return the list of rules
322        @return: list of rules
323        @rtype: ndg.xacml.utils.TypedList
324        """
325        return self.__attr
326   
327    @property
328    def obligations(self):
329        """@return: obligations
330        @rtype: ndg.xacml.utils.TypedList
331        """
332        return self.__obligations
333
334    def _getTarget(self):
335        """@return: target element
336        @rtype: NoneType / ndg.xacml.core.target.Target
337        """
338        return self.__target
339
340    def _setTarget(self, value):
341        """@param value: target element
342        @type value: ndg.xacml.core.target.Target
343        @raise TypeError: incorrect input type
344        """
345        if not isinstance(value, Target):
346            raise TypeError('Expecting Target for "target" '
347                            'attribute; got %r' % type(value))
348        self.__target = value
349
350    target = property(_getTarget, _setTarget, doc="list of Policy targets")
351
352    def _getDescription(self):
353        '''@return: policy description text
354        @rtype: NoneType / basestring
355        '''
356        return self.__description
357
358    def _setDescription(self, value):
359        '''@param value: policy description text
360        @type value: basestring
361        @raise TypeError: incorrect input type
362        '''
363        if not isinstance(value, basestring):
364            raise TypeError('Expecting string type for "description" '
365                            'attribute; got %r' % type(value))
366        self.__description = value
367
368    description = property(_getDescription, _setDescription, 
369                           doc="Policy Description text")
370
371    def _getPolicyDefaults(self):
372        '''@return: policy defaults
373        @rtype: NoneType / ndg.xacml.core.policydefaults.PolicyDefaults
374        '''
375        return self.__policyDefaults
376
377    def _setPolicyDefaults(self, value):
378        '''@param value: policy defaults
379        @type value: ndg.xacml.core.policydefaults.PolicyDefaults
380        @raise TypeError: incorrect input type
381        '''
382        if not isinstance(value, PolicyDefaults):
383            raise TypeError('Expecting string type for "policyDefaults" '
384                            'attribute; got %r' % type(value))
385           
386        self.__policyDefaults = value
387
388    policyDefaults = property(_getPolicyDefaults, 
389                              _setPolicyDefaults, 
390                              None, 
391                              "Policy PolicyDefaults element")   
392
393    def evaluate(self, request):
394        """Make an access control decision for the given request based on this
395        policy
396       
397        @param request: XACML request context
398        @type request: ndg.xacml.core.context.request.Request
399        @return: XACML response instance
400        @rtype: ndg.xacml.core.context.response.Response
401        @raise XacmlContextError: error evaluating input request context
402        """
403        response = Response()
404        result = Result.createInitialised(decision=Decision.NOT_APPLICABLE)
405        response.results.append(result)
406           
407        # Exception block around all rule processing in order to set
408        # INDETERMINATE response from any exceptions raised
409        try:
410            log.debug('Checking policy %r target for match with request...',
411                      self.policyId)
412           
413            target = self.target
414           
415            # If no target is set, ALL requests are counted as matches
416            if target is not None:
417                if not target.match(request):
418                    # The target didn't match so the whole policy does not apply
419                    # to this request
420                    log.debug('No match for policy target setting %r decision',
421                              Decision.NOT_APPLICABLE_STR)
422                   
423                    result.decision = Decision.NOT_APPLICABLE
424                    return response
425           
426            log.debug('Request matches the Policy %r target', self.policyId)
427           
428            # Apply the rule combining algorithm here combining the
429            # effects from the rules evaluated into an overall decision
430            result.decision = self.ruleCombiningAlg.evaluate(self.rules,
431                                                             request)
432        except XacmlContextError, e:
433            log.error('Exception raised evaluating request context, returning '
434                      '%r decision:%s', 
435                      e.response.results[0].decision, 
436                      traceback.format_exc())
437           
438            result = e.response.results[0]
439           
440        except Exception:
441            # Catch all so that nothing is handled from within the scope of this
442            # method
443            log.error('No PDPError type exception raised evaluating request '
444                      'context, returning %r decision:%s', 
445                      Decision.INDETERMINATE_STR, 
446                      traceback.format_exc()) 
447                       
448            result.decision = Decision.INDETERMINATE
449            result.status.statusCode.value = StatusCode.PROCESSING_ERROR
450           
451        return response
452
Note: See TracBrowser for help on using the repository browser.