You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2024/04/03 18:41:40 UTC

(allura) 02/07: [#8555] debugging option within has_access

This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8556-breaking-removal
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 2db77c578958a6322a0f5b512d9ab5a5dea3625a
Author: Dave Brondsema <db...@slashdotmedia.com>
AuthorDate: Tue Apr 2 17:44:46 2024 -0400

    [#8555] debugging option within has_access
---
 Allura/allura/lib/security.py | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/Allura/allura/lib/security.py b/Allura/allura/lib/security.py
index 3c16d05be..e73f6ad2b 100644
--- a/Allura/allura/lib/security.py
+++ b/Allura/allura/lib/security.py
@@ -293,6 +293,17 @@ def is_denied(obj, permission: str, user: M.User, project: M.Project) -> bool:
 
     return False
 
+def debug_obj(obj) -> str:
+    if hasattr(obj, 'url'):
+        url = obj.url
+        if callable(url):
+            try:
+                url = url()
+            except Exception:
+                url = obj._id
+        return f'{obj.__class__.__name__} {url}'
+    return str(obj)
+
 
 def has_access(obj, permission: str, user: M.User | None = None, project: M.Project | None = None):
     '''Return whether the given user has the permission name on the given object.
@@ -335,8 +346,12 @@ def has_access(obj, permission: str, user: M.User | None = None, project: M.Proj
     '''
     from allura import model as M
 
+    DEBUG = False
+
     def predicate(obj=obj, user=user, project=project, roles=None):
         if obj is None:
+            if DEBUG:
+                log.debug(f'{user} denied {permission} on {debug_obj(obj)} ({debug_obj(project)})')
             return False
         if roles is None:
             if user is None:
@@ -354,27 +369,31 @@ def has_access(obj, permission: str, user: M.User | None = None, project: M.Proj
                 else:
                     project = getattr(obj, 'project', None) or c.project
                     project = project.root_project
-            roles = cred.user_roles(
-                user_id=user._id, project_id=project._id).reaching_ids
+            roles: RoleCache = cred.user_roles(user_id=user._id, project_id=project._id).reaching_roles
 
         # TODO: move deny logic into loop below; see ticket [#6715]
         if is_denied(obj, permission, user, project):
+            if DEBUG:
+                log.debug(f"{user.username} '{permission}' denied on {debug_obj(obj)} ({debug_obj(project)})")
             return False
 
         chainable_roles = []
-        for rid in roles:
+        for role in roles:
             for ace in obj.acl:
-                if M.ACE.match(ace, rid, permission):
+                if M.ACE.match(ace, role['_id'], permission):
                     if ace.access == M.ACE.ALLOW:
                         # access is allowed
-                        # log.info('%s: True', txt)
+                        if DEBUG:
+                            log.debug(f"{user.username} '{permission}' granted on {debug_obj(obj)} ({debug_obj(project)})")
                         return True
                     else:
-                        # access is denied for this role
+                        # access is denied for this particular role
+                        if DEBUG:
+                            log.debug(f"{user.username} '{permission}' denied for role={role['name'] or role['_id']} (BUT continuing to see if other roles permit) on {debug_obj(obj)} ({debug_obj(project)})")
                         break
             else:
                 # access neither allowed or denied, may chain to parent context
-                chainable_roles.append(rid)
+                chainable_roles.append(role)
         parent = obj.parent_security_context()
         if parent and chainable_roles:
             result = has_access(parent, permission, user=user, project=project)(
@@ -385,7 +404,8 @@ def has_access(obj, permission: str, user: M.User | None = None, project: M.Proj
                 result = has_access(project, 'admin', user=user)()
         else:
             result = False
-        # log.info('%s: %s', txt, result)
+        if DEBUG:
+            log.debug(f"{user.username} '{permission}' {result} from parent(s) on {debug_obj(obj)} ({debug_obj(project)})")
         return result
     return TruthyCallable(predicate)