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

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