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

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

commit fc4c2764594653740ca3ea0a05d89b87bfb3a4bb
Author: Dave Brondsema <dbronds...@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)
 

Reply via email to