[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - ZopeSecurityPolicy.py:1.5

Jim Fulton jim@zope.com
Tue, 16 Jul 2002 19:41:48 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/Security
In directory cvs.zope.org:/tmp/cvs-serv19928/Zope/App/Security

Modified Files:
	ZopeSecurityPolicy.py 
Log Message:

Renamed (changed service type id) if all services with names ending in
"Service". Container services were given a plural form 
(e.g. "RoleService" => "Roles"), but other services just lost the
suffix (e.g. "AuthenticationService" => "Authentication").

Fixed bug in ZopeSecurityPolicy that caused placeless role-permission
grants to be ignored for placefully assigned roles.

Also changed grant lookup order. Now placeless grants are checked
*before* placeful grants.

Finished the implementation of placeful principal role grants
(re)started at the EuroPython sprint.

Fixed a bug in service directives that caused service component lookup
to fail for unpriviledged users. This caused authentication using
Stephan's authentication service to fail in mysterious ways.

Now you can create users with Stephan's auth service, and assign them
roles using principal-role grants.

Added code to the ZMI (boring) standard_macros template to display the
user, which, BTW is available in request.user.



=== Zope3/lib/python/Zope/App/Security/ZopeSecurityPolicy.py 1.4 => 1.5 ===
     def checkPermission(self, permission, object, context):
         # XXX We aren't really handling multiple principals yet
 
-        principals = { context.user : 1 }
-        assigned_roles = {}
-        roles = {}
-        seen_allow = 0
-
-        # Check the placeful principal permissions and aggregate the
-        # Roles in this context
-        for c in ContainmentIterator(object):
-            ppm = queryAdapter(c, IPrincipalPermissionManager, None,
-                               globalContext)
-            if ppm is not None: 
-                for principal in principals.keys():
-                    setting = ppm.getSetting(permission, principal)
-                    if setting is Deny:
-                        return 0 # Explicit deny on principal
-                    elif setting is Allow:
-                        return 1 # Explicit allow on principal
-                    
-            prm = queryAdapter(c, IPrincipalRoleManager, None, globalContext)
-            if prm is not None:
-                for principal in principals.keys():
-                    for role, setting in prm.getRolesForPrincipal(principal):
-                        if not (role in roles):
-                            roles[role] = 1
-                            if setting is Allow:
-                                assigned_roles[role] = 1
+        # mapping from principal to set of roles
+        principals = { context.user : {'Anonymous': Allow} }
         
-        # now check the global principal permissions
-        getSetting = principalPermissionManager.getSetting
-        for principal in principals.keys():
-            setting = getSetting(permission, principal)
-            if setting is Allow:
-                return 1 # Explicit allow on global principal
-            elif setting is Deny:
-                return 0 # Explicit deny on global principal
-                                    
-        # aggregate global roles
-        global_roles = principalRoleManager.getRolesForPrincipal(principal)
-        for principal in principals.keys():
-            for role, setting in global_roles:
-                if not (role in roles):
-                    roles[role] = 1
-                    if setting is Allow:
-                        assigned_roles[role] = 1
-                        
-        # Check the placeful role permissions, checking anonymous first
-        for c in ContainmentIterator(object):
-            rpm = queryAdapter(c, IRolePermissionManager, None, globalContext)
-            if rpm is not None:
-                for role in ['Anonymous'] + assigned_roles.keys():
-                    setting = rpm.getSetting(permission, role)
-                    if setting is Allow:
-                        seen_allow = 1 # Flag allow, but continue processing
-                    elif setting is Deny:
-                        return 0 # Deny on placeful role permission
-                if seen_allow:
-                    return 1 # Allow on placeful role permission
-            
-        # Last, check if there are any global role settings
-        getSetting = rolePermissionManager.getSetting
-        for principal in principals.keys():
-            for role, role_setting in [('Anonymous', Allow)] + global_roles:
-                if role_setting is Allow:
-                    setting = getSetting(permission, role)
-                    if setting == Allow:
-                        seen_allow = 1 # Flag allow and continue
-                    elif setting == Deny:
-                        return 0 # Deny on global role
-            if seen_allow:
-                return 1 # Allow on global role
+        role_permissions = {}
+        remove = {}
+        orig = object
+
+        # Look for placeless grants first.
+
+        # get placeless principal permissions
+        for principal in principals:
+            for permission, setting in getPermissionsForPrincipal(principal):
+                if setting is Deny:
+                    return 0
+                assert setting is Allow
+                remove[principal] = 1
+
+
+        # Clean out removed principals
+        if remove:
+            for principal in remove:
+                del principals[principal]
+            if principals:
+                # not done yet
+                remove.clear()
+            else:
+                # we've eliminated all the principals
+                return 1
+
+
+        # get placeless principal roles
+        for principal in principals:
+            roles = principals[principal]
+            for role, setting in getRolesForPrincipal(principal):
+                assert setting in (Allow, Deny)
+                if role not in roles:
+                    roles[role] = setting
 
-        return 0 # Deny by default
+        for perm, role, setting in (
+            rolePermissionManager.getRolesAndPermissions()):
+            assert setting in (Allow, Deny)
+            if role not in role_permissions:
+                role_permissions[role] = {perm: setting}
+            else:
+                if perm not in role_permissions[role]:
+                    role_permissions[role][perm] = setting
+
+        # Get principal permissions based on roles
+        for principal in principals:
+            roles = principals[principal]
+            for role in roles:
+                if role in role_permissions:
+                    if permission in role_permissions[role]:
+                        setting = role_permissions[role][permission]
+                        if setting is Deny:
+                            return 0
+                        remove[principal] = 1
+
+
+        # Clean out removed principals
+        if remove:
+            for principal in remove:
+                del principals[principal]
+            if principals:
+                # not done yet
+                remove.clear()
+            else:
+                # we've eliminated all the principals
+                return 1
+
+
+        # Look for placeful grants
+        for object in ContainmentIterator(orig):
+
+            # Copy specific principal permissions
+            prinper = queryAdapter(object, IPrincipalPermissionMap)
+            if prinper is not None:
+                for principal in principals:
+                    for permission, setting in (
+                        prinper.getPermissionsForPrincipal(principal)):
+
+                        if setting is Deny:
+                            return 0
+
+                        assert setting is Allow
+                        remove[principal] = 1
+
+            # Clean out removed principals
+            if remove:
+                for principal in remove:
+                    del principals[principal]
+                if principals:
+                    # not done yet
+                    remove.clear()
+                else:
+                    # we've eliminated all the principals
+                    return 1
+                
+            # Collect principal roles
+            prinrole = queryAdapter(object, IPrincipalRoleMap)
+            if prinrole is not None:
+                for principal in principals:
+                    roles = principals[principal]
+                    for role, setting in (
+                        prinrole.getRolesForPrincipal(principal)):
+                        assert setting in (Allow, Deny)
+                        if role not in roles:
+                            roles[role] = setting
+
+            # Collect role permissions
+            roleper = queryAdapter(object, IRolePermissionMap)
+            if roleper is not None:
+                for perm, role, setting in roleper.getRolesAndPermissions():
+                    assert setting in (Allow, Deny)
+                    if role not in role_permissions:
+                        role_permissions[role] = {perm: setting}
+                    else:
+                        if perm not in role_permissions[role]:
+                            role_permissions[role][perm] = setting
+
+            # Get principal permissions based on roles
+            for principal in principals:
+                roles = principals[principal]
+                for role in roles:
+                    if role in role_permissions:
+                        if permission in role_permissions[role]:
+                            setting = role_permissions[role][permission]
+                            if setting is Deny:
+                                return 0
+                            remove[principal] = 1
+
+            # Clean out removed principals
+            if remove:
+                for principal in remove:
+                    del principals[principal]
+                if principals:
+                    # not done yet
+                    remove.clear()
+                else:
+                    # we've eliminated all the principals
+                    return 1
 
+        return 0 # deny by default
 
 
 def permissionsOfPrincipal(principal, object):
@@ -163,6 +233,19 @@
     # Make two passes.
 
     # First, collect what we know about the principal:
+
+
+    # get placeless principal permissions
+    for permission, setting in getPermissionsForPrincipal(principal):
+        if permission not in permissions:
+            permissions[permission] = setting
+
+    # get placeless principal roles
+    for role, setting in getRolesForPrincipal(principal):
+        if role not in roles:
+            roles[role] = setting
+
+    # get placeful principal permissions and roles
     for object in ContainmentIterator(orig):
 
         # Copy specific principal permissions
@@ -180,17 +263,13 @@
                 if role not in roles:
                     roles[role] = setting
 
-    # get global principal permissions
-    for permission, setting in getPermissionsForPrincipal(principal):
-        if permission not in permissions:
-            permissions[permission] = setting
+    # Second, update permissions using principal 
 
-    # get glolbal principal roles
-    for role, setting in getRolesForPrincipal(principal):
-        if role not in roles:
-            roles[role] = setting
+    for perm, role, setting in (
+        rolePermissionManager.getRolesAndPermissions()):
+        if role in roles and perm not in permissions:
+            permissions[perm] = setting
 
-    # Second, update permissions using principal 
     for object in ContainmentIterator(orig):
 
         # Collect role permissions
@@ -200,11 +279,6 @@
                 if role in roles and perm not in permissions:
                     permissions[perm] = setting
 
-
-    for perm, role, setting in (
-        rolePermissionManager.getRolesAndPermissions()):
-        if role in roles and perm not in permissions:
-            permissions[perm] = setting
 
 
     result = [permission