Changeset 5157 for TI12-security


Ignore:
Timestamp:
01/04/09 16:06:37 (11 years ago)
Author:
pjkersha
Message:

Added to code for PDP to parse policy doc

Location:
TI12-security/trunk/python
Files:
3 edited

Legend:

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

    r5148 r5157  
    1616from ndg.security.common.authz.pdp import PDPInterface 
    1717 
     18# For parsing: ElementTree helpers  
     19getNs = lambda elem: elem.tag.split('}')[0][1:] 
     20getLocalName = lambda elem: elem.tag.rsplit('}',1)[-1] 
     21 
    1822class XacmlBase(object): 
    1923    pass 
     
    2125class Subject(XacmlBase): 
    2226    '''XACML Subject designator''' 
     27    def __init__(self, attributes={}): 
     28        self.attributes = attributes 
    2329 
    2430class Resource(XacmlBase): 
     
    3945 
    4046    def __init__(self, 
    41                      id, 
    42                      combiningAlg, 
    43                      description, 
    44                      target, 
    45                      ruleList): 
     47                 id='', 
     48                 ruleCombiningAlg=None, 
     49                 description='', 
     50                 target=None, 
     51                 rules=[], 
     52                 obligations=[]): 
    4653          self.id = id 
    4754          self.description = description 
    48           self.ruleList = ruleList 
    49           self.combiningAlg = combiningAlg 
    50           self.obligations = [] 
     55          self.rules = rules 
     56          self.ruleCombiningAlg = ruleCombiningAlg 
     57          self.obligations = obligations 
    5158          self.target = target 
    5259 
     
    5461        '''Encode the policy''' 
    5562        raise NotImplemented() 
     63     
     64    @classmethod 
     65    def getInstance(cls, elem): 
     66         
     67        for elem in elem.getchildren(): 
     68            localName = getLocalName(elem) 
     69            if localName == 'Description': 
     70                description = elem.text 
     71                 
     72            elif localName == 'Target': 
     73                target = Target.getInstance(elem) 
     74                 
     75            elif localName == 'Rule': 
     76                pass 
     77             
     78        policy = cls(id=root.attrib['PolicyId'],  
     79                     ruleCombiningAlg=root.attrib['RuleCombiningAlg'], 
     80                     description=description, 
     81                     target=target, 
     82                     rules=rules, 
     83                     obligations=obligations) 
     84        return policy 
    5685 
    5786class MatchResult(XacmlBase): 
     
    6190    '''The target selects policies relevant to a request''' 
    6291 
    63     def __init__(self, subjects=[], resources=[], actions=[]): 
     92    def __init__(self, subjects=None, resources=None, actions=None): 
    6493          self.subjects = subjects 
    6594          self.resources = resources 
     
    6998    def Match(self, evaluationCtx): 
    7099          return MatchResult() 
     100         
     101    @classmethod 
     102    def getInstance(cls, root): 
     103        '''Parse a Target from a given XML ElementTree element 
     104        ''' 
     105        subjects = None 
     106        resources = None 
     107        actions = None 
     108         
     109        for elem in root.getchildren(): 
     110            localName = getLocalName(elem) 
     111 
     112            if localName == "Subjects": 
     113                subjects = Target._getAttributes(elem, "Subject") 
     114                 
     115            elif name == "Resources": 
     116                resources = Target._getAttributes(elem, "Resource") 
     117                 
     118            elif name == "Actions": 
     119                actions = Target._getAttributes(elem, "Action") 
     120         
     121        return cls() 
     122     
     123    @staticmethod 
     124    def _getAttributes(root, prefix): 
     125        '''Helper method to get Target children elements''' 
     126        matches = [] 
     127 
     128        for elem in root.getchildren(): 
     129            localName = getLocalName(elem) 
     130 
     131            if localName == prefix: 
     132                matches += getMatches(elem, prefix) 
     133            elif name == "Any" + prefix: 
     134                return None 
     135 
     136        return matches 
     137     
     138    @staticmethod 
     139    def _getMatches(root, prefix): 
     140 
     141        list = [] 
     142 
     143        for elem in root.getchildren(): 
     144            localName = getLocalName(elem) 
     145 
     146            if localName == prefix + "Match": 
     147                list += TargetMatch.getInstance(child, prefix) 
     148 
     149        return tuple(list) 
    71150     
    72151     
     
    81160          self.issuer = issuer 
    82161 
    83  
     162    def getInstance(self): 
     163        pass 
     164     
    84165class TargetMatch(XacmlBase): 
    85166    '''Represents the SubjectMatch, ResourceMatch, or ActionMatch XML  
     
    124205                    doc="the type of match for this target") 
    125206     
    126     def getInstance(self, root, prefix, xpathVersion): 
     207    @classmethod 
     208    def getInstance(cls, root, prefix, xpathVersion): 
    127209        '''Creates a TargetMatch by parsing a node, using the 
    128210        input prefix to determine whether this is a SubjectMatch,  
     
    138220        @return a new TargetMatch constructed by parsing 
    139221        ''' 
    140         raise NotImplementedError() 
     222 
     223        action = ["Subject", "Resource", "Action"].index(prefix) 
     224        if action not in self.__class__.types: 
     225            raise TypeError("Unknown TargetMatch type: %s" % prefix) 
     226 
     227        # function type 
     228        funcId = root.attrib["MatchId"] 
     229        factory = FunctionFactory.getTargetInstance() 
     230        try: 
     231            function = factory.createFunction(funcId) 
     232        except UnknownIdentifierException, e: 
     233            raise ParsingException("Unknown MatchId: %s" % e) 
     234         
     235        except FunctionTypeException, e: 
     236            # try to create an abstract function 
     237            try: 
     238                function = factory.createAbstractFunction(funcId, root) 
     239            except Exception, e: 
     240                raise ParsingException("invalid abstract function: %s" % e) 
     241             
     242        # Get the designator or selector being used, and the attribute 
     243        # value paired with it 
     244        for elem in root.getchildren(): 
     245            localName = getLocalName(elem) 
     246 
     247            if name == prefix + "AttributeDesignator": 
     248                eval = AttributeDesignator.getInstance(node, type) 
     249                 
     250            elif name == "AttributeSelector": 
     251                eval = AttributeSelector.getInstance(node) 
     252                 
     253            elif name == "AttributeValue": 
     254                try: 
     255                    attrValue = attrFactory.createValue(node) 
     256                except UnknownIdentifierException, e: 
     257                    raise ParsingException("Unknown Attribute Type: %s" % e) 
     258 
     259        # finally, check that the inputs are valid for this function 
     260        inputs = [attrValue, eval] 
     261        function.checkInputsNoBag(inputs) 
     262         
     263        return cls(type, function, eval, attributeValue) 
     264     
    141265 
    142266    def match(self, context): 
     
    230354        raise NotImplementedError() 
    231355     
    232      
     356       
    233357class FunctionBase(XacmlBase): 
    234358    FUNCTION_NS = "urn:oasis:names:tc:xacml:1.0:function:" 
     
    300424        an EvaluationResult representing the error 
    301425        ''' 
    302         it = params.iterator() 
    303426        index = 0 
    304427 
    305         while it.hasNext(): 
     428        for eval in params: 
    306429            # get and evaluate the next parameter 
    307             eval = it.next() 
    308430            result = eval.evaluate(context) 
    309431 
     
    317439             
    318440        return None 
    319      
     441 
     442# TODO: Condition classes - minimal implementation until opportunity to fully  
     443# implement    
     444class Function(XacmlBase): 
     445    def __init__(self, *arg, **kw): 
     446        raise NotImplementedError() 
     447 
     448    @classmethod 
     449    def getInstance(cls, root): 
     450        raise NotImplementedError() 
     451 
     452class BagFunction(FunctionBase): 
     453    def __init__(self, *arg, **kw): 
     454        raise NotImplementedError() 
     455 
     456class SetFunction(FunctionBase): 
     457    def __init__(self, *arg, **kw): 
     458        raise NotImplementedError() 
     459        
     460class ConditionBagFunction(BagFunction): 
     461    def __init__(self, *arg, **kw): 
     462        raise NotImplementedError() 
     463         
     464class ConditionSetFunction(FunctionBase): 
     465    def __init__(self, *arg, **kw): 
     466        raise NotImplementedError() 
     467         
     468class HigherOrderFunction(Function): 
     469    def __init__(self, *arg, **kw): 
     470        raise NotImplementedError() 
     471 
     472# TODO: Function classes - minimal implementation until opportunity to fully  
     473# implement                                     
     474class LogicalFunction(FunctionBase): 
     475 
     476    def __init__(self, *arg, **kw): 
     477        raise NotImplementedError() 
     478 
     479class NOfFunction(FunctionBase): 
     480     
     481    def __init__(self, *arg, **kw): 
     482        raise NotImplementedError() 
     483         
     484class NotFunction(FunctionBase): 
     485     
     486    def __init__(self, *arg, **kw): 
     487        raise NotImplementedError() 
     488         
     489class ComparisonFunction(FunctionBase): 
     490     
     491    def __init__(self, *arg, **kw): 
     492        raise NotImplementedError() 
    320493 
    321494class MatchFunction(FunctionBase): 
     
    424597           
    425598        return datatype 
    426      
     599 
     600class AddFunction(FunctionBase): 
     601     
     602    def __init__(self, *arg, **kw): 
     603        raise NotImplementedError() 
     604             
     605class SubtractFunction(FunctionBase): 
     606     
     607    def __init__(self, *arg, **kw): 
     608        raise NotImplementedError() 
     609             
     610class MultiplyFunction(FunctionBase): 
     611     
     612    def __init__(self, *arg, **kw): 
     613        raise NotImplementedError() 
     614             
     615class DivideFunction(FunctionBase): 
     616     
     617    def __init__(self, *arg, **kw): 
     618        raise NotImplementedError() 
     619             
     620class ModFunction(FunctionBase): 
     621     
     622    def __init__(self, *arg, **kw): 
     623        raise NotImplementedError() 
     624 
     625class AbsFunction(FunctionBase): 
     626     
     627    def __init__(self, *arg, **kw): 
     628        raise NotImplementedError() 
     629 
     630class RoundFunction(FunctionBase): 
     631     
     632    def __init__(self, *arg, **kw): 
     633        raise NotImplementedError() 
     634 
     635class FloorFunction(FunctionBase): 
     636     
     637    def __init__(self, *arg, **kw): 
     638        raise NotImplementedError() 
     639 
     640class DateMathFunction(FunctionBase): 
     641     
     642    def __init__(self, *arg, **kw): 
     643        raise NotImplementedError() 
     644 
     645class GeneralBagFunction(BagFunction): 
     646     
     647    def __init__(self, *arg, **kw): 
     648        raise NotImplementedError() 
     649 
     650class NumericConvertFunction(FunctionBase): 
     651     
     652    def __init__(self, *arg, **kw): 
     653        raise NotImplementedError() 
     654 
     655class StringNormalizeFunction(FunctionBase): 
     656     
     657    def __init__(self, *arg, **kw): 
     658        raise NotImplementedError() 
     659 
     660class GeneralSetFunction(SetFunction): 
     661     
     662    def __init__(self, *arg, **kw): 
     663        raise NotImplementedError() 
     664     
     665class MapFunction(Function):         
     666    supportedIdentifiers = () 
     667    NAME_MAP = FunctionBase.FUNCTION_NS + "map" 
     668     
     669    def __init__(self, *arg, **kw): 
     670        raise NotImplementedError() 
     671 
     672    @classmethod 
     673    def getInstance(cls, root): 
     674        raise NotImplementedError() 
     675     
     676class FunctionProxy(): 
     677 
     678    def getInstance(self, root): 
     679        raise NotImplementedError() 
     680 
     681class MapFunctionProxy(FunctionProxy): 
     682 
     683    def getInstance(self, root): 
     684        return MapFunction.getInstance(root) 
     685 
     686 
     687class UnknownIdentifierException(Exception): 
     688    pass 
     689 
     690class FunctionTypeException(Exception): 
     691    pass 
     692 
     693class ParsingException(Exception): 
     694    pass 
     695 
     696class FunctionFactory(XacmlBase): 
     697    '''Factory used to create all functions. There are three kinds of factories: 
     698    general, condition, and target. These provide functions that can be used 
     699    anywhere, only in a condition's root and only in a target (respectively). 
     700     
     701    Note that all functions, except for abstract functions, are singletons, so 
     702    any instance that is added to a factory will be the same one returned 
     703    from the create methods. This is done because most functions don't have 
     704    state, so there is no need to have more than one, or to spend the time 
     705    creating multiple instances that all do the same thing.''' 
     706 
     707    defaultFactoryProxy = StandardFunctionFactory()                  
     708             
     709    @classmethod 
     710    def getTargetInstance(cls): 
     711        '''Returns the default FunctionFactory that will only provide those 
     712        functions that are usable in Target matching. 
     713         
     714        @return a FunctionFactory for target functions''' 
     715        return cls.defaultFactoryProxy.getTargetFactory() 
     716        
     717    @classmethod  
     718    def getConditionInstance(cls):  
     719        '''Returns the default FunctionFactory that provides access to all the 
     720        functions. These Functions are a superset of the Condition functions. 
     721         
     722        @return a FunctionFactory for all functions 
     723        ''' 
     724        return cls.defaultFactoryProxy.getConditionFactory() 
     725     
     726    @classmethod 
     727    def getGeneralInstance(cls):  
     728        '''Sets the default factory. Note that this is just a place holder for 
     729        now, and will be replaced with a more useful mechanism soon.''' 
     730        return cls.defaultFactoryProxy.getGeneralFactory() 
     731     
     732     
     733    def addFunction(self, function): 
     734        '''Adds the function to the factory. Most functions have no state, so 
     735        the singleton model used here is typically desirable. The factory will 
     736        not enforce the requirement that a Target or Condition matching  
     737        function must be boolean. 
     738         
     739        @param function the Function to add to the factory 
     740        ''' 
     741        raise NotImplementedError() 
     742         
     743    def addAbstractFunction(self, functionProxy, identity): 
     744        '''Adds the abstract function proxy to the factory. This is used for 
     745        those functions which have state, or change behaviour (for instance 
     746        the standard map function, which changes its return type based on 
     747        how it is used).  
     748         
     749        @param proxy the FunctionProxy to add to the factory 
     750        @param identity the function's identifier 
     751        ''' 
     752        raise NotImplementedError()         
     753     
     754    def getSupportedFunctions(self): 
     755        '''Returns the function identifiers supported by this factory. 
     756         
     757        @return a Set of Strings''' 
     758        raise NotImplementedError() 
     759 
     760    def createFunction(self, identity): 
     761        '''Tries to get an instance of the specified function. 
     762         
     763        @param identity the name of the function 
     764        '''        
     765        raise NotImplementedError() 
     766     
     767    def createAbstractFunction(self, identity, root): 
     768        '''Tries to get an instance of the specified abstract function. 
     769         
     770        @param identity the name of the function 
     771        @param root the DOM root containing info used to create the function 
     772        ''' 
     773        raise NotImplementedError() 
     774 
     775 
     776class FunctionFactoryProxy(XacmlBase): 
     777    '''A simple proxy interface used to install new FunctionFactorys. 
     778    The three kinds of factory (Target, Condition, and General) are tied 
     779    together in this interface because implementors writing new factories 
     780    should always implement all three types and provide them together''' 
     781    def getTargetFactory(): 
     782        raise NotImplementedError() 
     783 
     784    def getConditionFactory(): 
     785        raise NotImplementedError() 
     786 
     787    def getGeneralFactory(): 
     788        raise NotImplementedError() 
     789 
     790 
     791class BasicFunctionFactoryProxy(FunctionFactoryProxy): 
     792    '''A simple utility class that manages triples of function factories.''' 
     793     
     794    # the triple of factories 
     795    targetFactory = None 
     796    conditionFactory = None 
     797    generalFactory = None 
     798 
     799    def __init__(targetFactory, conditionFactory, generalFactory):  
     800        '''Creates a new proxy. 
     801         
     802        @param targetFactory the target factory provided by this proxy 
     803        @param conditionFactory the target condition provided by this proxy 
     804        @param generalFactory the general factory provided by this proxy 
     805        ''' 
     806        self.targetFactory = targetFactory 
     807        self.conditionFactory = conditionFactory 
     808        self.generalFactory = generalFactory 
     809     
     810    def getTargetFactory(): 
     811        return targetFactory 
     812 
     813    def getConditionFactory(): 
     814        return conditionFactory 
     815 
     816    def getGeneralFactory(): 
     817        return generalFactory 
     818     
     819 
     820class BaseFunctionFactory(FunctionFactory): 
     821    '''This is a basic implementation of <code>FunctionFactory</code>. It 
     822    implements the insertion and retrieval methods, but it doesn't actually 
     823    setup the factory with any functions. It also assumes a certain model 
     824    with regard to the different kinds of functions (Target, Condition, and 
     825    General). For this reason, you may want to re-use this class, or you  
     826    may want to extend FunctionFactory directly, if you're writing a new 
     827    factory implementation. 
     828     
     829    Note that while this class is thread-safe on all creation methods, it 
     830    is not safe to add support for a new function while creating an instance 
     831    of a function. This follows from the assumption that most people will 
     832    initialize these factories up-front, and then start processing without 
     833    ever modifying the factories. If you need these mutual operations to 
     834    be thread-safe, then you should write a wrapper class that implements 
     835    the right synchronization. 
     836    ''' 
     837     
     838    def __init__(self,  
     839                 superset=None,  
     840                 supportedFunctions=[], 
     841                 supportedAbstractFunctions={}): 
     842        '''Sets a "superset factory". This is useful since 
     843        the different function factories (Target, Condition, and General) 
     844        have a superset relationship (Condition functions are a superset 
     845        of Target functions, etc.). Adding a function to this factory will 
     846        automatically add the same function to the superset factory. 
     847 
     848        Constructor that defines the initial functions supported by this 
     849        factory but doesn't use a superset factory. 
     850 
     851        Constructor that defines the initial functions supported by this 
     852        factory but doesn't use a superset factory. 
     853 
     854        Constructor that defines the initial functions supported by this 
     855        factory and uses a superset factory. Note that the functions 
     856        supplied here are not propagated up to the superset factory, so 
     857        you must either make sure the superset factory is correctly 
     858        initialized or use BaseFunctionFactory(FunctionFactory) 
     859        and then manually add each function. 
     860        
     861        @param supportedFunctions a Set of Functions 
     862        @param supportedAbstractFunctions a mapping from URI to 
     863                                          FunctionProxy 
     864         
     865        @param supportedFunctions a Set of Functions 
     866        @param supportedAbstractFunctions a mapping from URI to FunctionProxy 
     867         
     868        @param superset the superset factory or None''' 
     869         
     870        # the backing maps for the Function objects 
     871        self.functionMap = {} 
     872     
     873        # the superset factory chained to this factory 
     874        self.superset = superset 
     875      
     876        for function in supportedFunctions: 
     877            self.functionMap[function.functionId] = function 
     878         
     879        for id in supportedAbstractFunctions.keys(): 
     880            proxy = supportedAbstractFunctions.get(id) 
     881            self.functionMap[id] = proxy 
     882  
     883    def addFunction(self, function): 
     884        '''Adds the function to the factory. Most functions have no state, so 
     885        the singleton model used here is typically desirable. The factory will 
     886        not enforce the requirement that a Target or Condition matching  
     887        function must be boolean. 
     888         
     889        @param function the Function to add to the factory 
     890        @raise TypeError if the function's identifier is already used or if the 
     891        function is non-boolean (when this is a Target or Condition factory) 
     892        ''' 
     893        id = function.functionId 
     894 
     895        # make sure this doesn't already exist 
     896        if id in self.functionMap: 
     897            raise TypeError("function %s already exists" % id) 
     898 
     899        # add to the superset factory 
     900        if self.superset != None: 
     901            self.superset.addFunction(function) 
     902 
     903        # Add to this factory 
     904        self.functionMap[id] = function 
     905     
     906         
     907    def addAbstractFunction(self, proxy, id): 
     908        '''Adds the abstract function proxy to the factory. This is used for 
     909        those functions which have state, or change behaviour (for instance 
     910        the standard map function, which changes its return type based on 
     911        how it is used).  
     912         
     913        @param proxy: the FunctionProxy to add to the factory 
     914        @param id: the function's identifier 
     915         
     916        @raise TypeError if the function's identifier is already used''' 
     917 
     918        # make sure this doesn't already exist 
     919        if id in self.functionMap: 
     920            raise TypeError("function already exists") 
     921 
     922        # add to the superset factory 
     923        if self.superset != None: 
     924            self.superset.addAbstractFunction(proxy, id) 
     925 
     926        # finally, add to this factory 
     927        functionMap[id] = proxy 
     928     
     929 
     930    def getSupportedFunctions(self):  
     931        '''Returns the function identifiers supported by this factory. 
     932         
     933        @return a list of strings''' 
     934     
     935        functions = self.functionMap.keys() 
     936 
     937        if self.superset != None: 
     938            functions += self.superset.getSupportedFunctions() 
     939 
     940        return functions 
     941     
     942 
     943    def createFunction(self, identity): 
     944        '''Tries to get an instance of the specified function. 
     945         
     946        @param identity the name of the function 
     947         
     948        @throws UnknownIdentifierException if the name isn't known 
     949        @throws FunctionTypeException if the name is known to map to an 
     950                                      abstract function, and should therefore 
     951                                      be created through createAbstractFunction 
     952        ''' 
     953        entry = self.functionMap.get(identity) 
     954        if entry is not None: 
     955            if isinstance(entry, Function):  
     956                return entry 
     957            else: 
     958                # this is actually a proxy, which means the other create 
     959                # method should have been called 
     960                raise FunctionTypeException("function is abstract")     
     961        else: 
     962            # we couldn't find a match 
     963            raise UnknownIdentifierException("functions of type %s are not " 
     964                                             "supported by this factory" %  
     965                                             identity)         
     966     
     967     
     968    def createAbstractFunction(identity, root): 
     969        '''Tries to get an instance of the specified abstract function. 
     970         
     971        @param identity the name of the function 
     972        @param root the DOM root containing info used to create the function 
     973        @param xpathVersion the version specified in the containing policy, or 
     974                            None if no version was specified 
     975         
     976        @throws UnknownIdentifierException if the name isn't known 
     977        @throws FunctionTypeException if the name is known to map to a 
     978                                      concrete function, and should therefore 
     979                                      be created through createFunction 
     980        @throws ParsingException if the function can't be created with the 
     981                                 given inputs''' 
     982     
     983        entry = self.functionMap.get(identity) 
     984        if entry is not None: 
     985            if isinstance(entry, FunctionProxy):  
     986                try:  
     987                    return entry.getInstance(root) 
     988                 
     989                except Exception, e: 
     990                    raise ParsingException("Couldn't create abstract function " 
     991                                           "%s: %s" % identity, e)       
     992            else: 
     993                # this is actually a concrete function, which means that 
     994                # the other create method should have been called 
     995                raise FunctionTypeException("function is concrete") 
     996             
     997        else: 
     998            raise UnknownIdentifierException("Abstract functions of type %s " 
     999                                             "are not supported by this " 
     1000                                             "factory" % identity) 
     1001 
     1002 
     1003class StandardFunctionFactory(BaseFunctionFactory): 
     1004    '''This factory supports the standard set of functions specified in XACML 
     1005    1.0 and 1.1. It is the default factory used by the system, and imposes 
     1006    a singleton pattern insuring that there is only ever one instance of 
     1007    this class. 
     1008    <p> 
     1009    Note that because this supports only the standard functions, this 
     1010    factory does not allow the addition of any other functions. If you call 
     1011    addFunction on an instance of this class, an exception 
     1012    will be thrown. If you need a standard factory that is modifiable, 
     1013    you can either create a new BaseFunctionFactory (or some 
     1014    other implementation of FunctionFactory) populated with 
     1015    the standard functions from getStandardFunctions or 
     1016    you can use getNewFactoryProxy to get a proxy containing 
     1017    a new, modifiable set of factories.''' 
     1018 
     1019 
     1020    # the three singleton instances 
     1021    targetFactory = None 
     1022    conditionFactory = None 
     1023    generalFactory = None 
     1024 
     1025    # the three function sets/maps that we use internally 
     1026    targetFunctions = None 
     1027    conditionFunctions = None 
     1028    generalFunctions = None 
     1029 
     1030    targetAbstractFunctions = None 
     1031    conditionAbstractFunctions = None 
     1032    generalAbstractFunctions = None 
     1033 
     1034    # the set/map used by each singleton factory instance 
     1035    supportedFunctions = None 
     1036    supportedAbstractFunctions = None 
     1037 
     1038     
     1039    def __init__(self, supportedFunctions, supportedAbstractFunctions):  
     1040        '''Creates a new StandardFunctionFactory, making sure that the default 
     1041        maps are initialized correctly. Standard factories can't be modified, 
     1042        so there is no notion of supersetting since that's only used for 
     1043        correctly propagating new functions.''' 
     1044        super(StandardFunctionFactory, self).__init__(supportedFunctions,  
     1045                                                    supportedAbstractFunctions) 
     1046 
     1047        self.supportedFunctions = supportedFunctions 
     1048        self.supportedAbstractFunctions = supportedAbstractFunctions 
     1049     
     1050 
     1051     
     1052     
     1053    def _initTargetFunctions(self):  
     1054        '''Private initializer for the target functions. This is only ever 
     1055        called once.''' 
     1056        log.info("Initializing standard Target functions") 
     1057 
     1058        # Emulate a list with unique items using a dict with only the keys set 
     1059        StandardFunctionFactory.targetFunctions = {} 
     1060 
     1061        # add EqualFunction 
     1062        StandardFunctionFactory.targetFunctions.fromkeys( 
     1063                                    EqualFunction.supportedIdentifiers) 
     1064 
     1065        # add LogicalFunction 
     1066        StandardFunctionFactory.targetFunctions.fromkeys( 
     1067                                    LogicalFunction.supportedIdentifiers) 
     1068         
     1069        # add NOfFunction 
     1070        StandardFunctionFactory.targetFunctions.fromkeys( 
     1071                                    NOfFunction.supportedIdentifiers) 
     1072         
     1073        # add NotFunction 
     1074        StandardFunctionFactory.targetFunctions.fromkeys( 
     1075                                    NotFunction.supportedIdentifiers) 
     1076         
     1077        # add ComparisonFunction 
     1078        StandardFunctionFactory.targetFunctions.fromkeys( 
     1079                                    ComparisonFunction.supportedIdentifiers) 
     1080 
     1081        # add MatchFunction 
     1082        StandardFunctionFactory.targetFunctions.fromkeys( 
     1083                                    MatchFunction.supportedIdentifiers) 
     1084 
     1085        StandardFunctionFactory.targetAbstractFunctions = {} 
     1086     
     1087     
     1088    def _initConditionFunctions(self):  
     1089        '''Private initializer for the condition functions. This is only ever 
     1090        called once.''' 
     1091        log.info("Initializing standard Condition functions") 
     1092 
     1093        if StandardFunctionFactory.targetFunctions is None: 
     1094            self._initTargetFunctions() 
     1095 
     1096        StandardFunctionFactory.conditionFunctions = \ 
     1097            StandardFunctionFactory.targetFunctions.copy() 
     1098 
     1099        # add condition functions from BagFunction 
     1100        conditionFunctions.fromkeys(ConditionBagFunction.supportedIdentifiers) 
     1101         
     1102        # add condition functions from SetFunction 
     1103        conditionFunctions.fromkeys(ConditionSetFunction.supportedIdentifiers) 
     1104         
     1105        # add condition functions from HigherOrderFunction 
     1106        conditionFunctions.fromkeys(HigherOrderFunction.supportedIdentifiers) 
     1107 
     1108        StandardFunctionFactory.conditionAbstractFunctions = \ 
     1109            StandardFunctionFactory.targetAbstractFunctions.copy() 
     1110     
     1111 
     1112    def _initGeneralFunctions(self):      
     1113        '''Private initializer for the general functions. This is only ever 
     1114        called once.''' 
     1115     
     1116        log.info("Initializing standard General functions") 
     1117 
     1118        if StandardFunctionFactory.conditionFunctions is None: 
     1119            self._initConditionFunctions() 
     1120 
     1121        StandardFunctionFactory.generalFunctions = \ 
     1122            StandardFunctionFactory.conditionFunctions.copy() 
     1123 
     1124        # add AddFunction 
     1125        StandardFunctionFactory.generalFunctions.fromkeys( 
     1126            AddFunction.supportedIdentifiers) 
     1127             
     1128        # add SubtractFunction 
     1129        StandardFunctionFactory.generalFunctions.fromkeys( 
     1130            SubtractFunction.supportedIdentifiers) 
     1131             
     1132        # add MultiplyFunction 
     1133        StandardFunctionFactory.generalFunctions.fromkeys( 
     1134            MultiplyFunction.supportedIdentifiers) 
     1135             
     1136        # add DivideFunction 
     1137        StandardFunctionFactory.generalFunctions.fromkeys( 
     1138            DivideFunction.supportedIdentifiers) 
     1139             
     1140        # add ModFunction 
     1141        StandardFunctionFactory.generalFunctions.fromkeys( 
     1142            ModFunction.supportedIdentifiers) 
     1143         
     1144        # add AbsFunction 
     1145        StandardFunctionFactory.generalFunctions.fromkeys( 
     1146            AbsFunction.supportedIdentifiers) 
     1147             
     1148        # add RoundFunction 
     1149        StandardFunctionFactory.generalFunctions.fromkeys( 
     1150            RoundFunction.supportedIdentifiers) 
     1151             
     1152        # add FloorFunction 
     1153        StandardFunctionFactory.generalFunctions.fromkeys( 
     1154            FloorFunction.supportedIdentifiers) 
     1155         
     1156        # add DateMathFunction 
     1157        StandardFunctionFactory.generalFunctions.fromkeys( 
     1158            DateMathFunction.supportedIdentifiers) 
     1159             
     1160        # add general functions from BagFunction 
     1161        StandardFunctionFactory.generalFunctions.fromkeys( 
     1162            GeneralBagFunction.supportedIdentifiers) 
     1163             
     1164        # add NumericConvertFunction 
     1165        StandardFunctionFactory.generalFunctions.fromkeys( 
     1166            NumericConvertFunction.supportedIdentifiers) 
     1167             
     1168        # add StringNormalizeFunction 
     1169        StandardFunctionFactory.generalFunctions.fromkeys( 
     1170            StringNormalizeFunction.supportedIdentifiers) 
     1171         
     1172        # add general functions from SetFunction 
     1173        StandardFunctionFactory.generalFunctions.fromkeys( 
     1174            GeneralSetFunction.supportedIdentifiers) 
     1175             
     1176        StandardFunctionFactory.generalAbstractFunctions = \ 
     1177            StandardFunctionFactory.conditionAbstractFunctions.copy() 
     1178 
     1179        # Add the map function's proxy 
     1180        StandardFunctionFactory.generalAbstractFunctions[ 
     1181                                    MapFunction.NAME_MAP] = MapFunctionProxy() 
     1182     
     1183    @classmethod  
     1184    def getTargetFactory(cls):  
     1185        '''Returns a FunctionFactory that will only provide those functions  
     1186        that are usable in Target matching. This method enforces a singleton 
     1187        model, meaning that this always returns the same instance, creating 
     1188        the factory if it hasn't been requested before. This is the default 
     1189        model used by the FunctionFactory, ensuring quick 
     1190        access to this factory. 
     1191         
     1192        @return a FunctionFactory for target functions''' 
     1193        if StandardFunctionFactory.targetFactory is None:  
     1194            if StandardFunctionFactory.targetFunctions is None: 
     1195                StandardFunctionFactory._initTargetFunctions() 
     1196                 
     1197            if StandardFunctionFactory.targetFactory is None: 
     1198                StandardFunctionFactory.targetFactory=StandardFunctionFactory( 
     1199                            StandardFunctionFactory.targetFunctions, 
     1200                            StandardFunctionFactory.targetAbstractFunctions) 
     1201         
     1202        return StandardFunctionFactory.targetFactory 
     1203 
     1204     
     1205    @classmethod 
     1206    def getConditionFactory(cls):  
     1207        '''Returns a FuntionFactory that will only provide those functions that 
     1208        are usable in the root of the Condition. These Functions are a 
     1209        superset of the Target functions. This method enforces a singleton 
     1210        model, meaning that this always returns the same instance, creating 
     1211        the factory if it hasn't been requested before. This is the default 
     1212        model used by the FunctionFactory, ensuring quick 
     1213        access to this factory. 
     1214     
     1215        @return a FunctionFactory for condition functions 
     1216        ''' 
     1217        if StandardFunctionFactory.conditionFactory is None: 
     1218            if StandardFunctionFactory.conditionFunctions is None: 
     1219                StandardFunctionFactory._initConditionFunctions() 
     1220                 
     1221            if StandardFunctionFactory.conditionFactory is None: 
     1222                StandardFunctionFactory.conditionFactory = \ 
     1223                    StandardFunctionFactory( 
     1224                           StandardFunctionFactory.conditionFunctions, 
     1225                           StandardFunctionFactory.conditionAbstractFunctions)        
     1226 
     1227        return StandardFunctionFactory.conditionFactory 
     1228     
     1229 
     1230    @classmethod 
     1231    def getGeneralFactory(cls):  
     1232        '''Returns a FunctionFactory that provides access to all the functions. 
     1233        These Functions are a superset of the Condition functions. This method 
     1234        enforces a singleton model, meaning that this always returns the same 
     1235        instance, creating the factory if it hasn't been requested before. 
     1236        This is the default model used by the FunctionFactory, 
     1237        ensuring quick access to this factory. 
     1238         
     1239        @return a FunctionFactory for all functions''' 
     1240     
     1241        if StandardFunctionFactory.generalFactory is None: 
     1242            if StandardFunctionFactory.generalFunctions is None: 
     1243                StandardFunctionFactory._initGeneralFunctions() 
     1244                 
     1245                StandardFunctionFactory.generalFactory = \ 
     1246                    StandardFunctionFactory( 
     1247                            StandardFunctionFactory.generalFunctions, 
     1248                            StandardFunctionFactory.generalAbstractFunctions) 
     1249                 
     1250        return StandardFunctionFactory.generalFactory 
     1251 
     1252 
     1253    def getStandardFunctions(self): 
     1254        '''Returns the set of functions that this standard factory supports. 
     1255         
     1256        @return a Set of Functions''' 
     1257        return tuple(self.supportedFunctions.keys()) 
     1258         
     1259    def getStandardAbstractFunctions(self): 
     1260        '''Returns the set of abstract functions that this standard factory 
     1261        supports as a mapping of identifier to proxy. 
     1262         
     1263        @return a Map mapping URIs to FunctionProxys''' 
     1264        return tuple(self.supportedAbstractFunctions.keys()) 
     1265     
     1266     
     1267    @classmethod 
     1268    def getNewFactoryProxy(cls):  
     1269        '''A convenience method that returns a proxy containing newly created 
     1270        instances of BaseFunctionFactorys that are correctly 
     1271        supersetted and contain the standard functions and abstract functions. 
     1272        These factories allow adding support for new functions. 
     1273         
     1274        @return a new proxy containing new factories supporting the standard 
     1275        functions''' 
     1276         
     1277        general = StandardFunctionFactory.getGeneralFactory() 
     1278             
     1279        newGeneral=BaseFunctionFactory(general.getStandardFunctions(), 
     1280                                       general.getStandardAbstractFunctions()) 
     1281 
     1282        condition = StandardFunctionFactory.getConditionFactory() 
     1283         
     1284        newCondition = BaseFunctionFactory(newGeneral, 
     1285                                    condition.getStandardFunctions(), 
     1286                                    condition.getStandardAbstractFunctions()) 
     1287 
     1288        target = StandardFunctionFactory.getTargetFactory() 
     1289        newTarget = BaseFunctionFactory(newCondition, 
     1290                                    target.getStandardFunctions(), 
     1291                                    target.getStandardAbstractFunctions()) 
     1292 
     1293        return BasicFunctionFactoryProxy(newTarget, newCondition, newGeneral) 
     1294     
     1295 
     1296     
     1297     
     1298    def addFunction(self, function): 
     1299        '''Always throws an exception, since support for new functions may not  
     1300        be added to a standard factory. 
     1301         
     1302        @param function the Function to add to the factory        
     1303        @raise NotImplementedError''' 
     1304     
     1305        raise NotImplementedError("a standard factory cannot support new " 
     1306                                  "functions") 
     1307     
     1308     
     1309    def addAbstractFunction(self, proxy, identity): 
     1310        '''Always throws an exception, since support for new functions may not  
     1311        be added to a standard factory. 
     1312         
     1313        @param proxy the FunctionProxy to add to the factory 
     1314        @param identity the function's identifier 
     1315         
     1316        @raise NotImplementedError always''' 
     1317        raise NotImplementedError("a standard factory cannot support new " 
     1318                                  "functions") 
     1319 
    4271320     
    4281321class Status(XacmlBase): 
     
    5061399    '''Consists of a condition, an effect, and a target. 
    5071400    ''' 
    508     def __init__(self): 
     1401    def __init__(self, conditions=[], effect=DenyEffect(), target=None): 
    5091402        # Conditions are statements about attributes that upon evaluation  
    5101403        # return either True, False, or Indeterminate. 
    511         self.conditions = [] 
     1404        self.conditions = conditions 
    5121405         
    5131406        # Effect is the intended consequence of the satisfied rule. It can  
    5141407        # either take the value Permit or Deny. 
    515         self.effect = DenyEffect() 
     1408        self.effect = effect 
    5161409       
    5171410        # Target, as in the case of a policy, helps in determining whether or  
     
    5191412        # this is also similar to how it is done in the case of a target for a  
    5201413        # policy. 
    521         self.target = Target() 
     1414        self.target = target 
     1415         
     1416    @classmethod 
     1417    def getInstance(cls, elem): 
     1418        root = elem.getroot() 
     1419        return Rule(conditions=conditions, effect=effect, target=target) 
    5221420           
    523           
     1421class Attribute(XacmlBase): 
     1422    def __init__(self, id, type=None, issuer=None, issueInstant=None, value=None): 
     1423        self.id = id 
     1424        self.type = type or value.__class__ 
     1425        self.issuer = issuer 
     1426        self.issueInstant = issueInstant 
     1427        self.value = value 
     1428 
     1429        
    5241430class Request(XacmlBase): 
    5251431    '''XACML Request XacmlBase 
    5261432     
    5271433    TODO: refactor from this initial placeholder''' 
    528     def __init__(self): 
    529           self.subject = Subject() 
    530           self.resource = Resource() 
    531           self.action = Action() 
    532           self.environment = Environment() 
    533   
    534 class PEP(XacmlBase): 
     1434    def __init__(self, subject, resource, action=None, environment={}): 
     1435          self.subject = subject 
     1436          self.resource = resource 
     1437          self.action = action 
     1438          self.environment = environment 
     1439 
     1440class Response(XacmlBase): 
    5351441    pass 
    536           
    537 class PDP(PDPInterface): 
     1442 
     1443 
     1444class PDP(XacmlBase): 
    5381445    '''Modify PDPInterface to use the four XACML request designators: subject, 
    5391446    resource, action and environment 
     
    5431450          pass 
    5441451     
    545     def accessPermitted(self, request): 
     1452    def evaluate(self, request): 
    5461453          '''Make access control decision - override this in a derived class to 
    5471454          implement the decision logic but this method may be called within 
    5481455          the derived method to check input types 
    5491456           
    550           @param subject: entity making the request e.g. user or user agent 
    551           @type subject: Subject 
    552           @param resource: resource to be accessed 
    553           @type resource: Resource 
    554           @param action: action to be carried out on the resource 
    555           @type action: Action 
    556           @param environ: environment settings 
    557           @type environ: Environment 
    558           @raise TypeError: incorrect inputs 
     1457          @param request: request object containing the subject, resource, 
     1458          action and environment 
     1459          @type request: ndg.security.common.authz.xacml.Request 
     1460          @return reponse object 
     1461          @rtype: ndg.security.common.authz.xacml.Response 
    5591462          ''' 
    560           if not isinstance(subject, Subject): 
    561               raise TypeError("Input subject must of type %r" % Subject) 
    562  
    563           if not isinstance(resource, Resource): 
    564               raise TypeError("Input resource must of type %r" % Resource) 
    565  
    566           if not isinstance(action, Action): 
    567               raise TypeError("Input action must of type %r" % Action) 
    568  
    569           if not isinstance(environment, Environment): 
    570               raise TypeError("Input environment must of type %r" % Environment) 
    571            
    572           # Default to denied 
    573           return False 
     1463          raise NotImplementedError() 
    5741464 
    5751465 
     
    6061496class EvaluationCtx(object): 
    6071497 
    608     # 
    6091498    # The standard URI for listing a resource's id 
    610     #  
    6111499    RESOURCE_ID ="urn:oasis:names:tc:xacml:1.0:resource:resource-id" 
    6121500 
    613     # 
    6141501    # The standard URI for listing a resource's scope 
    615     #  
    6161502    RESOURCE_SCOPE = "urn:oasis:names:tc:xacml:1.0:resource:scope" 
    6171503 
    618     # 
    6191504    # Resource scope of Immediate (only the given resource) 
    620     #  
    6211505    SCOPE_IMMEDIATE = 0 
    6221506 
    623     # 
    6241507    # Resource scope of Children (the given resource and its direct 
    6251508    # children) 
    626     #  
    6271509    SCOPE_CHILDREN = 1 
    6281510 
    629     # 
    6301511    # Resource scope of Descendants (the given resource and all descendants 
    6311512    # at any depth or distance) 
    632     #  
    6331513    SCOPE_DESCENDANTS = 2 
    6341514     
     
    7741654    '''Represents the XACML ApplyType and ConditionType XML types.''' 
    7751655 
    776     def __init__(self, function, evals, bagFunction=None, isCondition): 
     1656    def __init__(self, function, evals, bagFunction=None, isCondition=False): 
    7771657        '''Constructs an Apply object. Throws an 
    7781658        IllegalArgumentException if the given parameter list 
     
    7841664        to the function, each of which is an Evaluatable 
    7851665        @param bagFunction the higher-order function to use 
    786         @param isCondition true if this Apply is a Condition, False otherwise 
     1666        @param isCondition Rrue if this Apply is a Condition, False otherwise 
    7871667        ''' 
    7881668     
     
    8191699        raise NotImplementedError() 
    8201700          
    821     def getInstance(self, root, factory=None, isCondition=False, xpathVersion): 
     1701    def getInstance(self,  
     1702                    root,  
     1703                    factory=None,  
     1704                    isCondition=False,  
     1705                    xpathVersion=None): 
    8221706        '''Returns an instance of Apply based on the given DOM root. 
    8231707         
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/authz/__init__.py

    r5155 r5157  
    1515from ndg.security.server.wsgi import NDGSecurityPathFilter 
    1616from ndg.security.common.X509 import X500DN 
    17  
    18  
     17from ndg.security.common.authz.xacml import Request, Subject, Attribute, Policy 
     18from ndg.security.common.authz.xacml import PDP as XacmlPDP 
    1919from ndg.security.server.wsgi import NDGSecurityMiddlewareBase, \ 
    2020    NDGSecurityMiddlewareConfigError 
     21 
    2122 
    2223# TODO: move this class to separate resource constraint module 
     
    3435    NDGSecurityMiddlewareConfigError 
    3536 
    36 class Subject(object): 
    37     def __init__(self): 
    38         self.sessionManagerURI = None 
    39         self.sessionManagerEnvironKey = None 
    40         self.userID = None 
    41          
    42         # TODO: may need to refactor out as attributes can be derived from the 
    43         # user's wallet held be the Session Manager 
    44         self.attributes = [] 
    45  
    4637class Action(object): 
    4738    pass 
     
    4940class Environment(object): 
    5041    pass 
    51          
    52 class PDP(PDPInterface): 
    53     def __init__(self, *arg, **kw): 
    54         pass 
    5542 
    56     def accessPermitted(self, subject, resource, action, environ, **kw): 
     43from elementtree import ElementTree as ET 
     44        
     45class PDP(XacmlPDP): 
     46    def __init__(self, policyFilePath=None): 
     47        if policyFilePath: 
     48            elem = ET.parse(policyFilePath) 
     49            root = elem.getroot() 
     50            self.policy = Policy.getInstance(root) 
     51        else: 
     52            self.policy = Policy() 
     53 
     54    def evaluate(self, request): 
    5755        '''Make access control decision''' 
    5856        if action is None: 
     
    6866             
    6967        return False 
    70  
    71     __call__ = accessPermitted 
    7268 
    7369         
     
    8884                               doc='boolean to indicate is user logged in') 
    8985 
    90     def __init__(self, app, global_conf, **app_conf): 
    91         super(PEPMiddleware, self).__init__(app, global_conf, **app_conf) 
    92         self.pdp = PDP() 
     86    def __init__(self, app, global_conf, prefix='', **app_conf): 
     87         
     88        pdpCfg = {} 
     89        pdpCfgPfx = prefix + 'pdp.' 
     90        pdpCfgLen = len(pdpCfgPfx) 
     91        for k,v in app_conf.items(): 
     92            if k.startswith(pdpCfgPfx): 
     93                pdpCfg[k[pdpCfgLen:]] = app_conf.pop(k) 
     94                  
     95        self.pdp = PDP(**pdpCfg) 
     96 
     97        super(PEPMiddleware, self).__init__(app,  
     98                                            global_conf,  
     99                                            prefix=prefix,  
     100                                            **app_conf) 
     101         
    93102         
    94103    @NDGSecurityPathFilter.initCall 
     
    116125        resource = self.environ.get('ndg.security.server.wsgi.pep.resource') or \ 
    117126            Resource(self.pathInfo) 
    118         subject = Subject() 
    119         subject.userID = self.environ.get('REMOTE_USER') 
    120         subject.attributes += ['someAttribute'] 
    121         status = self.pdp(subject, resource, None, None) 
     127         
     128        session = self.environ[self.sessionKey] 
     129        user = Attribute(id='userId', value=session['username']) 
     130        sessionManager = Attribute(id='sessionManagerURI',  
     131                                   value=session['sessionManagerURI']) 
     132        role = Attribute(id='role', value='someAttribute') 
     133        subject = Subject(attributes={user.id: user,  
     134                                      sessionManager.id: sessionManager, 
     135                                      role.id: role}) 
     136        request = Request(subject, resource, environment=self.environ) 
     137        response = self.pdp.evaluate(request) 
    122138        return status 
    123139     
     
    164180                       PEPMiddleware.filter_app_factory,  
    165181                       global_conf, 
     182                       prefix=prefix, 
    166183                       **app_conf) 
    167184         
  • TI12-security/trunk/python/ndg.security.test/ndg/security/test/integration/authz/securedapp.ini

    r5155 r5157  
    4848paste.filter_app_factory=ndg.security.server.wsgi.authz:AuthorizationMiddleware.filter_app_factory 
    4949prefix = authz. 
     50authz.pdp.policyFilePath = %(here)s/policy.xml 
    5051#authz.pep.pathMatchList = /test_securedURI 
    5152 
Note: See TracChangeset for help on using the changeset viewer.