Package turbogears :: Package identity :: Module conditions

Source Code for Module turbogears.identity.conditions

  1  """Definition of the identity predicates.""" 
  2   
  3  # declare what should be exported 
  4  __all__ = ['All', 'Any', 'NotAny', 'CompoundPredicate', 
  5      'IdentityPredicateHelper', 'Predicate', 
  6      'SecureObject', 'SecureResource', 
  7      'from_host', 'from_any_host', 
  8      'in_all_groups', 'in_any_group', 'in_group', 
  9      'has_all_permissions', 'has_any_permission', 'has_permission', 
 10      'not_anonymous', 'require'] 
 11   
 12   
 13  from types import MethodType 
 14   
 15  from cherrypy import request 
 16   
 17  from turbogears import config 
 18  from turbogears.decorator import weak_signature_decorator 
 19  from turbogears.util import match_ip, request_available 
 20   
 21  from turbogears.identity.exceptions import (IdentityException, 
 22      IdentityFailure, RequestRequiredException) 
 23  from turbogears.identity.base import current 
 24   
 25   
26 -class Predicate(object):
27 """Generic base class for testing true or false for a condition.""" 28
29 - def eval_with_object(self, obj, errors=None):
30 """Determine whether predicate is True or False for the given object.""" 31 raise NotImplementedError
32
33 - def append_error_message(self, errors=None):
34 if errors is None: 35 return 36 errors.append(self.error_message % self.__dict__)
37 38
39 -class CompoundPredicate(Predicate):
40 """A predicate composed of other predicates.""" 41
42 - def __init__(self, *predicates):
43 self.predicates = predicates
44 45
46 -class All(CompoundPredicate):
47 """Logical 'and' of all sub-predicates. 48 49 This compound predicate evaluates to true only if all of its sub-predicates 50 evaluate to true for the given input. 51 52 """ 53 error_message = "One of the predicates denied access" 54
55 - def eval_with_object(self, obj, errors=None):
56 """Return true if all sub-predicates evaluate to true. 57 """ 58 for p in self.predicates: 59 if not p.eval_with_object(obj, errors): 60 self.append_error_message(errors) 61 return False 62 return True
63 64
65 -class Any(CompoundPredicate):
66 """Logical 'or' of all sub-predicates. 67 68 This compound predicate evaluates to true if any one of its sub-predicates 69 evaluates to true for the given input. 70 71 """ 72 error_message = "No predicate was able to grant access" 73
74 - def eval_with_object(self, obj, errors=None):
75 """Return true if any sub-predicate evaluates to true.""" 76 for p in self.predicates: 77 if p.eval_with_object(obj, None): 78 return True 79 self.append_error_message(errors) 80 return False
81 82
83 -class NotAny(CompoundPredicate):
84 """Locigal 'nor' of all sub-predicates. 85 86 A compound predicate that evaluates to true only if no sub-predicates 87 evaluate to true for the given input. 88 89 """ 90 error_message= "One of the predicates did not deny access" 91
92 - def eval_with_object(self, obj, errors=None):
93 """Return true if no sub-predicates evaluate to true.""" 94 for p in self.predicates: 95 if p.eval_with_object(obj, errors): 96 self.append_error_message(errors) 97 return False 98 return True
99 100
101 -class IdentityPredicateHelper(object):
102 """A mix-in helper class for Identity Predicates.""" 103
104 - def __nonzero__(self):
105 return self.eval_with_object(current)
106 107
108 -class in_group(Predicate, IdentityPredicateHelper):
109 """Predicate for requiring a group.""" 110 error_message = "Not member of group: %(group_name)s" 111
112 - def __init__(self, group_name):
114
115 - def eval_with_object(self, identity, errors=None):
116 if self.group_name in identity.groups: 117 return True 118 self.append_error_message(errors) 119 return False
120 121
122 -class in_all_groups(All, IdentityPredicateHelper):
123 """Predicate for requiring membership in a number of groups.""" 124
125 - def __init__(self, *groups):
126 group_predicates = [in_group(g) for g in groups] 127 super(in_all_groups, self).__init__(*group_predicates)
128 129
130 -class in_any_group(Any, IdentityPredicateHelper):
131 """Predicate for requiring membership in at least one group.""" 132 error_message = "Not member of any group: %(group_list)s" 133
134 - def __init__(self, *groups):
135 self.group_list = ", ".join(groups) 136 group_predicates = [in_group(g) for g in groups] 137 super(in_any_group, self).__init__(*group_predicates)
138 139
140 -class not_anonymous(Predicate, IdentityPredicateHelper):
141 """Predicate for checking whether current visitor is anonymous.""" 142 error_message = "Anonymous access denied" 143
144 - def eval_with_object(self, identity, errors=None):
145 if identity.anonymous: 146 self.append_error_message(errors) 147 return False 148 return True
149 150
151 -class has_permission(Predicate, IdentityPredicateHelper):
152 """Predicate for checking whether visitor has a particular permission.""" 153 error_message = "Permission denied: %(permission_name)s" 154
155 - def __init__(self, permission_name):
157
158 - def eval_with_object(self, identity, errors=None):
159 """Determine whether the visitor has the specified permission.""" 160 if self.permission_name in identity.permissions: 161 return True 162 self.append_error_message(errors) 163 return False
164 165
166 -class has_all_permissions(All, IdentityPredicateHelper):
167 """Predicate for checking whether the visitor has all permissions.""" 168
169 - def __init__(self, *permissions):
170 permission_predicates = [has_permission(p) for p in permissions] 171 super(has_all_permissions, self).__init__(*permission_predicates)
172 173
174 -class has_any_permission(Any, IdentityPredicateHelper):
175 """Predicate for checking whether visitor has at least one permission.""" 176 error_message = "No matching permissions: %(permission_list)s" 177
178 - def __init__(self, *permissions):
179 self.permission_list = ', '.join(permissions) 180 permission_predicates = [has_permission(p) for p in permissions] 181 super(has_any_permission, self).__init__(*permission_predicates)
182 183
184 -def _remoteHost():
185 if not request_available(): 186 raise RequestRequiredException() 187 else: 188 return request.headers.get('X-Forwarded-For', request.headers.get( 189 'Remote-Addr', '')).rsplit(',', 1)[-1].strip() or None
190
191 -class from_host(Predicate, IdentityPredicateHelper):
192 """Predicate for checking whether the visitor's host is a permitted host. 193 194 Note: We never want to announce what the list of allowed hosts is, because 195 it is way too easy to spoof an IP address in a TCP/IP packet. 196 197 """ 198 error_message = "Access from this host is not permitted." 199
200 - def __init__(self, host):
201 self.host = host
202
203 - def eval_with_object(self, obj, errors=None):
204 """Match the visitor's host against the criteria.""" 205 ip = _remoteHost() 206 if ip and match_ip(self.host, ip): 207 return True 208 self.append_error_message(errors) 209 return False
210 211
212 -class from_any_host(Any, IdentityPredicateHelper):
213 """Predicate for checking the visitor against a number of allowed hosts.""" 214 error_message = "Access from this host is not permitted." 215
216 - def __init__(self, hosts):
217 host_predicates = [from_host(h) for h in hosts] 218 super(from_any_host, self).__init__(*host_predicates)
219 220
221 -def require(predicate, obj=None):
222 """Function decorator checking requirements for the current user. 223 224 This function decorator checks whether the current user is a member 225 of the groups specified and has the permissions required. 226 227 """ 228 229 def entangle(fn): 230 def require(func, self, *args, **kwargs): 231 try: 232 errors = [] 233 if (predicate is None 234 or predicate.eval_with_object(current, errors)): 235 return fn(self, *args, **kwargs) 236 except IdentityException, e: 237 errors = [str(e)] 238 raise IdentityFailure(errors)
239 fn._require = predicate 240 return require 241 return weak_signature_decorator(entangle) 242 243
244 -def _check_method(obj, fn, predicate):
245 def _wrapper(*args, **kw): 246 errors= [] 247 if predicate.eval_with_object(current, errors): 248 return fn(*args, **kw) 249 else: 250 raise IdentityFailure(errors)
251 _wrapper.exposed = True 252 return _wrapper 253 254
255 -class SecureResource(object):
256
257 - def __getattribute__(self, name):
258 if name.startswith('_cp') or name == 'require': 259 return object.__getattribute__(self, name) 260 try: 261 value = object.__getattribute__(self, name) 262 try: 263 predicate = object.__getattribute__(self, 'require') 264 except AttributeError: 265 predicate = config.get('identity.require', None) 266 if predicate is None: 267 raise AttributeError("SecureResource requires a 'require'" 268 " attribute either on the controller class itself" 269 " or in the config file") 270 errors = [] 271 if (isinstance(value, MethodType) and 272 hasattr(value, 'exposed')): 273 return _check_method(self, value, predicate) 274 from turbogears.controllers import Controller 275 if isinstance(value, Controller): 276 return SecureObject(value, predicate) 277 # Some other property 278 return value 279 except IdentityException, e: 280 errors = [str(e)] 281 raise IdentityFailure(errors)
282 283
284 -class SecureObject(object):
285
286 - def __init__(self, obj, require, exclude=[]):
287 self._object = obj 288 self._require = require 289 self._exclude = exclude
290
291 - def __getattribute__(self, name):
292 if name in ('_object', '_require', '_exclude'): 293 return object.__getattribute__(self, name) 294 try: 295 obj = object.__getattribute__(self, '_object') 296 value = getattr(obj, name) 297 errors = [] 298 predicate = object.__getattribute__(self, '_require') 299 if name in object.__getattribute__(self, '_exclude'): 300 return value 301 if (isinstance(value, MethodType) and 302 hasattr(value, 'exposed')): 303 return _check_method(obj, value, predicate) 304 from turbogears.controllers import Controller 305 if isinstance(value, Controller): 306 return SecureObject(value, predicate) 307 # Some other property 308 return value 309 except IdentityException, e: 310 errors = [str(e)] 311 raise IdentityFailure(errors)
312
313 - def __setattr__(self, name, value):
314 if name in ('_object', '_require', '_exclude'): 315 super(SecureObject, self).__setattr__(name, value) 316 else: 317 setattr(self._object, name, value)
318