Package ndg :: Package xacml :: Package core :: Module attributevalue
[hide private]

Source Code for Module ndg.xacml.core.attributevalue

  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 
16 17 18 -class 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 - def __getstate__(self):
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 # Ugly hack to allow for derived classes setting private member 207 # variables 208 if attrName.startswith('__'): 209 attrName = "_AttributeValue" + attrName 210 211 _dict[attrName] = getattr(self, attrName) 212 213 return _dict
214
215 216 -class AttributeValueClassMap(VettedDict):
217 """Specialised dictionary to hold mappings of XML attribute type URIs to 218 their equivalent classes 219 """ 220
221 - def __init__(self):
222 """Force entries to derive from AttributeValue and IDs to 223 be string type 224 """ 225 # Filters are defined as staticmethods but reference via self here to 226 # enable derived class to override them as standard methods without 227 # needing to redefine this __init__ method 228 VettedDict.__init__(self, self.keyFilter, self.valueFilter)
229 230 @staticmethod
231 - def keyFilter(key):
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
246 - def valueFilter(value):
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
259 260 -class AttributeValueClassFactory(object):
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 # Dynamically Create classes based on AttributeValue for all the XACML 273 # primitive types 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
291 - def __init__(self, classMap=None):
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
307 - def __call__(self, identifier):
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 # Instantiate class map to validate input types. 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