Changeset 5393


Ignore:
Timestamp:
12/06/09 16:35:39 (10 years ago)
Author:
pjkersha
Message:

More work on new policy parser

Location:
TI12-security/trunk/python
Files:
5 added
4 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml/__init__.py

    r5375 r5393  
    1616from elementtree import ElementTree 
    1717 
    18 from ndg.security.common.authz.xacml.factory import FunctionFactory, \ 
     18from ndg.security.common.authz.xacml.cond.factory import FunctionFactory, \ 
    1919    UnknownIdentifierException, FunctionTypeException 
    2020     
    21 import ndg.security.common.authz.xacml.cond 
    22 #class FunctionFactory: 
    23 #    pass 
    24  
    25  
    26 # For parsing: ElementTree helpers  
     21from ndg.security.common.authz.xacml.attr import AttributeFactory 
     22from ndg.security.common.authz.xacml.ctx import Result 
     23   
    2724getNs = lambda elem: elem.tag.split('}')[0][1:] 
    2825getLocalName = lambda elem: elem.tag.rsplit('}',1)[-1] 
     26 
     27class UnknownIdentifierException(Exception): 
     28    pass 
     29 
     30class ParsingException(Exception): 
     31    pass 
    2932 
    3033class XacmlBase(object): 
     
    8689            root = elem.getroot() 
    8790         
     91        rules = [] 
    8892        for elem in root: 
    8993            localName = getLocalName(elem) 
     
    9599                 
    96100            elif localName == 'Rule': 
    97                 pass 
     101                rules.append(Rule.getInstance(elem)) 
    98102             
    99103        policy = cls(id=root.attrib['PolicyId'],  
     
    166170 
    167171            if localName == prefix + "Match": 
    168                 list += TargetMatch.getInstance(elem, prefix) 
     172                list.append(TargetMatch.getInstance(elem, prefix)) 
    169173 
    170174        return tuple(list) 
     
    302306                raise ParsingException("invalid abstract function: %s" % e) 
    303307             
     308        attributeFactory = AttributeFactory.getInstance() 
     309         
    304310        # Get the designator or selector being used, and the attribute 
    305311        # value paired with it 
     
    315321            elif localName == "AttributeValue": 
    316322                try: 
    317                     attrValue = attrFactory.createValue(elem) 
     323                    attributeValue = attributeFactory.createValue(root=elem) 
    318324                except UnknownIdentifierException, e: 
    319325                    raise ParsingException("Unknown Attribute Type: %s" % e) 
    320326 
    321327        # finally, check that the inputs are valid for this function 
    322         inputs = [attrValue, eval] 
     328        inputs = [attributeValue, eval] 
    323329        function.checkInputsNoBag(inputs) 
    324330         
     
    449455        return 'permit' 
    450456 
    451 class Rule(XacmlBase): 
    452     '''Consists of a condition, an effect, and a target. 
     457class PolicyTreeElement(XacmlBase): 
     458    pass 
     459 
     460class Rule(PolicyTreeElement): 
     461    '''Represents the RuleType XACML type. This has a target for matching, and 
     462    encapsulates the condition and all sub-operations that make up the heart 
     463    of most policies. 
    453464    ''' 
    454     def __init__(self, conditions=[], effect=DenyEffect(), target=None): 
    455         # Conditions are statements about attributes that upon evaluation  
    456         # return either True, False, or Indeterminate. 
    457         self.conditions = conditions 
     465    def __init__(self, id, effect, description, target, condition): 
     466        '''Creates a new <code>Rule</code> object. 
     467         
     468        @param id: the rule's identifier 
     469        @param effect: the effect to return if the rule applies (either 
     470                      Permit or Deny) as specified in <code>Result</code> 
     471        @param description: a textual description, or None 
     472        @param target: the rule's target, or None if the target is to be 
     473                      inherited from the encompassing policy 
     474        @param condition: the rule's condition, or None if there is none 
     475        ''' 
     476         
     477        self.idAttr = id 
    458478         
    459479        # Effect is the intended consequence of the satisfied rule. It can  
    460480        # either take the value Permit or Deny. 
    461481        self.effect = effect 
    462        
     482         
     483        self.description = description 
     484         
    463485        # Target, as in the case of a policy, helps in determining whether or  
    464486        # not a rule is relevant for a request. The mechanism for achieving  
     
    467489        self.target = target 
    468490         
     491        # Conditions are statements about attributes that upon evaluation  
     492        # return either True, False, or Indeterminate. 
     493        self.condition = condition 
     494         
    469495    @classmethod 
    470     def getInstance(cls, elem): 
    471         root = elem.getroot() 
    472         return Rule(conditions=conditions, effect=effect, target=target) 
     496    def getInstance(cls, root): 
     497        '''Returns a new instance of the Rule class based on an XML element. 
     498        The element must be the root of an XML RuleType. 
     499         
     500        @param root: the root of a RuleType XML type 
     501        @raise ParsingException: if the RuleType is invalid 
     502        ''' 
     503        id = None 
     504        name = None 
     505        effect = 0 
     506        description = None 
     507        target = None 
     508        condition = None 
     509 
     510        id = root.attrib.get("RuleId") 
     511        if id is None: 
     512            raise ParsingException("Error parsing required attribute RuleId") 
     513         
     514        str = root.attrib.get("Effect") 
     515        if str == "Permit": 
     516            effect = Result.DECISION_PERMIT 
     517        elif str == "Deny": 
     518            effect = Result.DECISION_DENY 
     519        else: 
     520            raise ParsingException("Invalid Effect: %s" % effect) 
     521         
     522 
     523        # next, get the elements 
     524        for elem in list(root): 
     525            cname = getLocalName(elem) 
     526 
     527            if cname == "Description": 
     528                description = elem.text 
     529                 
     530            elif cname == "Target": 
     531                target = Target.getInstance(elem) 
     532                 
     533            elif cname == "Condition": 
     534                condition = Apply.getConditionInstance(elem) 
     535             
     536        return Rule(id, effect, description, target, condition) 
     537     
     538    def getEffect(self):  
     539        '''Returns the effect that this <code>Rule</code> will return from 
     540        the evaluate method (Permit or Deny) if the request applies. 
     541         
     542        @return a decision effect, as defined in <code>Result</code> 
     543        ''' 
     544        return self.effectAttr 
     545     
     546    def getId(self): 
     547        '''Returns the id of this <code>Rule</code> 
     548         
     549        @return the rule id''' 
     550        return self.idAttr 
     551     
     552    def getDescription(self): 
     553        '''Returns the given description of this <code>Rule</code> or None if  
     554        there is no description 
     555         
     556        @return: the description or None''' 
     557        return self.description 
     558      
     559    def getTarget(self): 
     560        '''Returns the target for this Rule or None if there is no target 
     561         
     562        @return: the rule's target''' 
     563        return self.target 
     564 
     565     
     566    def getChildren(self): 
     567        '''Since a rule is always a leaf in a policy tree because it can have 
     568        no children, this always returns an empty list. 
     569         
     570        @return: a list with no elements''' 
     571        return [] 
     572     
     573    def getCondition(self): 
     574        '''Returns the condition for this <code>Rule</code> or None if there 
     575        is no condition 
     576         
     577        @return: the rule's condition 
     578        ''' 
     579        return self.condition 
     580     
     581    def match(self, context): 
     582        '''Given the input context sees whether or not the request matches this 
     583        <code>Rule</code>'s <code>Target</code>. Note that unlike the matching 
     584        done by the <code>evaluate</code> method, if the <code>Target</code> 
     585        is missing than this will return Indeterminate. This lets you write 
     586        your own custom matching routines for rules but lets evaluation 
     587        proceed normally. 
     588         
     589        @param context the representation of the request 
     590         
     591        @return the result of trying to match this rule and the request 
     592        ''' 
     593        if target is None:  
     594            code = [] 
     595            code.append(Status.STATUS_PROCESSING_ERROR) 
     596            status = Status(code, "no target available for matching a rule") 
     597 
     598            return MatchResult(MatchResult.INDETERMINATE, status) 
     599         
     600 
     601        return target.match(context) 
     602     
     603    def evaluate(self, context):  
     604        '''Evaluates the rule against the supplied context. This will check  
     605        that  the target matches, and then try to evaluate the condition. If  
     606        the target and condition apply, then the rule's effect is returned in 
     607        the result. 
     608 
     609        Note that rules are not required to have targets. If no target is 
     610        specified, then the rule inherits its parent's target. In the event 
     611        that this Rule has no Target then the match is assumed to be true,  
     612        since evaluating a policy tree to this level required the parent's  
     613        target to match. 
     614         
     615        @param context: the representation of the request we're evaluating 
     616         
     617        @return: the result of the evaluation 
     618        ''' 
     619        # If the Target is None then it's supposed to inherit from the 
     620        # parent policy, so we skip the matching step assuming we wouldn't 
     621        # be here unless the parent matched 
     622        if target is not None:  
     623            match = target.match(context) 
     624            result = match.getResult() 
     625 
     626            # if the target didn't match, then this Rule doesn't apply 
     627            if result == MatchResult.NO_MATCH: 
     628                return Result(Result.DECISION_NOT_APPLICABLE, 
     629                              context.getResourceId().encode()) 
     630 
     631            # if the target was indeterminate, we can't go on 
     632            if result == MatchResult.INDETERMINATE: 
     633                return Result(Result.DECISION_INDETERMINATE, 
     634                              match.getStatus(), 
     635                              context.getResourceId().encode()) 
     636         
     637 
     638        # if there's no condition, then we just return the effect... 
     639        if condition is None: 
     640            return Result(effectAttr, context.getResourceId().encode()) 
     641 
     642        # ...otherwise we evaluate the condition 
     643        result = condition.evaluate(context) 
     644         
     645        if result.indeterminate(): 
     646            # if it was INDETERMINATE, then that's what we return 
     647            return Result(Result.DECISION_INDETERMINATE, 
     648                          result.getStatus(), 
     649                          context.getResourceId().encode()) 
     650        else:  
     651            # otherwise we return the effect on true, and NA on false 
     652            boolVal = result.getAttributeValue() 
     653 
     654            if boolVal.getValue(): 
     655                return Result(effectAttr, 
     656                              context.getResourceId().encode()) 
     657            else: 
     658                return Result(Result.DECISION_NOT_APPLICABLE, 
     659                              context.getResourceId().encode()) 
     660     
     661    def encode(self, output=None, indenter=None):  
     662        '''Encodes this Rule into its XML representation and writes 
     663        this encoding to the given <code>OutputStream</code> with 
     664        indentation. 
     665         
     666        @param output: a stream into which the XML-encoded data is written 
     667        @param indenter: an object that creates indentation strings''' 
     668        raise NotImplementedError() 
     669     
     670 
     671 
    473672           
    474673class Attribute(XacmlBase): 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml/attr.py

    r5168 r5393  
    1414log = logging.getLogger(__name__) 
    1515import sys 
    16 #import ndg.security.common.authz.xacml.cond 
    17 #Evaluatable=ndg.security.common.authz.xacml.cond.Evaluatable 
    18 try: 
    19     from ndg.security.common.authz.xacml.cond import Evaluatable 
    20 except ImportError: 
    21     pass 
    22 #import ndg.security.common.authz.xacml  
    23 class Evaluatable: 
    24     pass 
     16 
     17from ndg.security.common.authz.xacml.cond.eval import Evaluatable 
    2518 
    2619class AttributeValue(Evaluatable): 
     
    116109    identifier = "http://www.w3.org/2001/XMLSchema#string" 
    117110     
    118     def __init__(self, value): 
     111    def __init__(self, value=''): 
    119112        self.value = value 
    120113        super(StringAttribute, self).__init__(self.__class__.identifier) 
     
    125118    def _encode(self): 
    126119        return self.value 
     120     
     121    @classmethod 
     122    def getInstance(cls, root=None, value=None): 
     123        """Make a new StrinAttribute instance from an element or string value 
     124        @type root: ElementTree.Element 
     125        @param root: XML element 
     126        @type value: basestring 
     127        @param value: value to set string to 
     128        """ 
     129        if root is not None: 
     130            value = root.text 
     131        elif value is None: 
     132            raise TypeError('"elem" or "value" keyword must be set') 
     133             
     134        return StringAttribute(value=value) 
     135     
    127136 
    128137class AnyURIAttribute(AttributeValue): 
    129138    identifier = "http://www.w3.org/2001/XMLSchema#anyURI" 
    130139     
    131     def __init__(self, value): 
    132         self.value = value 
    133         super(StringAttribute, self).__init__(self.__class__.identifier) 
     140    def __init__(self, value=''): 
     141        self.value = value 
     142        super(AnyURIAttribute, self).__init__(self.__class__.identifier) 
    134143         
    135144    def __str__(self): 
     
    142151    identifier = "http://www.w3.org/2001/XMLSchema#base64Binary" 
    143152     
    144     def __init__(self, value): 
    145         self.value = value 
    146         super(StringAttribute, self).__init__(self.__class__.identifier) 
     153    def __init__(self, value=0): 
     154        self.value = value 
     155        super(Base64BinaryAttribute, self).__init__(self.__class__.identifier) 
    147156         
    148157    def __str__(self): 
     
    155164    identifier = "http://www.w3.org/2001/XMLSchema#boolean" 
    156165     
    157     def __init__(self, value): 
    158         self.value = value 
    159         super(StringAttribute, self).__init__(self.__class__.identifier) 
     166    def __init__(self, value=False): 
     167        self.value = value 
     168        super(BooleanAttribute, self).__init__(self.__class__.identifier) 
    160169         
    161170    def __str__(self): 
     
    168177    identifier = "http://www.w3.org/2001/XMLSchema#date" 
    169178     
     179    def __init__(self, value=''): 
     180        self.value = value 
     181        super(DateAttribute, self).__init__(self.__class__.identifier) 
     182     
    170183class DateTimeAttribute(AttributeValue): 
    171184    identifier = "http://www.w3.org/2001/XMLSchema#dateTime" 
    172185     
    173 class DayTimeDurationEqual(AttributeValue): 
     186    def __init__(self, value=''): 
     187        self.value = value 
     188        super(DateTimeAttribute, self).__init__(self.__class__.identifier) 
     189     
     190class DayTimeDurationAttribute(AttributeValue): 
    174191    identifier = ("http://www.w3.org/TR/2002/WD-xquery-operators-20020816#" 
    175192                  "dayTimeDuration") 
    176193     
     194    def __init__(self, value=''): 
     195        self.value = value 
     196        super(DayTimeDurationAttribute, self).__init__( 
     197                                                    self.__class__.identifier) 
     198    
    177199class DoubleAttribute(AttributeValue): 
    178200    identifier = "http://www.w3.org/2001/XMLSchema#double" 
    179201     
     202    def __init__(self, value=0.): 
     203        self.value = value 
     204        super(DoubleAttribute, self).__init__(self.__class__.identifier) 
     205     
    180206class HexBinaryAttribute(AttributeValue): 
    181207    identifier = "http://www.w3.org/2001/XMLSchema#hexBinary" 
     208     
     209    def __init__(self, value=0x0): 
     210        self.value = value 
     211        super(HexBinaryAttribute, self).__init__(self.__class__.identifier) 
    182212    
    183213class IntegerAttribute(AttributeValue): 
    184214    identifier = "http://www.w3.org/2001/XMLSchema#integer" 
    185215     
     216    def __init__(self, value=0): 
     217        self.value = value 
     218        super(IntegerAttribute, self).__init__(self.__class__.identifier) 
     219     
    186220class RFC822NameAttribute(AttributeValue): 
    187221    identifier = "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name" 
     222     
     223    def __init__(self, value=''): 
     224        self.value = value 
     225        super(RFC822NameAttribute, self).__init__(self.__class__.identifier) 
    188226         
    189227class TimeAttribute(AttributeValue): 
    190228    identifier = "http://www.w3.org/2001/XMLSchema#time" 
     229     
     230    def __init__(self, value=''): 
     231        self.value = value 
     232        super(TimeAttribute, self).__init__(self.__class__.identifier) 
    191233 
    192234class X500NameAttribute(AttributeValue): 
    193235    identifier = "urn:oasis:names:tc:xacml:1.0:data-type:x500Name" 
     236 
     237    def __init__(self, value=''): 
     238        self.value = value 
     239        super(X500NameAttribute, self).__init__(self.__class__.identifier) 
    194240 
    195241class YearMonthDurationAttribute(AttributeValue): 
     
    197243                  "yearMonthDuration") 
    198244     
     245    def __init__(self, value=''): 
     246        self.value = value 
     247        super(YearMonthDurationAttribute, self).__init__( 
     248                                                    self.__class__.identifier) 
     249 
     250     
     251class AttributeFactoryProxy(object): 
     252    '''A simple proxy interface used to install new AttributeFactory''' 
     253    @staticmethod 
     254    def getFactory(): 
     255        raise NotImplementedError() 
     256 
     257               
     258class AttributeFactory(object): 
     259    '''This is an abstract factory class for creating XACML attribute values. 
     260    There may be any number of factories available in the system, though 
     261    there is always one default factory used by the core code. 
     262    ''' 
     263 
     264    # the proxy used to get the default factory 
     265    defaultFactoryProxy = AttributeFactoryProxy()  
     266    defaultFactoryProxy.getFactory = lambda: \ 
     267                                        StandardAttributeFactory.getFactory() 
     268              
     269    @classmethod 
     270    def getInstance(cls): 
     271        '''Returns the default factory. Depending on the default factory's 
     272        implementation, this may return a singleton instance or new instances 
     273        with each invocation. 
     274     
     275        @return: the default AttributeFactory 
     276        ''' 
     277        return cls.defaultFactoryProxy.getFactory()     
     278 
     279     
     280    def addDatatype(self, id, proxy): 
     281        '''Adds a proxy to the factory, which in turn will allow new attribute 
     282        types to be created using the factory. Typically the proxy is 
     283        provided as an anonymous class that simply calls the getInstance 
     284        methods (or something similar) of some AttributeValue 
     285        class. 
     286         
     287        @param id the name of the attribute type 
     288        @param proxy the proxy used to create new attributes of the given type 
     289         
     290        @raise AttributeError if the given id is already in use 
     291        ''' 
     292        raise NotImplementedError() 
     293     
     294    def getSupportedDatatypes(self): 
     295        '''Returns the datatype identifiers supported by this factory. 
     296         
     297        @return: a list of strings 
     298        ''' 
     299        raise NotImplementedError() 
     300 
     301    def createValue(self, root, dataType=None, value=None): 
     302        '''Creates a value based on the given root element. The type of the 
     303        attribute is assumed to be present in the node as an XAML attribute 
     304        named DataType, as is the case with the AttributeValueType in the  
     305        policy schema. The value is assumed to be the first child of this node. 
     306         
     307        @param: ElementTree.Element root of an attribute value      
     308        @param dataType: the type of the attribute 
     309        @param value the text-encoded representation of an attribute's value 
     310        @return: a new AttributeValue     
     311        @raise UnknownIdentifierException if the type in the node isn't 
     312                                           known to the factory 
     313        @raise ParsingException if the node is invalid or can't be parsed 
     314                                 by the appropriate proxy 
     315        ''' 
     316        raise NotImplementedError()   
     317     
     318       
     319class BaseAttributeFactory(AttributeFactory): 
     320    '''This is a basic implementation of AttributeFactory abstract class. It 
     321    implements the insertion and retrieval methods, but doesn't actually 
     322    setup the factory with any datatypes. 
     323  
     324    Note that while this class is thread-safe on all creation methods, it 
     325    is not safe to add support for a new datatype while creating an instance 
     326    of a value. This follows from the assumption that most people will 
     327    initialize these factories up-front, and then start processing without 
     328    ever modifying the factories. If you need these mutual operations to 
     329    be thread-safe, then you should write a wrapper class that implements 
     330    the right synchronization. 
     331    ''' 
     332 
     333    def __init__(self, attributeMap={}):  
     334        # the map of proxies 
     335        self._attributeMap = attributeMap.copy() 
     336     
     337     
     338    def addDatatype(self, id, proxy): 
     339        '''Adds a proxy to the factory, which in turn will allow new attribute 
     340        types to be created using the factory. Typically the proxy is 
     341        provided as an anonymous class that simply calls the getInstance 
     342        methods (or something similar) of some AttributeValue 
     343        class. 
     344     
     345        @param id: the name of the attribute type 
     346        @param proxy: the proxy used to create new attributes of the given type 
     347        ''' 
     348        # make sure this doesn't already exist 
     349        if id in self._attributeMap: 
     350            raise AttributeError("Data type %s already exists" % id) 
     351 
     352        self._attributeMap[id] = proxy 
     353     
     354    def getSupportedDatatypes(self):  
     355        '''Returns the datatype identifiers supported by this factory. 
     356         
     357        @return: a list of types''' 
     358        return self._attributeMap.keys() 
     359     
     360    def createValue(self, root=None, dataType=None, value=None): 
     361        '''Creates a value based on the given elem root node. The type of the 
     362        attribute is assumed to be present in the node as an XACML attribute 
     363        named DataType, as is the case with the 
     364        AttributeValueType in the policy schema. The value is assumed to be 
     365        the first child of this node. 
     366         
     367        @param root: the root elem of an attribute value 
     368        @param dataType: the type of the attribute 
     369        @param value: the text-encoded representation of an attribute's value 
     370        @return: a new AttributeValue instance 
     371        @raise UnknownIdentifierException: if the type in the node isn't 
     372                                            known to the factory 
     373        @raise ParsingException: if the node is invalid or can't be parsed 
     374        by the appropriate proxy 
     375        ''' 
     376        if dataType is None: 
     377            dataType = root.attrib["DataType"] 
     378 
     379        proxy = self._attributeMap.get(dataType) 
     380        if proxy is None: 
     381            raise UnknownIdentifierException("Attributes of type %s aren't " 
     382                                             "supported." % dataType) 
     383             
     384        if root is not None: 
     385            param = root 
     386        elif value is not None: 
     387            param = value 
     388        else: 
     389            raise TypeError('A "root" or "value" keyword must be set') 
     390             
     391        try: 
     392            return proxy.getInstance(param) 
     393        except Exception, e:  
     394            raise ParsingException("Couldn't create %s attribute based on " 
     395                                   "element: %s" % (dataType, e)) 
     396             
     397 
     398class StandardAttributeFactory(BaseAttributeFactory): 
     399    '''This factory supports the standard set of datatypes specified in XACML 
     400    1.0 and 1.1. It is the default factory used by the system, and imposes 
     401    a singleton pattern insuring that there is only ever one instance of 
     402    this class. 
     403     
     404    Note that because this supports only the standard datatypes, this 
     405    factory does not allow the addition of any other datatypes. If you call 
     406    addDatatype on an instance of this class, an exception 
     407    will be thrown. If you need a standard factory that is modifiable, you 
     408    should create a new BaseAttributeFactory (or some other 
     409    AttributeFactory) and configure it with the standard 
     410    datatypes using addStandardDatatypes (or, in the case of 
     411    BaseAttributeFactory, by providing the datatypes in the 
     412    constructor).''' 
     413     
     414    factoryInstance = None 
     415     
     416    # the datatypes supported by this factory 
     417    supportedDatatypes = None 
     418     
     419    def __init__(self): 
     420        """Initialise attribute map from supportedDatatypes class var by  
     421        calling BaseAttributeFactory constructor 
     422        """ 
     423        super(StandardAttributeFactory, self).__init__( 
     424                    attributeMap=StandardAttributeFactory.supportedDatatypes) 
     425         
     426    @classmethod 
     427    def _initDatatypes(cls):  
     428        '''Private initializer for the supported datatypes. This isn't called 
     429        until something needs these values, and is only called once.''' 
     430        log.info("Initializing standard datatypes") 
     431 
     432        # TODO: implement Attribute proxy classes - maybe not needed? 
     433        cls.supportedDatatypes = { 
     434#            BooleanAttribute.identifier: BooleanAttributeProxy(), 
     435#            StringAttribute.identifier: StringAttributeProxy(), 
     436#            DateAttribute.identifier: DateAttributeProxy(), 
     437#            TimeAttribute.identifier: TimeAttributeProxy(), 
     438#            DateTimeAttribute.identifier: DateTimeAttributeProxy(), 
     439#            DayTimeDurationAttribute.identifier: DayTimeDurationAttributeProxy(), 
     440#            YearMonthDurationAttribute.identifier: YearMonthDurationAttributeProxy(), 
     441#            DoubleAttribute.identifier: DoubleAttributeProxy(), 
     442#            IntegerAttribute.identifier: IntegerAttributeProxy(), 
     443#            AnyURIAttribute.identifier: AnyURIAttributeProxy(), 
     444#            HexBinaryAttribute.identifier: HexBinaryAttributeProxy(), 
     445#            Base64BinaryAttribute.identifier: Base64BinaryAttributeProxy(), 
     446#            X500NameAttribute.identifier: X500NameAttributeProxy(), 
     447#            RFC822NameAttribute.identifier: RFC822NameAttributeProxy() 
     448            BooleanAttribute.identifier: BooleanAttribute(), 
     449            StringAttribute.identifier: StringAttribute(), 
     450            DateAttribute.identifier: DateAttribute(), 
     451            TimeAttribute.identifier: TimeAttribute(), 
     452            DateTimeAttribute.identifier: DateTimeAttribute(), 
     453            DayTimeDurationAttribute.identifier: DayTimeDurationAttribute(), 
     454            YearMonthDurationAttribute.identifier: YearMonthDurationAttribute(), 
     455            DoubleAttribute.identifier: DoubleAttribute(), 
     456            IntegerAttribute.identifier: IntegerAttribute(), 
     457            AnyURIAttribute.identifier: AnyURIAttribute(), 
     458            HexBinaryAttribute.identifier: HexBinaryAttribute(), 
     459            Base64BinaryAttribute.identifier: Base64BinaryAttribute(), 
     460            X500NameAttribute.identifier: X500NameAttribute(), 
     461            RFC822NameAttribute.identifier: RFC822NameAttribute() 
     462        } 
     463 
     464    @classmethod 
     465    def getFactory(cls): 
     466        '''Returns an instance of this factory. This method enforces a  
     467        singleton model, meaning that this always returns the same instance,  
     468        creating the factory if it hasn't been requested before. This is the  
     469        default model used by the AttributeFactory, ensuring quick access to  
     470        this factory. 
     471         
     472        @return the factory instance 
     473        @classmethod''' 
     474        if cls.factoryInstance is None: 
     475            cls._initDatatypes() 
     476            cls.factoryInstance = cls() 
     477             
     478        return cls.factoryInstance 
     479     
     480    def addDatatype(self, id, proxy): 
     481        ''' 
     482        @param id the name of the attribute type 
     483        @param proxy the proxy used to create new attributes of the given type 
     484         
     485        @raise: NotImplementedError: standard factory can't be  
     486        modified 
     487        ''' 
     488        raise NotImplementedError("a standard factory cannot support new data " 
     489                                  "types") 
     490 
     491 
     492     
     493 
     494 
     495     
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml/cond/__init__.py

    r5377 r5393  
    1616from ndg.security.common.authz.xacml.attr import AnyURIAttribute, \ 
    1717    Base64BinaryAttribute, BooleanAttribute, DateAttribute, DateTimeAttribute,\ 
    18     DayTimeDurationEqual, DoubleAttribute, HexBinaryAttribute, \ 
     18    DayTimeDurationAttribute, DoubleAttribute, HexBinaryAttribute, \ 
    1919    IntegerAttribute, RFC822NameAttribute, StringAttribute, TimeAttribute, \ 
    2020    X500NameAttribute, YearMonthDurationAttribute 
     
    281281                 paramType=None, 
    282282                 paramIsBag=False, 
    283                  numParams=0,  
     283                 numParams=-1,  
    284284                 minParams=0, 
    285285                 returnType='',  
    286286                 returnsBag=False): 
    287287        ''' 
    288         @param functionName the name of this function as used by the factory 
     288        @param functionName: the name of this function as used by the factory 
    289289                            and any XACML policies 
    290         @param functionId an optional identifier that can be used by your 
     290        @param functionId: an optional identifier that can be used by your 
    291291                          code for convenience 
    292         @param paramTypes the type of each parameter, in order, required by 
     292        @param paramType: the type of each parameter, in order, required by 
    293293                          this function, as used by the factory and any XACML 
    294294                           documents 
    295         @param paramIsBag whether or not each parameter is actually a bag 
     295        @param paramIsBag: whether or not each parameter is actually a bag 
    296296                          of values 
    297         @param returnType the type returned by this function, as used by 
     297        @param numParams: the number of parameters required by this function, 
     298        or -1 if any number are allowed 
     299        @param minParams: the minimum number of parameters required if  
     300        numParams is -1  
     301        @param returnType: the type returned by this function, as used by 
    298302                          the factory and any XACML documents 
    299         @param returnsBag whether or not this function returns a bag of values 
    300         ''' 
    301            
     303        @param returnsBag: whether or not this function returns a bag of values 
     304        '''           
    302305        self.functionName = functionName 
    303306        self.functionId = functionId 
    304         self.returnType = None 
    305         self.returnsBag = False 
    306      
    307         self.singleType = True; 
     307        self.returnType = returnType 
     308        self.returnsBag = returnsBag 
    308309     
    309310        self.paramType = paramType 
     311                 
     312        if isinstance(self.paramType, (list, tuple)): 
     313            if not self.paramType: 
     314                raise TypeError('"paramType" is set to an empty list or tuple') 
     315            self.singleType = False 
     316             
     317            # Keep this test within the paramType is-a-list if-block otherwise 
     318            # it may fail checking the length of a bool 
     319            if len(paramIsBag) != len(self.paramType): 
     320                raise TypeError('"paramIsBag" and "paramType" inputs must ' 
     321                                'have the same length') 
     322        else: 
     323            self.singleType = True 
     324             
     325            # These only apply if the input parameters are all of a single type 
     326            self.numParams = numParams 
     327            self.minParams = minParams 
     328             
    310329        self.paramIsBag = paramIsBag 
    311         self.numParams = numParams 
    312         self.minParams = minParams 
    313330         
    314331   
     
    332349             
    333350    def checkInputsNoBag(self, inputs): 
    334         '''Checks that the given inputs are of the right types, in the right  
    335         order, and are the right number for this function to evaluate.''' 
    336         raise NotImplementedError() 
     351        '''Default handling of input checking. This does some simple checking 
     352        based on the type of constructor used. If you need anything more 
     353        complex, or if you used the simple constructor, then you must 
     354        override this method. 
     355     
     356        @param inputs: a list of Evaluatable instances 
     357         
     358        @raise TypeError: if the inputs won't work 
     359        ''' 
     360        numInputs = len(inputs) 
     361         
     362        if self.singleType: 
     363            # first check to see if we need bags 
     364            if sum(self.paramIsBag): 
     365                raise TypeError('"%s" needs bags on input' % self.functionName) 
     366 
     367            # now check on the length 
     368            if self.numParams != -1:  
     369                if numInputs != self.numParams: 
     370                    raise TypeError('wrong number of args to "%s"' %  
     371                                    self.functionName) 
     372            else:  
     373                if numInputs < self.minParams: 
     374                    raise TypeError("not enough args to " % self.functionName) 
     375             
     376 
     377            # finally check param list 
     378            for eval in inputs:  
     379                if eval.getType().toString() != self.paramType: 
     380                    raise TypeError("Illegal parameter: input type is %s but " 
     381                                    "%s type is %s" %  
     382                                    (eval.getType().toString(), 
     383                                     self.__class__.__name__, 
     384                                     self.paramType)) 
     385             
     386        else:  
     387            # first, check the length of the inputs 
     388            if len(self.paramType) != numInputs: 
     389                raise TypeError('Wrong number of args to "%s"' %  
     390                                self.functionName) 
     391 
     392            # Ensure everything is of the same, correct type 
     393            it = zip(inputs, self.paramType, self.paramIsBag) 
     394            for eval, paramType, paramIsBag in it: 
     395                if eval.type != paramType or paramIsBag: 
     396                    raise TypeError("Illegal parameter: input type is %s but " 
     397                                    "%s type is %s" %  
     398                                    (eval.type, 
     399                                     self.__class__.__name__, 
     400                                     paramType)) 
     401 
    337402  
    338403    def evaluate(self, inputs, context): 
     
    420485    NAME_RFC822NAME_MATCH = FunctionBase.FUNCTION_NS + "rfc822Name-match" 
    421486    NAME_X500NAME_MATCH = FunctionBase.FUNCTION_NS + "x500Name-match"      
    422  
    423     supportedIdentifiers = (NAME_REGEXP_STRING_MATCH,  
    424                             NAME_RFC822NAME_MATCH, 
    425                             NAME_X500NAME_MATCH) 
     487     
     488    supportedIdentifiers = ( 
     489        NAME_REGEXP_STRING_MATCH,  
     490        NAME_RFC822NAME_MATCH, 
     491        NAME_X500NAME_MATCH) 
     492     
     493    functionIds = range(3) 
     494    ID_REGEXP_STRING_MATCH, ID_X500NAME_MATCH, ID_RFC822NAME_MATCH=functionIds 
     495    getId = dict(zip(supportedIdentifiers, functionIds)) 
     496    argParams = ( 
     497        (StringAttribute.identifier,)*2, 
     498        (X500NameAttribute.identifier,)*2, 
     499        (StringAttribute.identifier, 
     500         RFC822NameAttribute.identifier) 
     501    ) 
     502    getArgumentTypes = dict(zip(supportedIdentifiers, argParams)) 
     503     
     504    bagParams = (False, False) 
    426505     
    427506    lut = { 
     
    432511     
    433512    def __init__(self, functionName, **kw): 
    434           super(MatchFunction, self).__init__(functionName, **kw) 
     513          super(MatchFunction, self).__init__(functionName,  
     514                     functionId=MatchFunction.getId[functionName],  
     515                     paramType=MatchFunction.getArgumentTypes[functionName], 
     516                     paramIsBag=MatchFunction.bagParams, 
     517                     returnType=BooleanAttribute.identifier,  
     518                     returnsBag=False) 
     519 
    435520 
    436521    def regexpStringMatch(self, regex, val): 
     
    493578        DateAttribute, 
    494579        DateTimeAttribute, 
    495         DayTimeDurationEqual, 
     580        DayTimeDurationAttribute, 
    496581        DoubleAttribute, 
    497582        HexBinaryAttribute, 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml/cond/factory.py

    r5376 r5393  
    277277        functions = self.functionMap.keys() 
    278278 
    279         if self.superset != None: 
     279        if self.superset is not None: 
    280280            functions += self.superset.getSupportedFunctions() 
    281281 
Note: See TracChangeset for help on using the changeset viewer.