source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml.py @ 5093

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml.py@5093
Revision 5093, 11.0 KB checked in by pjkersha, 11 years ago (diff)

More functionality added to xacml module.

Line 
1"""XACML Policy Decision Point module
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "13/02/09"
7__copyright__ = "(C) 2009 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
13import logging
14log = logging.getLogger(__name__)
15
16from ndg.security.common.authz.pdp import PDPInterface
17
18class XacmlBase(object):
19    pass
20
21class Subject(XacmlBase):
22    '''XACML Subject designator'''
23
24class Resource(XacmlBase):
25    '''XACML Resource designator'''
26
27class Action(XacmlBase):
28    '''XACML Action designator'''
29
30class Environment(XacmlBase):
31    '''XACML Environment designator'''
32
33class PolicySet(XacmlBase):
34    def __init__(self):
35        self.policies = []
36        self.combiningAlg = None
37       
38class Policy(XacmlBase):
39
40    def __init__(self,
41                 id,
42                 combiningAlg,
43                 description,
44                 target,
45                 ruleList):
46        self.id = id
47        self.description = description
48        self.ruleList = ruleList
49        self.combiningAlg = combiningAlg
50        self.obligations = []
51        self.target = target
52
53    def encode(self):
54        '''Encode the policy'''
55        raise NotImplemented()
56
57class MatchResult(XacmlBase):
58    pass
59
60class Target(XacmlBase):
61    '''The target selects policies relevant to a request'''
62
63    def __init__(self, subjects=[], resources=[], actions=[]):
64        self.subjects = subjects
65        self.resources = resources
66        self.actions = actions
67        self.rules = []
68
69    def Match(self, evaluationCtx):
70        return MatchResult()
71   
72   
73class AttributeDesignator(XacmlBase):
74    ACTION_TARGET, ENVIRONMENT_TARGET, RESOURCE_TARGET, SUBJECT_TARGET=range(4)
75
76    def __init__(self, target, type, id, mustBePresent=False, issuer=None):
77        self.target = target
78        self.type = type
79        self.id = id
80        self.mustBePresent = mustBePresent
81        self.issuer = issuer
82
83
84class TargetMatch(XacmlBase):
85    SUBJECT, RESOURCE, ACTION = range(3)
86   
87    def __init__(self,
88                 type,
89                 function,
90                 eval,
91                 attributeValue):
92        pass
93class FunctionBase(XacmlBase):
94    def __init__(self, functionName):
95        self.functionName = functionName
96        self.returnType = None
97        self.returnsBag = False
98       
99    def _setFunctionName(self, functionName):
100        if functionName not in MatchFunction.supportedIdentifiers:
101            matchFunctionList = ', '.join(MatchFunction.matchFunctionNames)
102            raise TypeError("Function name [%s] is not on of the recognised "
103                            "types: %s" % (functionName, matchFunctionList))
104        self._functionName = functionName
105       
106    def _getFunctionName(self):
107        return getattr(self, '_functionName', None)
108   
109    functionName = property(fset=_setFunctionName,
110                            fget=_getFunctionName)
111       
112    def checkInputs(self, inputs):
113        '''Checks that the given inputs are of the right types, in the right
114        order, and are the right number for this function to evaluate.'''
115        raise NotImplementedError()
116         
117    def checkInputsNoBag(self, inputs):
118        '''Checks that the given inputs are of the right types, in the right
119        order, and are the right number for this function to evaluate.'''
120        raise NotImplementedError()
121 
122    def evaluate(self, inputs, context):
123        '''Evaluates the Function using the given inputs.'''
124        raise NotImplementedError()
125
126class MatchFunction(FunctionBase):
127    NAME_REGEXP_STRING_MATCH = \
128        "urn:oasis:names:tc:xacml:1.0:function:regexp-string-match"
129    NAME_RFC822NAME_MATCH = \
130        "urn:oasis:names:tc:xacml:1.0:function:rfc822Name-match"
131    NAME_X500NAME_MATCH = \
132        "urn:oasis:names:tc:xacml:1.0:function:x500Name-match"     
133
134    supportedIdentifiers = (NAME_REGEXP_STRING_MATCH, 
135                            NAME_RFC822NAME_MATCH,
136                            NAME_X500NAME_MATCH)
137   
138    lut = {
139        NAME_REGEXP_STRING_MATCH: 'regexpStringMatch',
140        NAME_RFC822NAME_MATCH: 'rfc822NameMatch',
141        NAME_X500NAME_MATCH: 'x500NameMatch'
142    }
143    def __init__(self, functionName):
144        super(MatchFunction, self).__init__(functionName)
145
146    def regexpStringMatch(self, regex, val):
147        return re.match(regex, val) is not None
148   
149    def rfc822NameMatch(self, *inputs):
150        raise NotImplementedError()
151   
152    def x500NameMatch(self, *inputs):
153        raise NotImplementedError()
154   
155    def evaluate(self, inputs, context):
156        matchFunction = getattr(self, MatchFunction.lut[self.functionName])
157        match = matchFunction(self, *inputs)
158        if match:
159            return EvaluationResult(status=Status.STATUS_OK)
160
161
162class EqualFunction(FunctionBase):
163     NAME_ANYURI_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal"
164     NAME_BASE64BINARY_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:base64Binary-equal"
165     NAME_BOOLEAN_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:boolean-equal"
166     NAME_DATE_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:date-equal"
167     NAME_DATETIME_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:dateTime-equal"
168     NAME_DAYTIME_DURATION_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-equal"
169     NAME_DOUBLE_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:double-equal"
170     NAME_HEXBINARY_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:hexBinary-equal"
171     NAME_INTEGER_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:integer-equal"
172     NAME_RFC822NAME_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:rfc822Name-equal"
173     NAME_STRING_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:string-equal"
174     NAME_TIME_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:time-equal"
175     NAME_X500NAME_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:x500Name-equal"
176     NAME_YEARMONTH_DURATION_EQUAL = "urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-equal"
177
178     lut = {
179         NAME_STRING_EQUAL: 'stringEqual'
180     }
181     
182     def __init__(self, functionName, argumentType):
183         super(MatchFunction, self).__init__(functionName)
184         self.argumentType = argumentType
185
186     def evaluate(self, inputs, evaluationCtx):
187         function = EqualFunction.lut.get(self.functionName)
188         if function is None:
189             raise NotImplementedError("No implementation is available for "
190                                       "%s" % self.functionName)
191             
192         
193    def stringEqual(self, ):
194        pass
195   
196class Status(XacmlBase):
197    STATUS_MISSING_ATTRIBUTE = \
198        "urn:oasis:names:tc:xacml:1.0:status:missing-attribute"
199    STATUS_OK = "urn:oasis:names:tc:xacml:1.0:status:ok"
200    STATUS_PROCESSING_ERROR = \
201        "urn:oasis:names:tc:xacml:1.0:status:processing-error"
202    STATUS_SYNTAX_ERROR = \
203        "urn:oasis:names:tc:xacml:1.0:status:syntax-error" 
204     
205class EvaluationResult(XacmlBase):
206    def __init__(self, 
207                 attributeValue=None, 
208                 status=None, 
209                 indeterminate=False):
210        self.status = status
211        self.attributeValue = attributeValue
212        self.indeterminate = indeterminate
213           
214class Effect(XacmlBase):
215    def __str__(self):
216        raise NotImplementedError()
217       
218class DenyEffect(Effect):
219    def __str__(self):
220        return 'deny'
221       
222class PermitEffect(Effect):
223    def __str__(self):
224        return 'permit'
225
226class Rule(XacmlBase):
227    '''Consists of a condition, an effect, and a target.
228    '''
229    def __init__(self):
230        # Conditions are statements about attributes that upon evaluation
231        # return either True, False, or Indeterminate.
232        self.conditions = []
233        # Effect is the intended consequence of the satisfied rule. It can
234        # either take the value Permit or Deny.
235        self.effect = DenyEffect()
236       
237        # Target, as in the case of a policy, helps in determining whether or
238        # not a rule is relevant for a request. The mechanism for achieving
239        # this is also similar to how it is done in the case of a target for a
240        # policy.
241        self.target = Target()
242       
243       
244class Request(XacmlBase):
245    '''XACML Request XacmlBase
246   
247    TODO: refactor from this initial placeholder'''
248    def __init__(self):
249        self.subject = Subject()
250        self.resource = Resource()
251        self.action = Action()
252        self.environment = Environment()
253 
254class PEP(XacmlBase):
255    pass
256       
257class PDP(PDPInterface):
258    '''Modify PDPInterface to use the four XACML request designators: subject,
259    resource, action and environment
260   
261    This is an initial iteration toward a complete XACML implementation'''
262    def __init__(self, *arg, **kw):
263        pass
264   
265    def accessPermitted(self, request):
266        '''Make access control decision - override this in a derived class to
267        implement the decision logic but this method may be called within
268        the derived method to check input types
269       
270        @param subject: entity making the request e.g. user or user agent
271        @type subject: Subject
272        @param resource: resource to be accessed
273        @type resource: Resource
274        @param action: action to be carried out on the resource
275        @type action: Action
276        @param environ: environment settings
277        @type environ: Environment
278        @raise TypeError: incorrect inputs
279        '''
280        if not isinstance(subject, Subject):
281            raise TypeError("Input subject must of type %r" % Subject)
282
283        if not isinstance(resource, Resource):
284            raise TypeError("Input resource must of type %r" % Resource)
285
286        if not isinstance(action, Action):
287            raise TypeError("Input action must of type %r" % Action)
288
289        if not isinstance(environment, Environment):
290            raise TypeError("Input environment must of type %r" % Environment)
291       
292        # Default to denied
293        return False
294
295
296class RuleCombiningAlg(XacmlBase):
297    id = None
298
299class DenyOverrides(RuleCombiningAlg):
300   '''Deny-overrides: If any rule evaluates to Deny, then the final
301   authorization decision is also Deny.'''
302   id = 'Deny-overrides'
303   
304class OrderedDenyOverrides(RuleCombiningAlg):
305    '''Ordered-deny-overrides: Same as deny-overrides, except the order in
306    which relevant rules are evaluated is the same as the order in which they
307    are added in the policy.'''
308    id = 'Ordered-deny-overrides'
309   
310class PermitOverrides(RuleCombiningAlg):
311    '''Permit-overrides: If any rule evaluates to Permit, then the final
312    authorization decision is also Permit.'''
313   
314class OrderedPermitOverrides(RuleCombiningAlg):
315    '''Ordered-permit-overrides: Same as permit-overrides, except the order in
316    which relevant rules are evaluated is the same as the order in which they
317    are added in the policy.'''
318    id = 'Ordered-permit-overrides'
319   
320class FirstApplicable(RuleCombiningAlg):
321    '''First-applicable: The result of the first relevant rule encountered is
322    the final authorization decision as well.'''
323    id = 'First-applicable'
Note: See TracBrowser for help on using the repository browser.