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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg-security/TI12-security/trunk/ndg_xacml/ndg/xacml/core/policy.py@7103
Revision 7103, 14.5 KB checked in by pjkersha, 11 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 / basestring
79    @ivar __attr: attribute
80    @type __attr: NoneType / basestring
81    @ivar __obligations: obligations
82    @type __obligations: NoneType / basestring
83    @ivar __ruleCombiningAlgFactory: rule combining algorithm factory
84    @type __ruleCombiningAlgFactory: NoneType / basestring
85    @ivar __ruleCombiningAlg: rule combining algorithm
86    @type __ruleCombiningAlg: NoneType / basestring
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       
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        return self.__ruleCombiningAlgFactory
149
150    def _setRuleCombiningAlgFactory(self, value):
151        if not isinstance(value, RuleCombiningAlgClassFactory):
152            raise TypeError('Expecting %r derived type for '
153                            '"ruleCombiningAlgFactory" attibute; got %r' % 
154                            (RuleCombiningAlgClassFactory, type(value)))
155           
156        self.__ruleCombiningAlgFactory = value
157
158    ruleCombiningAlgFactory = property(_getRuleCombiningAlgFactory, 
159                                       _setRuleCombiningAlgFactory, 
160                                       doc="Rule Combining Algorithm Factory")
161   
162    @property
163    def ruleCombiningAlg(self):
164        "Rule Combining algorithm"
165        return self.__ruleCombiningAlg
166   
167    @classmethod
168    def fromSource(cls, source, readerFactory):
169        """Create a new policy from the input source parsing it using a
170        reader from the required reader factory e.g. ETreeReaderFactory to use
171        ElementTree based parsing
172       
173        @param source: source from which to read the policy - file path,
174        file object, XML node or other dependent on the reader factory selected
175        @type source: string, file, XML node type
176        @param readerFactory: factory class returns reader class used to parse
177        the policy
178        @type readerFactory: ndg.xacml.parsers.AbstractReaderFactory
179        @return: new policy instance
180        @rtype: ndg.xacml.core.policy.Policy
181        """
182        if not issubclass(readerFactory, AbstractReaderFactory):
183            raise TypeError('Expecting %r derived class for reader factory '
184                            'method; got %r' % (AbstractReaderFactory, 
185                                                readerFactory))
186           
187        reader = readerFactory.getReader(cls)
188        if not issubclass(reader, AbstractReader):
189            raise TypeError('Expecting %r derived class for reader class; '
190                            'got %r' % (AbstractReader, reader))
191           
192        return reader.parse(source)
193       
194    def _getPolicyId(self):
195        return self.__policyId
196
197    def _setPolicyId(self, value):
198        if not isinstance(value, basestring):
199            raise TypeError('Expecting string type for "policyId" '
200                            'attribute; got %r' % type(value))
201           
202        self.__policyId = value
203
204    policyId = property(_getPolicyId, _setPolicyId, None, "Policy Id")
205
206    def _getVersion(self):
207        return self.__version
208
209    def _setVersion(self, value):
210        if not isinstance(value, basestring):
211            raise TypeError('Expecting string type for "version" '
212                            'attribute; got %r' % type(value))
213           
214        self.__version = value
215
216    version = property(_getVersion, _setVersion, None, "Policy Version")
217
218    def _getRuleCombiningAlgId(self):
219        return self.__ruleCombiningAlgId
220
221    def _setRuleCombiningAlgId(self, value):
222        if not isinstance(value, basestring):
223            raise TypeError('Expecting string type for "ruleCombiningAlgId" '
224                            'attribute; got %r' % type(value))
225           
226        self.__ruleCombiningAlgId = value
227        self._setRuleCombiningAlgFromId()
228       
229    def _setRuleCombiningAlgFromId(self):
230        """Set the rule combining algorithm implementation from the Id set
231        """
232        # Look-up rule combining algorithm
233        ruleCombiningAlgClass = self.__ruleCombiningAlgFactory(
234                                                    self.__ruleCombiningAlgId)
235        if (not isinstance(ruleCombiningAlgClass, type) or 
236            not issubclass(ruleCombiningAlgClass, RuleCombiningAlgInterface)):
237            raise TypeError('Expecting %r derived type for rule combining '
238                            'algorithm class; got %r type' %
239                            (RuleCombiningAlgInterface, ruleCombiningAlgClass))
240           
241        self.__ruleCombiningAlg = ruleCombiningAlgClass()
242        if self.__ruleCombiningAlg is NotImplemented:
243            raise UnsupportedStdFunctionError('The rule combining algorithm %r '
244                                              'is not currently implemented' % 
245                                              self.__ruleCombiningAlgId)
246           
247        elif self.__ruleCombiningAlg is None:
248            raise UnsupportedFunctionError('%r is not recognised as a valid '
249                                           'XACML rule combining algorithm' % 
250                                           self.__ruleCombiningAlgId) 
251
252    ruleCombiningAlgId = property(_getRuleCombiningAlgId, 
253                                  _setRuleCombiningAlgId, None, 
254                                  doc="Rule Combining Algorithm Id")
255
256    @property
257    def combinerParameters(self):
258        raise NotImplementedError()
259   
260    @property
261    def ruleCombinerParameters(self):
262        raise NotImplementedError()
263   
264    @property
265    def variableDefinitions(self):
266        raise NotImplementedError()
267   
268    @property
269    def rules(self):
270        return self.__attr
271   
272    @property
273    def obligations(self):
274        return self.__obligations
275
276    def _getTarget(self):
277        return self.__target
278
279    def _setTarget(self, value):
280        if not isinstance(value, Target):
281            raise TypeError('Expecting Target for "target" '
282                            'attribute; got %r' % type(value))
283        self.__target = value
284
285    target = property(_getTarget, _setTarget, doc="list of Policy targets")
286
287    def _getDescription(self):
288        return self.__description
289
290    def _setDescription(self, value):
291        if not isinstance(value, basestring):
292            raise TypeError('Expecting string type for "description" '
293                            'attribute; got %r' % type(value))
294        self.__description = value
295
296    description = property(_getDescription, _setDescription, 
297                           doc="Policy Description text")
298
299    def _getPolicyDefaults(self):
300        return self.__policyDefaults
301
302    def _setPolicyDefaults(self, value):
303        if not isinstance(value, PolicyDefaults):
304            raise TypeError('Expecting string type for "policyDefaults" '
305                            'attribute; got %r' % type(value))
306           
307        self.__policyDefaults = value
308
309    policyDefaults = property(_getPolicyDefaults, 
310                              _setPolicyDefaults, 
311                              None, 
312                              "Policy PolicyDefaults element")   
313
314    def evaluate(self, request):
315        """Make an access control decision for the given request based on this
316        policy
317       
318        @param request: XACML request context
319        @type request: ndg.xacml.core.context.request.Request
320        @return: XACML response instance
321        @rtype: ndg.xacml.core.context.response.Response
322        """
323        response = Response()
324        result = Result.createInitialised(decision=Decision.NOT_APPLICABLE)
325        response.results.append(result)
326           
327        # Exception block around all rule processing in order to set
328        # INDETERMINATE response from any exceptions raised
329        try:
330            log.debug('Checking policy %r target for match with request...',
331                      self.policyId)
332           
333            target = self.target
334           
335            # If no target is set, ALL requests are counted as matches
336            if target is not None:
337                if not target.match(request):
338                    # The target didn't match so the whole policy does not apply
339                    # to this request
340                    log.debug('No match for policy target setting %r decision',
341                              Decision.NOT_APPLICABLE_STR)
342                   
343                    result.decision = Decision.NOT_APPLICABLE
344                    return response
345           
346            log.debug('Request matches the Policy %r target', self.policyId)
347           
348            # Apply the rule combining algorithm here combining the
349            # effects from the rules evaluated into an overall decision
350            result.decision = self.ruleCombiningAlg.evaluate(self.rules,
351                                                             request)
352        except XacmlContextError, e:
353            log.error('Exception raised evaluating request context, returning '
354                      '%r decision:%s', 
355                      e.response.results[0].decision, 
356                      traceback.format_exc())
357           
358            result = e.response.results[0]
359           
360        except Exception:
361            # Catch all so that nothing is handled from within the scope of this
362            # method
363            log.error('No PDPError type exception raised evaluating request '
364                      'context, returning %r decision:%s', 
365                      Decision.INDETERMINATE_STR, 
366                      traceback.format_exc()) 
367                       
368            result.decision = Decision.INDETERMINATE
369            result.status.statusCode.value = StatusCode.PROCESSING_ERROR
370           
371        return response
372
Note: See TracBrowser for help on using the repository browser.