source: TI12-security/trunk/ndg_xacml/ndg/xacml/core/rule_combining_alg.py @ 7682

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

Working and tested version with functionality for adding custom attribute value types and functions.

  • Property svn:keywords set to Id
RevLine 
[6822]1"""NDG XACML Condition type definition
2
[7087]3NERC DataGrid
[6822]4"""
5__author__ = "P J Kershaw"
6__date__ = "15/04/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"
[7064]11__revision__ = "$Id$"
[7682]12import logging
13log = logging.getLogger(__name__)
[6822]14
[7682]15from abc import abstractmethod
16
[6822]17from ndg.xacml.core.context.result import Decision
18
19
[7108]20# Rule Combining algorithms from the XACML spec.
[6822]21ALGORITHMS = (
22'urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides',
23'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:deny-overrides',
24'urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides',
25'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:permit-overrides',
26'urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable',
27'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable',
28'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:only-one-applicable',
29'urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:ordered-deny-overrides',
30'urn:oasis:names:tc:xacml:1.1:policy-combining-algorithm:ordered-deny-overrides',
31'urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:ordered-permit-overrides',
32'urn:oasis:names:tc:xacml:1.1:policy-combining-algorithm:ordered-permit-overrides',
33)
34
35
36class RuleCombiningAlgInterface(object):
37    """Interface class for XAML rule combining algorithms"""
38   
39    @abstractmethod
40    def evaluate(self, rules, context):
41        """Combine the input rule results to make an access control decision
42        based.  Derived classes must implement this method.  This implementation
43        returns indeterminate result.
44       
45        @param rules: rules from the policy.  Decisions from these will be put
46        together into a single decision by this algorithm
47        @type rules: TypedList(<ndg.xacml.core.rule.Rule>)
48        @param context: request context to apply to the rules
49        @type context: ndg.xacml.core.request.Request
50        @return: resulting overall access control decision
51        @rtype: ndg.xacml.core.context.result.Decision
52        """
53        return Decision.INDETERMINATE
54
[7108]55
[7050]56class DenyOverridesRuleCombiningAlg(RuleCombiningAlgInterface):
57    """Deny overrides rule combining algorithm"""
58   
59    def evaluate(self, rules, context):
60        """Combine the input rule results to make an access control decision.
61        Implementation taken direct from XACML 2.0 spec. pseudo code - Section
62        C.1 Deny Overrides
63       
64        @param rules: rules from the policy.  Decisions from these will be put
65        together into a single decision by this algorithm
66        @type rules: TypedList(<ndg.xacml.core.rule.Rule>)
67        @param context: request context to apply to the rules
68        @type context: ndg.xacml.core.request.Request
69        @return: resulting overall access control decision
70        @rtype: ndg.xacml.core.context.result.Decision
71        """
72        atLeastOneError = False
73        potentialDeny = False
74        atLeastOnePermit = False
75       
76        for rule in rules:
77            decision = rule.evaluate(context)
78            if decision == Decision.DENY:
79                return Decision.DENY
[6822]80
[7050]81            if decision == Decision.PERMIT:
82                atLeastOnePermit = True
83                continue
84           
85            if decision == Decision.NOT_APPLICABLE:
86                continue
87           
88            if decision == Decision.INDETERMINATE:
89                atLeastOneError = True
90   
[7682]91                if rule.effect.value == Decision.DENY:
[7050]92                    potentialDeny = True
93                   
94                continue
95
96        if potentialDeny:
97            return Decision.INDETERMINATE
98
99        elif atLeastOnePermit:
100            return Decision.PERMIT
101       
102        elif atLeastOneError:
103            return Decision.INDETERMINATE
104        else:
105            return Decision.NOT_APPLICABLE
106
107
[6823]108class PermitOverridesRuleCombiningAlg(RuleCombiningAlgInterface):
[6822]109    """Implementation of permit overrides XACML rule combining algorithm"""
110   
111    def evaluate(self, rules, context):
112        """Combine the input rule results to make an access control decision.
113        Implementation taken direct from XACML 2.0 spec. pseudo code - Section
114        C.3
115       
116        @param rules: rules from the policy.  Decisions from these will be put
117        together into a single decision by this algorithm
118        @type rules: TypedList(<ndg.xacml.core.rule.Rule>)
119        @param context: request context to apply to the rules
120        @type context: ndg.xacml.core.request.Request
121        @return: resulting overall access control decision
122        @rtype: ndg.xacml.core.context.result.Decision
123        """
124        atLeastOneError = False
125        potentialPermit = False
126        atLeastOneDeny = False
127       
[6823]128        for rule in rules:
[6822]129            decision = rule.evaluate(context)
130            if decision == Decision.DENY:
131                atLeastOneDeny = True
132                continue
133           
134            if decision == Decision.PERMIT:
[7682]135                log.debug("Rule %r permits, returning overall permit decision",
136                          rule.id)
[6822]137                return Decision.PERMIT
138           
139            if decision == Decision.NOT_APPLICABLE:
140                continue
141           
142            if decision == Decision.INDETERMINATE:
143                atLeastOneError = True
144               
145                if rule.effect.value == Decision.PERMIT_STR:
146                    potentialPermit = True
147               
148                continue
149       
150        if potentialPermit:
[7682]151            log.debug('Rule found with potential permit but it evaluates to '
152                      'indeterminate, returning overall indeterminate decision')
[6822]153            return Decision.INDETERMINATE
154       
155        if atLeastOneDeny:
[7682]156            log.debug('At least one rule with a deny decision found, returning '
157                      'overall deny decision')
[6822]158            return Decision.DENY
159       
160        if atLeastOneError:
[7682]161            log.debug('At least one rule with an error found, returning '
162                      'overall indeterminate decision')
[6822]163            return Decision.INDETERMINATE
164       
[7682]165        log.debug('No rules were applicable to the request, returning '
166                  'overall not applicable decision')
[6822]167        return Decision.NOT_APPLICABLE
168
169   
170class RuleCombiningAlgClassFactory(object):
171    """Class Factory mapping Rule Combining Algorithm identifiers to their
172    class implementations"""
[6823]173   
174    # All algorithms are not implemented by default(!)
[6822]175    DEFAULT_MAP = {}.fromkeys(ALGORITHMS, NotImplemented)
[6823]176   
177    # Permit overrides is the only one currently implemented
[7050]178    DEFAULT_MAP.update({
179    'urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides':
180        DenyOverridesRuleCombiningAlg,     
181    'urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides':
182        PermitOverridesRuleCombiningAlg
183    })
[7108]184    __slots__ = ('__map',)
[6822]185   
186    def __init__(self, map=DEFAULT_MAP):
[7108]187        """Initialise mapping of identifiers to class implementations
188       
189        @param map: mapping of rule combining algorithms IDs to classes.  Set
190        this to override the default taken from the DEFAULT_MAP class variable
191        """
[6822]192        self.__map = map
193   
194    def __call__(self, identifier):
195        """Return the class for a given Rule Combining Algorithm identifier
[6823]196        @param identifier: XACML rule combining algorithm urn
197        @type identifier: basestring
198        @return: rule combining class corresponding to the given input
199        identifier
200        @rtype: RuleCombiningAlgInterface derived type or NoneType if no match
201        is found or NotImplementedType if the identifier corresponds to a valid
202        XACML rule combining algorithm but is not supported in this
203        implementation
[6822]204        """
[6823]205        return self.__map.get(identifier)
Note: See TracBrowser for help on using the repository browser.