Package turbogears :: Package identity :: Module conditions

Source Code for Module turbogears.identity.conditions

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