source: TI12-security/trunk/ndg_xacml/ndg/xacml/parsers/etree/attributevaluereader.py @ 7661

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/ndg_xacml/ndg/xacml/parsers/etree/attributevaluereader.py@7661
Revision 7661, 6.3 KB checked in by pjkersha, 10 years ago (diff)

ndg_xacml:

  • added support for custom AttributeValue? DataTypes? - this means that the ESGF GroupRole? attribute type can be added directly into XACML policies.
  • TODO: add support for adding custom functions so that a PDP can correctly apply rules based on custom types like the ESGF GroupRole?.
  • Property svn:keywords set to Id
Line 
1"""NDG XACML ElementTree based reader for AttributeValue type
2
3NERC DataGrid
4"""
5__author__ = "P J Kershaw"
6__date__ = "16/03/10"
7__copyright__ = "(C) 2010 Science and Technology Facilities Council"
8__contact__ = "Philip.Kershaw@stfc.ac.uk"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = "$Id$"
12from ndg.xacml.core.attributevalue import (AttributeValue, 
13                                           AttributeValueClassFactory)
14from ndg.xacml.parsers import XMLParseError
15from ndg.xacml.parsers.etree import QName
16from ndg.xacml.parsers.etree.expressionreader import ExpressionReader
17from ndg.xacml.utils import VettedDict
18
19
20class AttributeValueReader(ExpressionReader):
21    '''ElementTree based XACML AttributeValue type parser
22   
23    @cvar TYPE: XACML class type that this reader will read values into
24    @type TYPE: abc.ABCMeta
25   
26    @cvar FACTORY: factory function for returning an Attribute value type for a
27    given XACML Attribute value URI
28    @type FACTORY: ndg.xacml.core.attributevalue.AttributeValueClassFactory
29    '''
30    TYPE = AttributeValue
31    FACTORY = AttributeValueClassFactory()
32   
33    def __call__(self, obj):
34        """Parse *AttributeValue type element - override this method instead of
35        _parseExtension since AttributeValue class is virtual.  A sub-type can
36        be instantiated only once the data type attribute is parsed
37       
38        @param obj: input object to parse
39        @type obj: ElementTree Element, or stream object
40        @return: new XACML attribute value instance
41        @rtype: ndg.xacml.core.attributevalue.AttributeValue derived type
42        @raise XMLParseError: error reading element       
43        """
44        elem = super(AttributeValueReader, self)._parse(obj)
45       
46        xacmlType = self.__class__.TYPE
47        localName = QName.getLocalPart(elem.tag)
48        if localName != xacmlType.ELEMENT_LOCAL_NAME:
49            raise XMLParseError("No \"%s\" element found" % 
50                                xacmlType.ELEMENT_LOCAL_NAME)
51           
52        # Unpack *required* attributes from top-level element
53        elemAttributeValues = []
54        for attributeName in (xacmlType.DATA_TYPE_ATTRIB_NAME,):
55            attributeValue = elem.attrib.get(attributeName)
56            if attributeValue is None:
57                raise XMLParseError('No "%s" attribute found in "%s" element' %
58                                    (attributeName, 
59                                     xacmlType.ELEMENT_LOCAL_NAME))
60               
61            elemAttributeValues.append(attributeValue)
62             
63        attributeValueClass = self.__class__.FACTORY(elemAttributeValues[0])
64        if attributeValueClass is None:
65            raise XMLParseError("No Attribute Value class available for "
66                                "parsing %r type" % elemAttributeValues[0])
67           
68        attributeValue = attributeValueClass()
69        attributeValue.dataType = elemAttributeValues[0]
70        self._parseExtension(elem, attributeValue)
71       
72        return attributeValue
73   
74    def _parseExtension(self, elem, attributeValue):
75        """Parse XML Attribute value element
76       
77        @param elem: ElementTree XML element
78        @type elem: xml.etree.Element
79       
80        @param attributeValue: attribute selector to be updated with parsed
81        values
82        @type attributeValue: ndg.xacml.core.attributevalue.AttributeValue
83       
84        @raise XMLParseError: error parsing attribute ID XML attribute
85        """
86        reader = DataTypeReaderClassFactory.getReader(attributeValue)
87        reader.parse(elem, attributeValue)
88       
89
90class ETreeDataTypeReaderBase(object): 
91    @classmethod
92    def parse(cls, elem, attributeValue):
93        if elem.text is None:
94            raise XMLParseError('No attribute value element found parsing %r' % 
95                                AttributeValueReader.TYPE.ELEMENT_LOCAL_NAME) 
96           
97        attributeValue.value = elem.text
98
99       
100class ETreeDataTypeReaderClassMap(VettedDict):
101    """Specialised dictionary to hold mappings of XACML AttributeValue DataTypes
102    and their equivalent ElementTree reader classes
103    """
104   
105    def __init__(self):
106        """Force entries to derive from AttributeValue and IDs to
107        be string type
108        """       
109        # Filters are defined as staticmethods but reference via self here to
110        # enable derived class to override them as standard methods without
111        # needing to redefine this __init__ method           
112        VettedDict.__init__(self, self.keyFilter, self.valueFilter)
113       
114    @staticmethod
115    def keyFilter(key):
116        """Enforce string type keys for Attribute Value DataType URIs
117       
118        @param key: URN for attribute
119        @type key: basestring
120        @return: boolean True indicating key is OK
121        @rtype: bool
122        @raise TypeError: incorrect input type
123        """
124        if not isinstance(key, basestring):
125            raise TypeError('Expecting %r derived type for key; got %r' % 
126                            (basestring, type(key))) 
127        return True 
128   
129    @staticmethod
130    def valueFilter(value):
131        """Enforce ElementTree abstract reader derived types for values
132        @param value: attribute value
133        @type value:
134        ndg.xacml.parsers.etree.attributevaluereader.ETreeDataTypeReaderBase to
135        their derived type
136        @return: boolean True indicating attribute value is correct type
137        @rtype: bool
138        @raise TypeError: incorrect input type
139        """
140        if not issubclass(value, ETreeDataTypeReaderBase):
141            raise TypeError('Expecting %r derived type for value; got %r' % 
142                            (ETreeDataTypeReaderBase, type(value))) 
143        return True 
144   
145             
146class DataTypeReaderClassFactory(object):
147    """Return class to parse the content of the Attribute value based on the
148    DataType setting"""
149    MAP = ETreeDataTypeReaderClassMap()
150    _id = None
151    for _id in AttributeValue.TYPE_URIS:
152        MAP[_id] = ETreeDataTypeReaderBase
153       
154    del _id
155   
156    @classmethod
157    def addReader(cls, identifier, readerClass):
158        cls.MAP[identifier] = readerClass
159       
160    @classmethod
161    def getReader(cls, attributeValue):
162        return cls.MAP[attributeValue.dataType]
163   
Note: See TracBrowser for help on using the repository browser.