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

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

XACML implementation: fixes to Apply class added separate exceptions module

Line 
1"""XACML Package
2
3NERC DataGrid Project
4
5This package is adapted from the Sun Java XACML implementation ...
6
7Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
8
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions are met:
11
12  1. Redistribution of source code must retain the above copyright notice,
13     this list of conditions and the following disclaimer.
14
15  2. Redistribution in binary form must reproduce the above copyright
16     notice, this list of conditions and the following disclaimer in the
17     documentation and/or other materials provided with the distribution.
18
19Neither the name of Sun Microsystems, Inc. or the names of contributors may
20be used to endorse or promote products derived from this software without
21specific prior written permission.
22
23This software is provided "AS IS," without a warranty of any kind. ALL
24EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
25ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
26OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
27AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
28AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
29DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
30REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
31INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
32OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
33EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34
35You acknowledge that this software is not designed or intended for use in
36the design, construction, operation or maintenance of any nuclear facility.
37"""
38__author__ = "P J Kershaw"
39__date__ = "13/02/09"
40__copyright__ = "(C) 2009 Science and Technology Facilities Council"
41__contact__ = "Philip.Kershaw@stfc.ac.uk"
42__license__ = "BSD - see LICENSE file in top-level directory"
43__contact__ = "Philip.Kershaw@stfc.ac.uk"
44__revision__ = "$Id$"
45
46import logging
47log = logging.getLogger(__name__)
48
49from elementtree import ElementTree
50from ndg.security.common.utils import getLocalName
51
52from ndg.security.common.authz.xacml.exceptions import ParsingException, \
53    UnknownIdentifierException
54   
55from ndg.security.common.authz.xacml.cond.factory import FunctionFactory, \
56    FunctionTypeException
57
58from ndg.security.common.authz.xacml.attr import AttributeFactory, \
59    AttributeDesignator
60from ndg.security.common.authz.xacml.ctx import Result
61from ndg.security.common.authz.xacml.cond import Apply
62
63class XacmlBase(object):
64    pass
65
66class Subject(XacmlBase):
67    '''XACML Subject designator'''
68    def __init__(self, attributes={}):
69        self.attributes = attributes
70
71class Resource(XacmlBase):
72    '''XACML Resource designator'''
73
74class Action(XacmlBase):
75    '''XACML Action designator'''
76
77class Environment(XacmlBase):
78    '''XACML Environment designator'''
79
80class PolicySet(XacmlBase):
81    def __init__(self):
82          self.policies = []
83          self.combiningAlg = None
84         
85class Policy(XacmlBase):
86
87    def __init__(self,
88                 id='',
89                 ruleCombiningAlg=None,
90                 description='',
91                 target=None,
92                 rules=[],
93                 obligations=[]):
94          self.id = id
95          self.description = description
96          self.rules = rules
97          self.ruleCombiningAlg = ruleCombiningAlg
98          self.obligations = obligations
99          self.target = target
100
101    def encode(self):
102        '''Encode the policy'''
103        raise NotImplemented()
104   
105    @classmethod
106    def getInstance(cls, root=None, source=None):
107        """
108        @type root: ElementTree.Element
109        @param root: ElementTree root element
110        @type source: basestring / file like object
111        @param source: file path or file like object source of data
112        """
113        if root is None:
114            if source is None:
115                raise AttributeError('"root" or "source" keywords must be '
116                                     'provided')
117               
118            elem = ElementTree.parse(source)
119            root = elem.getroot()
120       
121        rules = []
122        for elem in root:
123            localName = getLocalName(elem)
124            if localName == 'Description':
125                description = elem.text.strip()
126               
127            elif localName == 'Target':
128                target = Target.getInstance(elem)
129               
130            elif localName == 'Rule':
131                rules.append(Rule.getInstance(elem))
132           
133        policy = cls(id=root.attrib['PolicyId'], 
134                     ruleCombiningAlg=root.attrib['RuleCombiningAlgId'],
135                     description=description,
136                     target=target,
137                     rules=rules,
138                     obligations=obligations)
139        return policy
140
141class MatchResult(XacmlBase):
142    pass
143
144class Target(XacmlBase):
145    '''The target selects policies relevant to a request'''
146
147    def __init__(self, subjects=None, resources=None, actions=None):
148          self.subjects = subjects
149          self.resources = resources
150          self.actions = actions
151          self.rules = []
152
153    def Match(self, evaluationCtx):
154          return MatchResult()
155       
156    @classmethod
157    def getInstance(cls, root):
158        '''Parse a Target from a given XML ElementTree element
159        '''
160        subjects = None
161        resources = None
162        actions = None
163       
164        for elem in root:
165            localName = getLocalName(elem)
166
167            if localName == "Subjects":
168                subjects = Target._getAttributes(elem, "Subject")
169               
170            elif localName == "Resources":
171                resources = Target._getAttributes(elem, "Resource")
172               
173            elif localName == "Actions":
174                actions = Target._getAttributes(elem, "Action")
175       
176        return cls(subjects=subjects, resources=resources, actions=actions)
177   
178    @staticmethod
179    def _getAttributes(root, prefix):
180        '''Helper method to get Target children elements'''
181        matches = []
182
183        for elem in root:
184            localName = getLocalName(elem)
185
186            if localName == prefix:
187                matches += Target._getMatches(elem, prefix)
188            elif localName == "Any" + prefix:
189                return None
190
191        return matches
192   
193    @staticmethod
194    def _getMatches(root, prefix):
195
196        list = []
197
198        for elem in root:
199            localName = getLocalName(elem)
200
201            if localName == prefix + "Match":
202                list.append(TargetMatch.getInstance(elem, prefix))
203
204        return tuple(list)
205       
206   
207class TargetMatch(XacmlBase):
208    '''Represents the SubjectMatch, ResourceMatch, or ActionMatch XML
209    types in XACML, depending on the value of the type field. This is the
210    part of the Target that actually evaluates whether the specified
211    attribute values in the Target match the corresponding attribute
212    values in the request context.
213    '''
214    types = range(3)
215    SUBJECT, RESOURCE, ACTION = types
216   
217    def __init__(self,
218                 type,
219                 function,
220                 eval,
221                 attributeValue):
222        '''Create a TargetMatch from components.
223         
224        @param type an integer indicating whether this class represents a
225        SubjectMatch, ResourceMatch, or ActionMatch
226        @param function the Function that represents the MatchId
227        @param eval the AttributeDesignator or AttributeSelector to be used to
228        select attributes from the request context
229        @param attrValue the AttributeValue to compare against
230        @raise TypeError if the input type isn't a valid value
231        '''
232        if type not in self.__class__.types:
233            raise TypeError("Type is [%d] but it must be one of %r" % 
234                            (type, self.__class__.types))
235        self.type = type
236        self.function = function
237        self.eval = eval
238        self.attrValue = attributeValue
239
240    def _getType(self):
241        return getattr(self, '_type', None)
242   
243    def _setType(self, type):
244        if type not in self.__class__.types:
245            raise TypeError('Type value "%d" not recognised, expecting one of '
246                            '%r types' % (type, self.__class__.types))
247        self._type = type
248       
249    type = property(fget=_getType, fset=_setType, 
250                    doc="the type of match for this target")
251   
252    @classmethod
253    def getInstance(cls, root, prefix):
254        '''Creates a TargetMatch by parsing a node, using the
255        input prefix to determine whether this is a SubjectMatch,
256        ResourceMatch, or ActionMatch.
257     
258        @param root the node to parse for the TargetMatch
259        @param prefix a String indicating what type of TargetMatch
260        to instantiate (Subject, Resource, or Action)
261        @param xpathVersion the XPath version to use in any selectors, or
262        null if this is unspecified (ie, not supplied in
263        the defaults section of the policy)
264
265        @return a new TargetMatch constructed by parsing
266        '''
267
268        type = ["Subject", "Resource", "Action"].index(prefix)
269        if type not in cls.types:
270            raise TypeError("Unknown TargetMatch type: %s" % prefix)
271
272        # function type
273        funcId = root.attrib["MatchId"]
274        factory = FunctionFactory.getTargetInstance()
275        try:
276            function = factory.createFunction(funcId)
277        except UnknownIdentifierException, e:
278            raise ParsingException("Unknown MatchId: %s" % e)
279       
280        except FunctionTypeException, e:
281            # try to create an abstract function
282            try:
283                function = factory.createAbstractFunction(funcId, root)
284            except Exception, e:
285                raise ParsingException("invalid abstract function: %s" % e)
286           
287        attributeFactory = AttributeFactory.getInstance()
288       
289        # Get the designator or selector being used, and the attribute
290        # value paired with it
291        for elem in root:
292            localName = getLocalName(elem)
293
294            if localName == prefix + "AttributeDesignator":
295                eval = AttributeDesignator.getInstance(elem, type)
296               
297            elif localName == "AttributeSelector":
298                eval = AttributeSelector.getInstance(elem)
299               
300            elif localName == "AttributeValue":
301                try:
302                    attributeValue = attributeFactory.createValue(root=elem)
303                except UnknownIdentifierException, e:
304                    raise ParsingException("Unknown Attribute Type: %s" % e)
305
306        # finally, check that the inputs are valid for this function
307        inputs = [attributeValue, eval]
308        function.checkInputsNoBag(inputs)
309       
310        return cls(type, function, eval, attributeValue)
311   
312
313    def match(self, context):
314        '''determines whether this TargetMatch matches
315        the input request (whether it is applicable)
316
317        @param context the representation of the request
318
319        @return the result of trying to match the TargetMatch and the request
320        '''
321       
322        result = eval.evaluate(context)
323       
324        if result.indeterminate():
325            # in this case, we don't ask the function for anything, and we
326            # simply return INDETERMINATE
327            return MatchResult(MatchResult.INDETERMINATE, result.getStatus())
328       
329
330        bag = result.getAttributeValue()
331
332        if not bag.isEmpty():
333           
334            # we got back a set of attributes, so we need to iterate through
335            # them, seeing if at least one matches
336            it = bag.iterator()
337            atLeastOneError = False
338            firstIndeterminateStatus = None
339
340            while it.hasNext():
341                inputs = []
342
343                inputs.add(attrValue)
344                inputs.add(it.next())
345
346                # do the evaluation
347                match = evaluateMatch(inputs, context)
348               
349                # we only need one match for this whole thing to match
350                if match.getResult() == MatchResult.MATCH:
351                    return match
352
353                # if it was INDETERMINATE, we want to remember for later
354                if match.getResult() == MatchResult.INDETERMINATE:
355                    atLeastOneError = True
356
357                    # there are no rules about exactly what status data
358                    # should be returned here, so like in the combining
359                    # also, we'll just track the first error
360                    if firstIndeterminateStatus == None:
361                        firstIndeterminateStatus = match.getStatus()
362
363            # if we got here, then nothing matched, so we'll either return
364            # INDETERMINATE or NO_MATCH
365            if atLeastOneError:
366                return MatchResult(MatchResult.INDETERMINATE,
367                                       firstIndeterminateStatus)
368            else:
369                return MatchResult(MatchResult.NO_MATCH)
370
371        else:
372            # this is just an optimization, since the loop above will
373            # actually handle this case, but this is just a little
374            # quicker way to handle an empty bag
375            return MatchResult(MatchResult.NO_MATCH)
376   
377    def evaluateMatch(self, inputs, context):
378        '''Private helper that evaluates an individual match'''
379       
380        # evaluate the function
381        result = function.evaluate(inputs, context)
382
383        # if it was indeterminate, then that's what we return immediately
384        if result.indeterminate():
385            return MatchResult(MatchResult.INDETERMINATE,
386                               result.getStatus())
387
388        # otherwise, we figure out if it was a match
389        bool = result.getAttributeValue()
390
391        if bool.getValue():
392            return MatchResult(MatchResult.MATCH)
393        else:
394            return MatchResult(MatchResult.NO_MATCH)
395
396    def encode(self, output, indenter=None):
397        '''Encodes this TargetMatch into its XML representation
398        and writes this encoding to the given OutputStream with no
399        indentation.
400        @param output a stream into which the XML-encoded data is written'''
401        raise NotImplementedError()
402   
403   
404class Status(XacmlBase):
405    STATUS_MISSING_ATTRIBUTE = \
406          "urn:oasis:names:tc:xacml:1.0:status:missing-attribute"
407    STATUS_OK = "urn:oasis:names:tc:xacml:1.0:status:ok"
408    STATUS_PROCESSING_ERROR = \
409          "urn:oasis:names:tc:xacml:1.0:status:processing-error"
410    STATUS_SYNTAX_ERROR = \
411          "urn:oasis:names:tc:xacml:1.0:status:syntax-error" 
412     
413class EvaluationResult(XacmlBase):
414    def __init__(self, 
415                 attributeValue=None, 
416                 status=None, 
417                 indeterminate=False):
418        self.status = status
419        self.attributeValue = attributeValue
420        self.indeterminate = indeterminate
421     
422
423class Effect(XacmlBase):
424    def __str__(self):
425        raise NotImplementedError()
426
427             
428class DenyEffect(Effect):
429    def __str__(self):
430        return 'deny'
431         
432class PermitEffect(Effect):
433    def __str__(self):
434        return 'permit'
435
436class PolicyTreeElement(XacmlBase):
437    pass
438
439class Rule(PolicyTreeElement):
440    '''Represents the RuleType XACML type. This has a target for matching, and
441    encapsulates the condition and all sub-operations that make up the heart
442    of most policies.
443    '''
444    def __init__(self, ruleId, effect, description, target, condition):
445        '''Creates a new <code>Rule</code> object.
446       
447        @param ruleId: the rule's identifier
448        @param effect: the effect to return if the rule applies (either
449                      Permit or Deny) as specified in <code>Result</code>
450        @param description: a textual description, or None
451        @param target: the rule's target, or None if the target is to be
452                      inherited from the encompassing policy
453        @param condition: the rule's condition, or None if there is none
454        '''
455       
456        self.idAttr = ruleId
457       
458        # Effect is the intended consequence of the satisfied rule. It can
459        # either take the value Permit or Deny.
460        self.effect = effect
461       
462        self.description = description
463       
464        # Target, as in the case of a policy, helps in determining whether or
465        # not a rule is relevant for a request. The mechanism for achieving
466        # this is also similar to how it is done in the case of a target for a
467        # policy.
468        self.target = target
469       
470        # Conditions are statements about attributes that upon evaluation
471        # return either True, False, or Indeterminate.
472        self.condition = condition
473       
474    @classmethod
475    def getInstance(cls, root):
476        '''Returns a new instance of the Rule class based on an XML element.
477        The element must be the root of an XML RuleType.
478       
479        @param root: the root of a RuleType XML type
480        @raise ParsingException: if the RuleType is invalid
481        '''
482        id = None
483        name = None
484        effect = 0
485        description = None
486        target = None
487        condition = None
488
489        id = root.attrib.get("RuleId")
490        if id is None:
491            raise ParsingException("Error parsing required attribute RuleId")
492       
493        str = root.attrib.get("Effect")
494        if str == "Permit":
495            effect = Result.DECISION_PERMIT
496        elif str == "Deny":
497            effect = Result.DECISION_DENY
498        else:
499            raise ParsingException("Invalid Effect: %s" % effect)
500       
501
502        # next, get the elements
503        for elem in list(root):
504            cname = getLocalName(elem)
505
506            if cname == "Description":
507                description = elem.text
508               
509            elif cname == "Target":
510                target = Target.getInstance(elem)
511               
512            elif cname == "Condition":
513                condition = Apply.getConditionInstance(elem)
514           
515        return Rule(id, effect, description, target, condition)
516   
517    def getEffect(self): 
518        '''Returns the effect that this <code>Rule</code> will return from
519        the evaluate method (Permit or Deny) if the request applies.
520       
521        @return a decision effect, as defined in <code>Result</code>
522        '''
523        return self.effectAttr
524   
525    def getId(self):
526        '''Returns the id of this <code>Rule</code>
527       
528        @return the rule id'''
529        return self.idAttr
530   
531    def getDescription(self):
532        '''Returns the given description of this <code>Rule</code> or None if
533        there is no description
534       
535        @return: the description or None'''
536        return self.description
537     
538    def getTarget(self):
539        '''Returns the target for this Rule or None if there is no target
540       
541        @return: the rule's target'''
542        return self.target
543
544   
545    def getChildren(self):
546        '''Since a rule is always a leaf in a policy tree because it can have
547        no children, this always returns an empty list.
548       
549        @return: a list with no elements'''
550        return []
551   
552    def getCondition(self):
553        '''Returns the condition for this <code>Rule</code> or None if there
554        is no condition
555       
556        @return: the rule's condition
557        '''
558        return self.condition
559   
560    def match(self, context):
561        '''Given the input context sees whether or not the request matches this
562        <code>Rule</code>'s <code>Target</code>. Note that unlike the matching
563        done by the <code>evaluate</code> method, if the <code>Target</code>
564        is missing than this will return Indeterminate. This lets you write
565        your own custom matching routines for rules but lets evaluation
566        proceed normally.
567       
568        @param context the representation of the request
569       
570        @return the result of trying to match this rule and the request
571        '''
572        if target is None: 
573            code = []
574            code.append(Status.STATUS_PROCESSING_ERROR)
575            status = Status(code, "no target available for matching a rule")
576
577            return MatchResult(MatchResult.INDETERMINATE, status)
578       
579
580        return target.match(context)
581   
582    def evaluate(self, context): 
583        '''Evaluates the rule against the supplied context. This will check
584        that  the target matches, and then try to evaluate the condition. If
585        the target and condition apply, then the rule's effect is returned in
586        the result.
587
588        Note that rules are not required to have targets. If no target is
589        specified, then the rule inherits its parent's target. In the event
590        that this Rule has no Target then the match is assumed to be true,
591        since evaluating a policy tree to this level required the parent's
592        target to match.
593       
594        @param context: the representation of the request we're evaluating
595       
596        @return: the result of the evaluation
597        '''
598        # If the Target is None then it's supposed to inherit from the
599        # parent policy, so we skip the matching step assuming we wouldn't
600        # be here unless the parent matched
601        if target is not None: 
602            match = target.match(context)
603            result = match.getResult()
604
605            # if the target didn't match, then this Rule doesn't apply
606            if result == MatchResult.NO_MATCH:
607                return Result(Result.DECISION_NOT_APPLICABLE,
608                              context.getResourceId().encode())
609
610            # if the target was indeterminate, we can't go on
611            if result == MatchResult.INDETERMINATE:
612                return Result(Result.DECISION_INDETERMINATE,
613                              match.getStatus(),
614                              context.getResourceId().encode())
615       
616
617        # if there's no condition, then we just return the effect...
618        if condition is None:
619            return Result(effectAttr, context.getResourceId().encode())
620
621        # ...otherwise we evaluate the condition
622        result = condition.evaluate(context)
623       
624        if result.indeterminate():
625            # if it was INDETERMINATE, then that's what we return
626            return Result(Result.DECISION_INDETERMINATE,
627                          result.getStatus(),
628                          context.getResourceId().encode())
629        else: 
630            # otherwise we return the effect on true, and NA on false
631            boolVal = result.getAttributeValue()
632
633            if boolVal.getValue():
634                return Result(effectAttr,
635                              context.getResourceId().encode())
636            else:
637                return Result(Result.DECISION_NOT_APPLICABLE,
638                              context.getResourceId().encode())
639   
640    def encode(self, output=None, indenter=None): 
641        '''Encodes this Rule into its XML representation and writes
642        this encoding to the given <code>OutputStream</code> with
643        indentation.
644       
645        @param output: a stream into which the XML-encoded data is written
646        @param indenter: an object that creates indentation strings'''
647        raise NotImplementedError()
648   
649
650
651         
652class Attribute(XacmlBase):
653    def __init__(self, id, type=None, issuer=None, issueInstant=None, 
654                 value=None):
655        self.id = id
656        self.type = type or value.__class__
657        self.issuer = issuer
658        self.issueInstant = issueInstant
659        self.value = value
660
661       
662class Request(XacmlBase):
663    '''XACML Request XacmlBase
664   
665    TODO: refactor from this initial placeholder'''
666    def __init__(self, subject, resource, action=None, environment={}):
667          self.subject = subject
668          self.resource = resource
669          self.action = action
670          self.environment = environment
671
672class Response(XacmlBase):
673    pass
674
675
676class PDP(XacmlBase):
677    '''Modify PDPInterface to use the four XACML request designators: subject,
678    resource, action and environment
679   
680    This is an initial iteration toward a complete XACML implementation'''
681    def __init__(self, *arg, **kw):
682          pass
683   
684    def evaluate(self, request):
685          '''Make access control decision - override this in a derived class to
686          implement the decision logic but this method may be called within
687          the derived method to check input types
688         
689          @param request: request object containing the subject, resource,
690          action and environment
691          @type request: ndg.security.common.authz.xacml.Request
692          @return reponse object
693          @rtype: ndg.security.common.authz.xacml.Response
694          '''
695          raise NotImplementedError()
696
697
698class RuleCombiningAlg(XacmlBase):
699    id = None
700
701class DenyOverrides(RuleCombiningAlg):
702   '''Deny-overrides: If any rule evaluates to Deny, then the final
703   authorization decision is also Deny.'''
704   id = 'Deny-overrides'
705   
706class OrderedDenyOverrides(RuleCombiningAlg):
707    '''Ordered-deny-overrides: Same as deny-overrides, except the order in
708    which relevant rules are evaluated is the same as the order in which they
709    are added in the policy.'''
710    id = 'Ordered-deny-overrides'
711   
712class PermitOverrides(RuleCombiningAlg):
713    '''Permit-overrides: If any rule evaluates to Permit, then the final
714    authorization decision is also Permit.'''
715   
716class OrderedPermitOverrides(RuleCombiningAlg):
717    '''Ordered-permit-overrides: Same as permit-overrides, except the order in
718    which relevant rules are evaluated is the same as the order in which they
719    are added in the policy.'''
720    id = 'Ordered-permit-overrides'
721   
722class FirstApplicable(RuleCombiningAlg):
723    '''First-applicable: The result of the first relevant rule encountered is
724    the final authorization decision as well.'''
725    id = 'First-applicable'
726
727
728class EvaluationCtx(object):
729
730    # The standard URI for listing a resource's id
731    RESOURCE_ID ="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
732
733    # The standard URI for listing a resource's scope
734    RESOURCE_SCOPE = "urn:oasis:names:tc:xacml:1.0:resource:scope"
735
736    # Resource scope of Immediate (only the given resource)
737    SCOPE_IMMEDIATE = 0
738
739    # Resource scope of Children (the given resource and its direct
740    # children)
741    SCOPE_CHILDREN = 1
742
743    # Resource scope of Descendants (the given resource and all descendants
744    # at any depth or distance)
745    SCOPE_DESCENDANTS = 2
746   
747    def getRequestRoot(self):
748        '''Returns the DOM root of the original RequestType XML document, if
749        this context is backed by an XACML Request. If this context is not
750        backed by an XML representation, then an exception is thrown.'''
751        raise NotImplementedError()
752
753    def getResourceId(self):
754        '''Returns the identifier for the resource being requested.'''
755        raise NotImplementedError()
756
757    def getScope(self):
758        '''Returns the resource scope, which will be one of the three fields
759        denoting Immediate, Children, or Descendants.'''
760        raise NotImplementedError()
761
762    def setResourceId(self, resourceId):
763        '''Changes the value of the resource-id attribute in this context. This
764        is useful when you have multiple resources (ie, a scope other than
765        IMMEDIATE), and you need to keep changing only the resource-id to
766        evaluate the different effective requests.'''
767        raise NotImplementedError()
768
769    def getCurrentTime(self):
770        '''Returns the cached value for the current time. If the value has
771        never been set by a call to setCurrentTime, or if caching
772        is not enabled in this instance, then this will return null.'''
773        raise NotImplementedError()
774
775    def setCurrentTime(self, currentTime):
776        '''Sets the current time for this evaluation. If caching is not enabled
777        for this instance then the value is ignored.
778     
779        @param currentTime the dynamically resolved current time'''
780        raise NotImplementedError()
781
782    def getCurrentDate(self):
783        '''Returns the cached value for the current date. If the value has
784        never been set by a call to setCurrentDate, or if caching
785        is not enabled in this instance, then this will return null.'''
786        raise NotImplementedError()
787
788    def setCurrentDate(self, currentDate):
789        '''Sets the current date for this evaluation. If caching is not enabled
790        for this instance then the value is ignored.'''
791        raise NotImplementedError()
792
793    def getCurrentDateTime(self):
794        '''Returns the cached value for the current dateTime. If the value has
795        never been set by a call to setCurrentDateTime, or if
796        caching is not enabled in this instance, then this will return null.
797        '''
798        raise NotImplementedError()
799
800    def setCurrentDateTime(self, currentDateTime):
801        '''Sets the current dateTime for this evaluation. If caching is not
802        enabled for this instance then the value is ignored.
803     
804        @param currentDateTime the dynamically resolved current dateTime'''
805        raise NotImplementedError()
806
807    def getSubjectAttribute(self, type, id, category):
808        '''Returns available subject attribute value(s) ignoring the issuer.
809     
810        @param type the type of the attribute value(s) to find
811        @param id the id of the attribute value(s) to find
812        @param category the category the attribute value(s) must be in
813     
814        @return a result containing a bag either empty because no values were
815        found or containing at least one value, or status associated with an
816        Indeterminate result'''
817        raise NotImplementedError()
818
819    def getSubjectAttribute(self, type, id, issuer, category):
820        '''Returns available subject attribute value(s).
821     
822        @param type the type of the attribute value(s) to find
823        @param id the id of the attribute value(s) to find
824        @param issuer the issuer of the attribute value(s) to find or null
825        @param category the category the attribute value(s) must be in
826     
827        @return a result containing a bag either empty because no values were
828        found or containing at least one value, or status associated with an
829        Indeterminate result'''
830        raise NotImplementedError()
831   
832    def getResourceAttribute(self, type, id, issuer):
833        '''Returns available resource attribute value(s).
834     
835        @param type the type of the attribute value(s) to find
836        @param id the id of the attribute value(s) to find
837        @param issuer the issuer of the attribute value(s) to find or null
838     
839        @return a result containing a bag either empty because no values were
840        found or containing at least one value, or status associated with an
841        Indeterminate result'''
842        raise NotImplementedError()
843
844    def getActionAttribute(self, type, id, issuer):
845        '''Returns available action attribute value(s).
846     
847        @param type the type of the attribute value(s) to find
848        @param id the id of the attribute value(s) to find
849        @param issuer the issuer of the attribute value(s) to find or null
850     
851        @return a result containing a bag either empty because no values were
852        found or containing at least one value, or status associated with an
853        Indeterminate result'''
854        raise NotImplementedError()
855
856    def getEnvironmentAttribute(self, type, id, issuer):
857        '''Returns available environment attribute value(s).
858     
859        @param type the type of the attribute value(s) to find
860        @param id the id of the attribute value(s) to find
861        @param issuer the issuer of the attribute value(s) to find or null
862     
863        @return a result containing a bag either empty because no values were
864        found or containing at least one value, or status associated with an
865        Indeterminate result'''
866        raise NotImplementedError()
867
868    def getAttribute(self, contextPath, namespaceNode, type, xpathVersion):
869        '''Returns the attribute value(s) retrieved using the given XPath
870        expression.
871     
872        @param contextPath the XPath expression to search
873        @param namespaceNode the DOM node defining namespace mappings to use,
874                            or null if mappings come from the context root
875        @param type the type of the attribute value(s) to find
876        @param xpathVersion the version of XPath to use
877     
878        @return a result containing a bag either empty because no values were
879       
880        found or containing at least one value, or status associated with an
881        Indeterminate result'''
882        raise NotImplementedError()
Note: See TracBrowser for help on using the repository browser.