1 """NDG XACML Policy Combining Algorithm definitions
2
3 NERC DataGrid
4 """
5 __author__ = "R B Wilkinson"
6 __date__ = "01/11/11"
7 __copyright__ = "(C) 2011 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$"
12 import logging
13 log = logging.getLogger(__name__)
14
15 from abc import abstractmethod
16
17 from ndg.xacml.core.context.result import Decision
18
19
20
21 ALGORITHMS = (
22 'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:deny-overrides',
23 'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:permit-overrides',
24 'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable',
25 'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:only-one-applicable',
26 'urn:oasis:names:tc:xacml:1.1:policy-combining-algorithm:ordered-deny-overrides',
27 'urn:oasis:names:tc:xacml:1.1:policy-combining-algorithm:ordered-permit-overrides',
28 )
32 """Interface class for XAML policy combining algorithms"""
33
34 @abstractmethod
36 """Combine the results from evaluating policies or policy sets to make
37 an access control decision. Derived classes must implement this
38 method. This implementation returns indeterminate result.
39
40 @param policies: policies and/or policy sets. Decisions from these
41 will be put together into a single decision by this algorithm.
42 @type policies: TypedList(<ndg.xacml.core.policybase.PolicyBase>)
43 @param context: request context to apply to the rules
44 @type context: ndg.xacml.core.request.Request
45 @return: resulting overall access control decision
46 @rtype: ndg.xacml.core.context.result.Decision
47 """
48 return Decision.INDETERMINATE
49
52 """Deny overrides policy combining algorithm"""
53
55 """Combine the input policy results to make an access control decision.
56 Implementation taken directly from XACML 2.0 spec. pseudo code -
57 Section C.1 Deny Overrides
58
59 @param policies: policies and/or policy sets. Decisions from these
60 will be put together into a single decision by this algorithm.
61 @type policies: TypedList(<ndg.xacml.core.policybase.PolicyBase>)
62 @param context: request context to apply to the rules
63 @type context: ndg.xacml.core.request.Request
64 @return: resulting overall access control decision
65 @rtype: ndg.xacml.core.context.result.Decision
66 """
67 atLeastOnePermit = False
68
69 for policy in policies:
70 decision = policy.evaluate(context)
71 if decision == Decision.DENY:
72 return Decision.DENY
73
74 if decision == Decision.PERMIT:
75 atLeastOnePermit = True
76 continue
77
78 if decision == Decision.NOT_APPLICABLE:
79 continue
80
81 if decision == Decision.INDETERMINATE:
82 return Decision.DENY
83
84 if atLeastOnePermit:
85 return Decision.PERMIT
86
87 return Decision.NOT_APPLICABLE
88
90 """Implementation of permit overrides XACML policy combining algorithm"""
91
93 """Combine the input policy results to make an access control decision.
94 Implementation taken directly from XACML 2.0 spec. pseudo code -
95 Section C.3 Permit Overrides
96
97 @param policies: policies and/or policy sets. Decisions from these
98 will be put together into a single decision by this algorithm.
99 @type policies: TypedList(<ndg.xacml.core.policybase.PolicyBase>)
100 @param context: request context to apply to the rules
101 @type context: ndg.xacml.core.request.Request
102 @return: resulting overall access control decision
103 @rtype: ndg.xacml.core.context.result.Decision
104 """
105 atLeastOneError = False
106 atLeastOneDeny = False
107
108 for policy in policies:
109 decision = policy.evaluate(context)
110 if decision == Decision.DENY:
111 atLeastOneDeny = True
112 continue
113
114 if decision == Decision.PERMIT:
115 log.debug("Policy %r permits, returning overall permit"
116 " decision", policy.ident)
117 return Decision.PERMIT
118
119 if decision == Decision.NOT_APPLICABLE:
120 continue
121
122 if decision == Decision.INDETERMINATE:
123 atLeastOneError = True
124 continue
125
126 if atLeastOneDeny:
127 log.debug('At least one policy with a deny decision found, '
128 'returning overall deny decision')
129 return Decision.DENY
130
131 if atLeastOneError:
132 log.debug('At least one policy with an error found, returning '
133 'overall indeterminate decision')
134 return Decision.INDETERMINATE
135
136 log.debug('No policies were applicable to the request, returning '
137 'overall not applicable decision')
138 return Decision.NOT_APPLICABLE
139
142 """Implementation of first applicable XACML policy combining algorithm"""
143
145 """Combine the results from evaluating policies or policy sets to make
146 an access control decision. Implementation taken directly from XACML
147 2.0 spec. pseudo code - Section C.5 First Applicable
148
149 @param policies: policies and/or policy sets. Decisions from these
150 will be put together into a single decision by this algorithm.
151 @type policies: TypedList(<ndg.xacml.core.policybase.PolicyBase>)
152 @param context: request context to apply to the rules
153 @type context: ndg.xacml.core.request.Request
154 @return: resulting overall access control decision
155 @rtype: ndg.xacml.core.context.result.Decision
156 """
157 for policy in policies:
158 decision = policy.evaluate(context)
159 if decision == Decision.DENY:
160 log.debug("Policy %r denies, returning overall deny decision",
161 policy.ident)
162 return Decision.DENY
163
164 if decision == Decision.PERMIT:
165 log.debug("Policy %r permits, returning overall permit "
166 "decision",
167 policy.ident)
168 return Decision.PERMIT
169
170 if decision == Decision.NOT_APPLICABLE:
171 continue
172
173 if decision == Decision.INDETERMINATE:
174 log.debug("Policy %r is indeterminate, returning overall "
175 "indeterminate decision", policy.ident)
176 return Decision.INDETERMINATE
177
178 log.debug('No policies were applicable to the request, returning '
179 'overall not applicable decision')
180 return Decision.NOT_APPLICABLE
181
184 """Class Factory mapping Policy Combining Algorithm identifiers to their
185 class implementations"""
186
187
188 DEFAULT_MAP = {}.fromkeys(ALGORITHMS, NotImplemented)
189
190
191 DEFAULT_MAP.update({
192 'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:deny-overrides':
193 DenyOverridesPolicyCombiningAlg,
194 'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:permit-overrides':
195 PermitOverridesPolicyCombiningAlg,
196 'urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable':
197 FirstApplicablePolicyCombiningAlg
198 })
199 __slots__ = ('__map',)
200
202 """Initialise mapping of identifiers to class implementations
203
204 @param map: mapping of policy combining algorithms IDs to classes. Set
205 this to override the default taken from the DEFAULT_MAP class variable
206 """
207 self.__map = map
208
210 """Return the class for a given Policy Combining Algorithm identifier
211 @param identifier: XACML policy combining algorithm urn
212 @type identifier: basestring
213 @return: policy combining class corresponding to the given input
214 identifier
215 @rtype: PolicyCombiningAlgInterface derived type or NoneType if no match
216 is found or NotImplementedType if the identifier corresponds to a valid
217 XACML policy combining algorithm but is not supported in this
218 implementation
219 """
220 return self.__map.get(identifier)
221