1 """NDG XACML attribute type definition
2
3 NERC 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: attributevalue.py 8010 2012-01-30 16:24:06Z rwilkinson $"
12 from datetime import datetime, timedelta
13
14 from ndg.xacml.utils import VettedDict
15 from ndg.xacml.core.expression import 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
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
145 self.dataType = self.__class__.IDENTIFIER
146
147 if value is not None:
148 self.value = value
149
153
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
164 """Get value
165 @return: setting for this attribute value
166 @rtype: any - constrained in derived classes
167 """
168 return self.__value
169
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
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
199 '''Enable pickling
200
201 @return: object's attribute dictionary
202 @rtype: dict
203 '''
204 _dict = super(AttributeValue, self).__getstate__()
205 for attrName in AttributeValue.__slots__:
206
207
208 if attrName.startswith('__'):
209 attrName = "_AttributeValue" + attrName
210
211 _dict[attrName] = getattr(self, attrName)
212
213 return _dict
214
217 """Specialised dictionary to hold mappings of XML attribute type URIs to
218 their equivalent classes
219 """
220
229
230 @staticmethod
232 """Enforce string type keys
233
234 @param key: URN for attribute
235 @type key: basestring
236 @return: boolean True indicating key is OK
237 @rtype: bool
238 @raise TypeError: incorrect input type
239 """
240 if not isinstance(key, basestring):
241 raise TypeError('Expecting %r type for key; got %r' %
242 (basestring, type(key)))
243 return True
244
245 @staticmethod
247 """Enforce AttributeValue derived types for values
248 @param value: attribute value
249 @type value: ndg.xacml.core.attributevalue.AttributeValue derived type
250 @return: boolean True indicating attribute value is correct type
251 @rtype: bool
252 @raise TypeError: incorrect input type
253 """
254 if not issubclass(value, AttributeValue):
255 raise TypeError('Expecting %r derived type for value; got %r' %
256 (AttributeValue, type(value)))
257 return True
258
261 """Create AttributeValue types based on the XML namespace identifier
262
263 Convenience wrapper for IDENTIFIER2CLASS_MAP instance of
264 AttributeValueClassMap
265
266 @ivar __classMap: mapping object to map attribute value URIs to their
267 implementations as classes
268 @type __classMap: ndg.xacml.core.attributevalue.AttributeValueClassMap
269 """
270 __slots__ = ('__classMap',)
271
272
273
274 IDENTIFIER2CLASS_MAP = AttributeValueClassMap()
275 _typeName, _type, _identifier, _className, _classVars, \
276 _attributeValueClass = (None,)*6
277
278 for _typeName, _type in AttributeValue.TYPE_MAP.items():
279 _identifier = AttributeValue.TYPE_URI_MAP[_typeName]
280
281 _className = _typeName + AttributeValue.CLASS_NAME_SUFFIX
282 _classVars = {'TYPE': _type, 'IDENTIFIER': _identifier}
283
284 _attributeValueClass = type(_className, (AttributeValue, ), _classVars)
285 AttributeValue.register(_attributeValueClass)
286 IDENTIFIER2CLASS_MAP[_identifier] = _attributeValueClass
287
288 del _typeName, _type, _identifier, _className, _classVars, \
289 _attributeValueClass
290
292 """Set a mapping object to map attribute value URIs to their
293 implementations as classes
294
295 @param classMap: input an alternative to the default class mapping
296 object IDENTIFIER2CLASS_MAP, if None, it will default to this setting
297 @type classMap: ndg.xacml.core.attributevalue.AttributeValueClassMap
298 """
299 if classMap is None:
300 self.__classMap = self.__class__.IDENTIFIER2CLASS_MAP
301 elif isinstance(classMap, AttributeValueClassMap):
302 self.__classMap = classMap
303 else:
304 raise TypeError('Expecting %r derived type for "map" input; got %r'
305 % (AttributeValueClassMap, type(map)))
306
308 """Return <type>AttributeValue class for given identifier URI or None
309 if no match is found
310
311 @return: attribute value class
312 @rtype: NoneType / ndg.xacml.core.attributevalue.AttributeValue derived
313 type
314 """
315 return self.__classMap.get(identifier)
316
317 @classmethod
318 - def addClass(cls, identifier, attributeValueClass, overwrite=False):
319 """Extend Default AttributeValue Class Map with custom types. This
320 enables the policy to support additional attribute types
321
322 @param identifier: ID for candidate Attribute Value class
323 @type identifier: ndg.xacml.core.attributevalue.AttributeValueClassMap
324 @param attributeValueClass: new Attribute Value class to be added
325 @type attributeValueClass: ndg.xacml.core.attributevalue.AttributeValue
326 @param overwrite: set to True to allow overwriting of existing map
327 entries, defaults to disable overwrite
328 @type overwrite: bool
329 """
330
331 classMap = AttributeValueClassMap()
332 classMap[identifier] = attributeValueClass
333
334 if overwrite:
335 cls.IDENTIFIER2CLASS_MAP.update(classMap)
336 else:
337 for k, v in classMap.items():
338 if k not in cls.IDENTIFIER2CLASS_MAP:
339 cls.IDENTIFIER2CLASS_MAP[k] = v
340