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

Source Code for Module ndg.xacml.core.rule

  1  """NDG Security Rule 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: rule.py 7955 2011-12-21 18:29:45Z rwilkinson $" 
 12  import traceback 
 13  import logging 
 14  log = logging.getLogger(__name__) 
 15   
 16  from ndg.xacml.core import XacmlCoreBase 
 17  from ndg.xacml.core.target import Target 
 18  from ndg.xacml.core.condition import Condition 
 19  from ndg.xacml.core.context.result import Decision 
20 21 22 -class Effect(object):
23 """Rule Effect 24 25 @cvar PERMIT_STR: permit decision string 26 @type PERMIT_STR: string 27 28 @cvar DENY_STR: deny decision string 29 @type DENY_STR: string 30 31 @cvar TYPES: list of valid effect strings 32 @type TYPES: tuple 33 34 @ivar value: effect value 35 @type value: string 36 """ 37 DENY_STR = 'Deny' 38 PERMIT_STR = 'Permit' 39 TYPES = (DENY_STR, PERMIT_STR) 40 __slots__ = ('__value',) 41
42 - def __init__(self, effect=DENY_STR):
43 """@param effect: initialise effect value, defaults to deny 44 @type effect: basestring / ndg.xacml.core.rule.Effect 45 """ 46 self.__value = None 47 self.value = effect
48
49 - def __getstate__(self):
50 '''Enable pickling 51 52 @return: class instance attributes dictionary 53 @rtype: dict 54 ''' 55 _dict = {} 56 for attrName in Effect.__slots__: 57 # Ugly hack to allow for derived classes setting private member 58 # variables 59 if attrName.startswith('__'): 60 attrName = "_Effect" + attrName 61 62 _dict[attrName] = getattr(self, attrName) 63 64 return _dict
65
66 - def __setstate__(self, attrDict):
67 '''Enable pickling 68 69 @param attrDict: class instance attributes dictionary 70 @type attrDict: dict 71 ''' 72 for attrName, val in attrDict.items(): 73 setattr(self, attrName, val)
74
75 - def _setValue(self, value):
76 """Set effect value 77 78 @param value: effect value - constrained vocabulary to Effect.TYPES 79 @type value: string or ndg.xacml.core.rule.Effect 80 @raise AttributeError: invalid decision string value input 81 @raise TypeError: invalid type for input decision value 82 """ 83 if isinstance(value, Effect): 84 # Cast to string 85 value = str(value) 86 87 elif not isinstance(value, basestring): 88 raise TypeError('Expecting string or Effect instance for ' 89 '"value" attribute; got %r instead' % type(value)) 90 91 if value not in self.__class__.TYPES: 92 raise AttributeError('Permissable effect types are %r; got ' 93 '%r instead' % (Effect.TYPES, value)) 94 self.__value = value
95
96 - def _getValue(self):
97 """Get effect value 98 99 @return: effect value 100 @rtype: string 101 """ 102 return self.__value
103 104 value = property(fget=_getValue, fset=_setValue, doc="Effect value") 105
106 - def __str__(self):
107 """represent decision as a string 108 109 @return: decision value 110 @rtype: string 111 """ 112 return self.__value
113
114 - def __eq__(self, effect):
115 """ 116 @param effect: effect value to compare with self's 117 @type effect: string or ndg.xacml.core.rule.Effect 118 @return: True if the decision values match, False otherwise 119 @rtype: bool 120 @raise AttributeError: invalid decision string value input 121 @raise TypeError: invalid type for input decision value 122 """ 123 if isinstance(effect, Effect): 124 # Cast to string 125 value = effect.value 126 127 elif isinstance(effect, basestring): 128 value = effect 129 130 else: 131 raise TypeError('Expecting string or Effect instance for ' 132 'input effect value; got %r instead' % type(value)) 133 134 if value not in self.__class__.TYPES: 135 raise AttributeError('Permissable effect types are %r; got ' 136 '%r instead' % (Effect.TYPES, value)) 137 138 return self.__value == value
139
140 - def __nonzero__(self):
141 """Boolean evaluation of a rule effect - True = Allow; False = Deny 142 143 @return: True if the effect value is permit, False otherwise 144 @rtype: bool 145 """ 146 return self.__value == Effect.PERMIT_STR
147
148 149 -class PermitEffect(Effect):
150 """Permit authorisation Effect""" 151 __slots__ = () 152
153 - def __init__(self):
154 """Initialise set with Permit value""" 155 super(PermitEffect, self).__init__(Effect.PERMIT_STR)
156
157 - def _setValue(self, value):
158 """Make value read-only 159 @raise AttributeError: value can't be set 160 """ 161 raise AttributeError("can't set attribute")
162
163 164 -class DenyEffect(Effect):
165 """Deny authorisation Effect""" 166 __slots__ = () 167
168 - def __init__(self):
169 """Initialise set with Permit value""" 170 super(DenyEffect, self).__init__(Effect.DENY_STR)
171
172 - def _setValue(self, value):
173 """Make value read-only 174 @raise AttributeError: value can't be set 175 """ 176 raise AttributeError("can't set attribute")
177 178 # Add instances of each for convenience 179 Effect.PERMIT = PermitEffect() 180 Effect.DENY = DenyEffect()
181 182 183 -class Rule(XacmlCoreBase):
184 """XACML Policy Rule 185 186 @cvar ELEMENT_LOCAL_NAME: XML local name for this element 187 @type ELEMENT_LOCAL_NAME: string 188 @cvar DESCRIPTION_LOCAL_NAME: XML local name for the description element 189 @type DESCRIPTION_LOCAL_NAME: string 190 @cvar RULE_ID_ATTRIB_NAME: rule id XML attribute name 191 @type RULE_ID_ATTRIB_NAME: string 192 @cvar EFFECT_ATTRIB_NAME: effect XML attribute name 193 @type EFFECT_ATTRIB_NAME: string 194 195 @ivar __target: rule target 196 @type __target: ndg.xacml.core.target.Target / NoneType 197 @ivar __condition: rule condition 198 @type __condition: ndg.xacml.core.condition.Condition / NoneType 199 @ivar __description: rule description text 200 @type __description: basestring / NoneType 201 @ivar __id: rule ID 202 @type __id: basestring / NoneType 203 @ivar __effect: rule effect 204 @type __effect: ndg.xacml.core.rule.Effect / NoneType 205 """ 206 ELEMENT_LOCAL_NAME = 'Rule' 207 RULE_ID_ATTRIB_NAME = 'RuleId' 208 EFFECT_ATTRIB_NAME = 'Effect' 209 210 DESCRIPTION_LOCAL_NAME = 'Description' 211 212 __slots__ = ( 213 '__target', 214 '__condition', 215 '__description', 216 '__id', 217 '__effect' 218 ) 219
220 - def __init__(self):
221 """Initialise attributes""" 222 super(Rule, self).__init__() 223 224 self.__id = None 225 self.__effect = None 226 self.__target = None 227 self.__condition = None
228 229 @property
230 - def target(self):
231 """Get Rule target 232 @return: rule target 233 @rtype: ndg.xacml.core.target import Target / NoneType 234 """ 235 return self.__target
236 237 @target.setter
238 - def target(self, value):
239 """Set rule target 240 @param value: rule target 241 @type value: ndg.xacml.core.target import Target 242 @raise TypeError: incorrect type set 243 """ 244 if not isinstance(value, Target): 245 raise TypeError('Expecting %r type for "id" ' 246 'attribute; got %r' % (Target, type(value))) 247 self.__target = value
248 249 @property
250 - def condition(self):
251 """Get rule condition 252 253 @return: rule condition 254 @rtype: ndg.xacml.core.condition.Condition / NoneType 255 """ 256 return self.__condition
257 258 @condition.setter
259 - def condition(self, value):
260 """Set rule condition 261 262 @param value: rule condition 263 @type value: ndg.xacml.core.condition.Condition 264 @raise TypeError: incorrect type set 265 """ 266 if not isinstance(value, Condition): 267 raise TypeError('Expecting %r type for "id" attribute; got %r' % 268 (Condition, type(value))) 269 270 self.__condition = value
271
272 - def _get_id(self):
273 """Get rule ID 274 275 @return: rule ID 276 @rtype: ndg.xacml.core.condition.Condition / NoneType 277 """ 278 return self.__id
279
280 - def _set_id(self, value):
281 """Set rule ID 282 283 @param value: rule ID 284 @type value: basestring 285 @raise TypeError: incorrect type set 286 """ 287 if not isinstance(value, basestring): 288 raise TypeError('Expecting %r type for "id" attribute; got %r' % 289 (basestring, type(value))) 290 291 self.__id = value
292 293 id = property(_get_id, _set_id, None, "Rule identifier attribute") 294
295 - def _get_effect(self):
296 """Get rule effect 297 298 @return: rule effect 299 @rtype: ndg.xacml.core.rule.Effect / NoneType 300 """ 301 return self.__effect
302
303 - def _set_effect(self, value):
304 """Set rule effect 305 306 @param value: rule effect 307 @type value: ndg.xacml.core.rule.Effect 308 @raise TypeError: incorrect type set 309 """ 310 if not isinstance(value, Effect): 311 raise TypeError('Expecting %r type for "effect" ' 312 'attribute; got %r' % (Effect, type(value))) 313 314 self.__effect = value
315 316 effect = property(_get_effect, _set_effect, None, 317 "Rule effect attribute") 318
319 - def _getDescription(self):
320 """Get rule description 321 322 @return: rule description 323 @rtype: basestring / NoneType 324 """ 325 return self.__description
326
327 - def _setDescription(self, value):
328 """Set rule description 329 330 @param value: rule description 331 @type value: basestring 332 @raise TypeError: incorrect type set 333 """ 334 if not isinstance(value, basestring): 335 raise TypeError('Expecting string type for "description" ' 336 'attribute; got %r' % type(value)) 337 self.__description = value
338 339 description = property(_getDescription, _setDescription, 340 doc="Rule Description text") 341
342 - def evaluate(self, context):
343 """Evaluate a rule 344 @param context: the request context 345 @type context: ndg.xacml.core.request.Request 346 @return: result of the evaluation - the decision for this rule 347 @rtype: ndg.xacml.core.context.result.Decision 348 """ 349 350 # Place exception block to enable rule combining algorithm which calls 351 # this method to correctly handle Indeterminate results 352 try: 353 log.debug('Evaluating rule %r ...', self.id) 354 355 # Instantiation implicitly sets to default value of Indeterminate 356 decision = Decision() 357 358 # Check for a rule target 359 if self.target is not None: 360 targetMatch = self.target.match(context) 361 if targetMatch: 362 log.debug('Match to request context for target in rule ' 363 '%r', self.id) 364 else: 365 log.debug('No target set in rule %r', self.id) 366 targetMatch = True 367 368 if not targetMatch: 369 log.debug('No match to request context for target in rule ' 370 '%r returning NotApplicable status', self.id) 371 decision = Decision.NOT_APPLICABLE 372 return decision 373 374 # Apply the condition if present 375 if self.condition is not None: 376 conditionStatus = self.condition.evaluate(context) 377 else: 378 # No condition set to True - 7.8 in spec.: 379 # 380 # The condition value SHALL be "True" if the <Condition> element 381 # is absent 382 log.debug('No condition set for rule %r: setting condition ' 383 'status True', self.id) 384 conditionStatus = True 385 386 # Ref. Spec. 7.9 Rule evaluation, Nb. to get this far, the target 387 # must evaluated as True 388 if conditionStatus: 389 decision = Decision(decision=self.effect.value) 390 else: 391 decision = Decision.NOT_APPLICABLE 392 393 log.debug('Rule %r evaluates to %s', self.id, decision) 394 return decision 395 396 except Exception: 397 _traceback = traceback.format_exc() 398 log.error('Error occurred evaluating rule %r, returning ' 399 'Indeterminate result to caller: %s', 400 self.id, _traceback) 401 return Decision.INDETERMINATE
402