1 """Definition of the identity predicates."""
2
3
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
27 """Generic base class for testing true or false for a condition."""
28
30 """Determine whether predicate is True or False for the given object."""
31 raise NotImplementedError
32
37
38
40 """A predicate composed of other predicates."""
41
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
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
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
99
100
102 """A mix-in helper class for Identity Predicates."""
103
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
114
120
121
123 """Predicate for requiring membership in a number of groups."""
124
128
129
131 """Predicate for requiring membership in at least one group."""
132 error_message = "Not member of any group: %(group_list)s"
133
138
139
141 """Predicate for checking whether current visitor is anonymous."""
142 error_message = "Anonymous access denied"
143
149
150
152 """Predicate for checking whether visitor has a particular permission."""
153 error_message = "Permission denied: %(permission_name)s"
154
157
164
165
167 """Predicate for checking whether the visitor has all permissions."""
168
172
173
175 """Predicate for checking whether visitor has at least one permission."""
176 error_message = "No matching permissions: %(permission_list)s"
177
182
183
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
202
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
213 """Predicate for checking the visitor against a number of allowed hosts."""
214 error_message = "Access from this host is not permitted."
215
219
220
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
251 _wrapper.exposed = True
252 return _wrapper
253
254
256
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
278 return value
279 except IdentityException, e:
280 errors = [str(e)]
281 raise IdentityFailure(errors)
282
283
285
286 - def __init__(self, obj, require, exclude=[]):
287 self._object = obj
288 self._require = require
289 self._exclude = exclude
290
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
308 return value
309 except IdentityException, e:
310 errors = [str(e)]
311 raise IdentityFailure(errors)
312
318