source: TI12-security/trunk/ndg_xacml/ndg/xacml/core/attributevalue.py @ 7682

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg-security/TI12-security/trunk/ndg_xacml/ndg/xacml/core/attributevalue.py@7682
Revision 7682, 11.6 KB checked in by pjkersha, 10 years ago (diff)

Working and tested version with functionality for adding custom attribute value types and functions.

  • Property svn:keywords set to Id
RevLine 
[6740]1"""NDG XACML attribute type definition
[6643]2
[7087]3NERC DataGrid
[6734]4"""
5__author__ = "P J Kershaw"
6__date__ = "25/02/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"
[7064]11__revision__ = "$Id$"
[6797]12from datetime import datetime, timedelta
13
14from ndg.xacml.utils import VettedDict
[6747]15from ndg.xacml.core.expression import Expression
16   
[6643]17
[6747]18class AttributeValue(Expression):
[7101]19    """XACML Attribute Value type
20   
21    @cvar ELEMENT_LOCAL_NAME: XML local name for this element
22    @type ELEMENT_LOCAL_NAME: string 
23    @cvar CLASS_NAME_SUFFIX: all attribute value classes end with this suffix
24    @type CLASS_NAME_SUFFIX: string
25    @cvar IDENTIFIER_PREFIX: geberic prefix for attribute value URNs
26    @type IDENTIFIER_PREFIX: string
27    @cvar IDENTIFIER: URN for attribute value in derived class
28    @type IDENTIFIER: NoneType - derived classes should set to appropriate
29    string
30    @cvar TYPE_URIS: URIs for all the different supported types
31    @type TYPE_URIS: tuple
32    @cvar TYPE_NAMES: corresponding short names for all the types
33    @type TYPE_NAMES: tuple
34    @cvar NATIVE_TYPES: equivalent python types as implemented
35    @cvar TYPE_MAP: mapping from type names to python types
36    @type TYPE_MAP: dict
37    @cvar TYPE_URI_MAP: mapping from type names to type URIs
38    @type TYPE_URI_MAP: dict
39    @cvar TYPE: type name for derived type - set to None in this parent class
40    @type TYPE: NoneType / string in derived type
41   
42    @ivar __value: setting for this attribute value
43    @type __value: any - constrained in derived classes
44    """
[6747]45    ELEMENT_LOCAL_NAME = 'AttributeValue'
[6797]46    CLASS_NAME_SUFFIX = 'AttributeValue'
47    IDENTIFIER_PREFIX = 'http://www.w3.org/2001/XMLSchema#'
[7064]48 
[6797]49    IDENTIFIER = None
[7412]50   
51    STRING_TYPE_URI = IDENTIFIER_PREFIX + 'string'
52    ANY_TYPE_URI = IDENTIFIER_PREFIX + 'anyURI'
53    INTEGER_TYPE_URI = IDENTIFIER_PREFIX + 'integer'
54    BOOLEAN_TYPE_URI = IDENTIFIER_PREFIX + 'boolean'
55    DOUBLE_TYPE_URI = IDENTIFIER_PREFIX + 'double'
56    DATE_TYPE_URI = IDENTIFIER_PREFIX + 'date'
57    DATETIME_TYPE_URI = IDENTIFIER_PREFIX + 'dateTime'
58    TIME_TYPE_URI = IDENTIFIER_PREFIX + 'time'
59    DAYTIMEDURATION_TYPE_URI = \
60    'http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration'
61    YEARMONTHDURATION_TYPE_URI = \
62    'http://www.w3.org/TR/2002/WD-xquery-operators-20020816#yearMonthDuration'
63    X500NAME_TYPE_URI = 'urn:oasis:names:tc:xacml:1.0:data-type:x500Name'
64    RFC822NAME_TYPE_URI = 'urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name'
65    HEXBINARY_TYPE_URI = IDENTIFIER_PREFIX + 'hexBinary'
66    BASE64BINARY_TYPE_URI = IDENTIFIER_PREFIX + 'base64Binary'
67    IPADDRESS_TYPE_URI = 'urn:oasis:names:tc:xacml:2.0:data-type:ipAddress'
68    DNSNAME_TYPE_URI = 'urn:oasis:names:tc:xacml:2.0:data-type:dnsName'
69
[7064]70    TYPE_URIS = (
[7412]71        STRING_TYPE_URI,
72        ANY_TYPE_URI,
73        INTEGER_TYPE_URI,
74        BOOLEAN_TYPE_URI,
75        DOUBLE_TYPE_URI,
76        DATE_TYPE_URI,
77        DATETIME_TYPE_URI,
78        TIME_TYPE_URI,
79        DAYTIMEDURATION_TYPE_URI,
80        YEARMONTHDURATION_TYPE_URI,
81        X500NAME_TYPE_URI,
82        RFC822NAME_TYPE_URI,
83        HEXBINARY_TYPE_URI,
84        BASE64BINARY_TYPE_URI,
85        IPADDRESS_TYPE_URI,
86        DNSNAME_TYPE_URI
[7064]87    )
88    TYPE_NAMES = (
89        'String',
90        'AnyURI',
91        'Integer',
92        'Boolean',
93        'Double',
94        'Date',
95        'DateTime',
96        'Time',
97        'DayTimeDuration',
98        'YearMonthDuration',
99        'X500Name',
100        'Rfc822Name',
101        'HexBinary',
102        'Base64Binary',
103        'IpAddress',
104        'DnsName',
105    )
106    NATIVE_TYPES = (
107        basestring,
108        basestring,
109        int,
110        bool,
111        float,
112        datetime,
113        datetime,
114        datetime,
115        timedelta,
116        timedelta,
117        basestring,
118        basestring,
119        int,
120        NotImplemented,
121        basestring,
122        basestring
123    )
124    TYPE_MAP = dict(zip(TYPE_NAMES, NATIVE_TYPES))
125    TYPE_URI_MAP = dict(zip(TYPE_NAMES, TYPE_URIS))
[6797]126    TYPE = None
127   
[6747]128    __slots__ = ('__value',) 
[6643]129   
[7324]130    def __init__(self, value=None):
131        """Derived classes must override setting TYPE class variable
[7101]132       
[7324]133        @param value: initialise the attribute value by setting this keyword
134        @type value: (set by self.__class__.TYPE)
135        """
136       
[6747]137        super(AttributeValue, self).__init__()
[6802]138        if self.__class__.TYPE is None:
[7101]139            raise NotImplementedError('TYPE class variable must be set to a '
140                                      'valid type in a derived class')
[6802]141           
[6643]142        self.__value = None
[6807]143       
144        # Allow derived classes to make an implicit data type setting
145        self.dataType = self.__class__.IDENTIFIER
[7324]146       
147        if value is not None:
148            self.value = value
[6805]149
150    def __repr__(self):
151        return "%s = %r " % (super(AttributeValue, self).__repr__(),
[7682]152                             self.value)
[7351]153
154    def __eq__(self, attrVal):
155        """Check for equality by comparing the value attributes"""
156        if not isinstance(attrVal, self.__class__):
157            raise TypeError('Expecting %r type for "value" '
158                            'attribute; got %r' % (self.__class__.TYPE, 
159                                                   type(attrVal)))
160           
161        return self.__value == attrVal.value
[6805]162   
[6643]163    def _get_value(self):
[7101]164        """Get value
[7109]165        @return: setting for this attribute value
[7101]166        @rtype: any - constrained in derived classes
167        """
[6643]168        return self.__value
169
170    def _set_value(self, value):
[7101]171        """Set value
172       
173        @param value: setting for this attribute value
174        @type value: any - constrained in derived classes
175        @raise TypeError: if type doesn't match TYPE class variable.  Derived
176        classes should set this
177        """
[6797]178        if not isinstance(value, self.__class__.TYPE):
[6643]179            raise TypeError('Expecting %r type for "value" '
[6797]180                            'attribute; got %r' % (self.__class__.TYPE, 
181                                                   type(value)))
[6643]182           
183        self.__value = value 
184
[6792]185    value = property(_get_value, _set_value, None, "expression value") 
186   
187    def evaluate(self, context):
[6805]188        """Evaluate the result of the expression in a condition.  In the case of
189        an attribute value it's simply itself
190       
[6792]191        @param context: the request context
192        @type context: ndg.xacml.core.context.request.Request
[6805]193        @return: this attribute value
194        @rtype: AttributeValue 
[6792]195        """ 
[6805]196        return self
[6797]197
198
199class AttributeValueClassMap(VettedDict):
200    """Specialised dictionary to hold mappings of XML attribute type URIs to
201    their equivalent classes
202    """
203   
204    def __init__(self):
205        """Force entries to derive from AttributeValue and IDs to
206        be string type
207        """       
208        # Filters are defined as staticmethods but reference via self here to
209        # enable derived class to override them as standard methods without
210        # needing to redefine this __init__ method           
[7072]211        VettedDict.__init__(self, self.keyFilter, self.valueFilter)
[6797]212       
213    @staticmethod
214    def keyFilter(key):
[7101]215        """Enforce string type keys
216       
217        @param key: URN for attribute
218        @type key: basestring
219        @return: boolean True indicating key is OK
220        @rtype: bool
221        @raise TypeError: incorrect input type
222        """
[6797]223        if not isinstance(key, basestring):
224            raise TypeError('Expecting %r type for key; got %r' % 
225                            (basestring, type(key))) 
226        return True 
227   
228    @staticmethod
229    def valueFilter(value):
[7101]230        """Enforce AttributeValue derived types for values
231        @param value: attribute value
232        @type value: ndg.xacml.core.attributevalue.AttributeValue derived type
233        @return: boolean True indicating attribute value is correct type
234        @rtype: bool
235        @raise TypeError: incorrect input type
236        """
[6797]237        if not issubclass(value, AttributeValue):
238            raise TypeError('Expecting %r derived type for value; got %r' % 
239                            (AttributeValue, type(value))) 
240        return True 
241
242
[6802]243class AttributeValueClassFactory(object):
[6797]244    """Create AttributeValue types based on the XML namespace identifier
245   
[7661]246    Convenience wrapper for IDENTIFIER2CLASS_MAP instance of
[6797]247    AttributeValueClassMap
[7101]248   
[7109]249    @ivar __classMap: mapping object to map attribute value URIs to their
[7101]250    implementations as classes
251    @type __classMap: ndg.xacml.core.attributevalue.AttributeValueClassMap
[6797]252    """
[7101]253    __slots__ = ('__classMap',)
254   
[7661]255    # Dynamically Create classes based on AttributeValue for all the XACML
256    # primitive types
257    IDENTIFIER2CLASS_MAP = AttributeValueClassMap()
258    _typeName, _type, _identifier, _className, _classVars, \
259        _attributeValueClass = (None,)*6
260       
261    for _typeName, _type in AttributeValue.TYPE_MAP.items():
262        _identifier = AttributeValue.TYPE_URI_MAP[_typeName]
263   
264        _className = _typeName + AttributeValue.CLASS_NAME_SUFFIX               
265        _classVars = {'TYPE': _type, 'IDENTIFIER': _identifier}
266       
267        _attributeValueClass = type(_className, (AttributeValue, ), _classVars)
268        AttributeValue.register(_attributeValueClass)
269        IDENTIFIER2CLASS_MAP[_identifier] = _attributeValueClass
270   
271    del _typeName, _type, _identifier, _className, _classVars, \
272        _attributeValueClass
273       
[6797]274    def __init__(self, classMap=None):
[7101]275        """Set a mapping object to map attribute value URIs to their
276        implementations as classes
277       
278        @param classMap: input an alternative to the default class mapping
[7661]279        object IDENTIFIER2CLASS_MAP, if None, it will default to this setting
[7101]280        @type classMap: ndg.xacml.core.attributevalue.AttributeValueClassMap
281        """
[6797]282        if classMap is None:
[7661]283            self.__classMap = self.__class__.IDENTIFIER2CLASS_MAP
[6797]284        elif isinstance(classMap, AttributeValueClassMap):
285            self.__classMap = classMap
286        else:
287            raise TypeError('Expecting %r derived type for "map" input; got %r'
288                            % (AttributeValueClassMap, type(map)))
289           
290    def __call__(self, identifier):
291        """Return <type>AttributeValue class for given identifier URI or None
292        if no match is found
[7101]293       
294        @return: attribute value class
295        @rtype: NoneType / ndg.xacml.core.attributevalue.AttributeValue derived
296        type
[6797]297        """
298        return self.__classMap.get(identifier)
[7661]299   
300    @classmethod
301    def addClass(cls, identifier, attributeValueClass, overwrite=False):
302        """Extend Default AttributeValue Class Map with custom types.  This
303        enables the policy to support additional attribute types
304       
305        @param identifier: ID for candidate Attribute Value class
306        @type identifier: ndg.xacml.core.attributevalue.AttributeValueClassMap
307        @param attributeValueClass: new Attribute Value class to be added
308        @type attributeValueClass: ndg.xacml.core.attributevalue.AttributeValue
309        @param overwrite: set to True to allow overwriting of existing map
310        entries, defaults to disable overwrite
311        @type overwrite: bool
312        """
313        # Instantiate class map to validate input types.
314        classMap = AttributeValueClassMap()
315        classMap[identifier] = attributeValueClass
316       
317        if overwrite:
318            cls.IDENTIFIER2CLASS_MAP.update(classMap)
319        else:
320            for k, v in classMap.items():
321                if k not in cls.IDENTIFIER2CLASS_MAP:
322                    cls.IDENTIFIER2CLASS_MAP[k] = v       
323                   
Note: See TracBrowser for help on using the repository browser.