Switch to unified view

a/Allura/allura/lib/security.py b/Allura/allura/lib/security.py
...
...
295
            result = False
295
            result = False
296
        # log.info('%s: %s', txt, result)
296
        # log.info('%s: %s', txt, result)
297
        return result
297
        return result
298
    return TruthyCallable(predicate)
298
    return TruthyCallable(predicate)
299
299
300
def all_allowed(obj, user_or_role=None, project=None):
301
    '''
302
    List all the permission names that a given user or named role
303
    is allowed for a given object.  This list reflects the permissions
304
    for which has_access() would return True for the user (or a user
305
    in the given named role, e.g. Developer).
306
307
    Example:
308
309
        Given a tracker with the following ACL (pseudo-code):
310
            [
311
                ACE.allow(ProjectRole.by_name('Developer'), 'create'),
312
                ACE.allow(ProjectRole.by_name('Member'), 'post'),
313
                ACE.allow(ProjectRole.by_name('*anonymous'), 'read'),
314
            ]
315
316
        And user1 is in the Member group, then all_allowed(tracker, user1)
317
        will return:
318
319
            set(['post', 'read'])
320
321
        And all_allowed(tracker, ProjectRole.by_name('Developer')) will return:
322
323
            set(['create', 'post', 'read'])
324
    '''
325
    from allura import model as M
326
    anon = M.ProjectRole.anonymous(project)
327
    auth = M.ProjectRole.authenticated(project)
328
    if user_or_role is None:
329
        user_or_role = c.user
330
    if user_or_role is None:
331
        user_or_role = anon
332
    if isinstance(user_or_role, M.User):
333
        user_or_role = M.ProjectRole.by_user(user_or_role, project)
334
        if user_or_role is None:
335
            user_or_role = auth  # user is not member of project, treat as auth
336
    roles = [user_or_role]
337
    if user_or_role == anon:
338
        pass  # anon inherits nothing
339
    elif user_or_role == auth:
340
        roles += [anon]  # auth inherits from anon
341
    else:
342
        roles += [auth, anon]  # named group or user inherits from auth + anon
343
    role_ids = RoleCache(Credentials.get(), roles).reaching_ids  # match rules applicable to us
344
    perms = set()
345
    denied = defaultdict(set)
346
    while obj:  # traverse parent contexts
347
        for role_id in role_ids:
348
            for ace in obj.acl:
349
                if ace.permission in denied[role_id]:
350
                    # don't consider permissions that were denied for this role
351
                    continue
352
                if M.ACE.match(ace, role_id, ace.permission):
353
                    if ace.access == M.ACE.ALLOW:
354
                        perms.add(ace.permission)
355
                    else:
356
                        # explicit DENY overrides any ALLOW for this permission
357
                        # for this role_id in this ACL or parent(s) (but an ALLOW
358
                        # for a different role could still grant this permission)
359
                        denied[role_id].add(ace.permission)
360
        obj = obj.parent_security_context()
361
    if M.ALL_PERMISSIONS in perms:
362
        return set([M.ALL_PERMISSIONS])
363
    return perms
364
300
def require(predicate, message=None):
365
def require(predicate, message=None):
301
    '''
366
    '''
302
    Example: require(has_access(c.app, 'read'))
367
    Example: require(has_access(c.app, 'read'))
303
368
304
    :param callable predicate: truth function to call
369
    :param callable predicate: truth function to call