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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/ndg_xacml/ndg/xacml/core/attributevalue.py@7661
Revision 7661, 11.6 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 attribute type definition
2
3NERC DataGrid
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"
11__revision__ = "$Id$"
12from datetime import datetime, timedelta
13
14from ndg.xacml.utils import VettedDict
15from ndg.xacml.core.expression import Expression
16   
17
18class AttributeValue(Expression):
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    """
45    ELEMENT_LOCAL_NAME = 'AttributeValue'
46    CLASS_NAME_SUFFIX = 'AttributeValue'
47    IDENTIFIER_PREFIX = 'http://www.w3.org/2001/XMLSchema#'
48 
49    IDENTIFIER = None
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
70    TYPE_URIS = (
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
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))
126    TYPE = None
127   
128    __slots__ = ('__value',) 
129   
130    def __init__(self, value=None):
131        """Derived classes must override setting TYPE class variable
132       
133        @param value: initialise the attribute value by setting this keyword
134        @type value: (set by self.__class__.TYPE)
135        """
136       
137        super(AttributeValue, self).__init__()
138        if self.__class__.TYPE is None:
139            raise NotImplementedError('TYPE class variable must be set to a '
140                                      'valid type in a derived class')
141           
142        self.__value = None
143       
144        # Allow derived classes to make an implicit data type setting
145        self.dataType = self.__class__.IDENTIFIER
146       
147        if value is not None:
148            self.value = value
149
150    def __repr__(self):
151        return "%s = %r " % (super(AttributeValue, self).__repr__(),
152                             self.__value)
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
162   
163    def _get_value(self):
164        """Get value
165        @return: setting for this attribute value
166        @rtype: any - constrained in derived classes
167        """
168        return self.__value
169
170    def _set_value(self, value):
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        """
178        if not isinstance(value, self.__class__.TYPE):
179            raise TypeError('Expecting %r type for "value" '
180                            'attribute; got %r' % (self.__class__.TYPE, 
181                                                   type(value)))
182           
183        self.__value = value 
184
185    value = property(_get_value, _set_value, None, "expression value") 
186   
187    def evaluate(self, context):
188        """Evaluate the result of the expression in a condition.  In the case of
189        an attribute value it's simply itself
190       
191        @param context: the request context
192        @type context: ndg.xacml.core.context.request.Request
193        @return: this attribute value
194        @rtype: AttributeValue 
195        """ 
196        return self
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           
211        VettedDict.__init__(self, self.keyFilter, self.valueFilter)
212       
213    @staticmethod
214    def keyFilter(key):
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        """
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):
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        """
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
243class AttributeValueClassFactory(object):
244    """Create AttributeValue types based on the XML namespace identifier
245   
246    Convenience wrapper for IDENTIFIER2CLASS_MAP instance of
247    AttributeValueClassMap
248   
249    @ivar __classMap: mapping object to map attribute value URIs to their
250    implementations as classes
251    @type __classMap: ndg.xacml.core.attributevalue.AttributeValueClassMap
252    """
253    __slots__ = ('__classMap',)
254   
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       
274    def __init__(self, classMap=None):
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
279        object IDENTIFIER2CLASS_MAP, if None, it will default to this setting
280        @type classMap: ndg.xacml.core.attributevalue.AttributeValueClassMap
281        """
282        if classMap is None:
283            self.__classMap = self.__class__.IDENTIFIER2CLASS_MAP
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
293       
294        @return: attribute value class
295        @rtype: NoneType / ndg.xacml.core.attributevalue.AttributeValue derived
296        type
297        """
298        return self.__classMap.get(identifier)
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.