AccessControl Security Framework for Zope
raw JSON → 7.3 verified Thu Apr 16 auth: no python
AccessControl is the foundational security framework for the Zope application server, providing core components for authentication, authorization, and permission management within Zope Object Database (ZODB) applications. It defines security policies, user management interfaces, and permission checking mechanisms. The current version is 7.3, and it follows the release cadence of the wider Zope ecosystem, with stable updates aligning with Zope 5+ development.
pip install accesscontrol Common errors
error ImportError: cannot import name 'User' from 'AccessControl.User' ↓
cause Attempting to import a concrete user class directly from `AccessControl.User`. This module primarily defines interfaces and base classes, not specific user implementations for ZODB.
fix
For standard Zope installations using ZODB, import user-related classes from
OFS.User (e.g., from OFS.User import UserFolder) or refer to your specific user management product. If creating custom users, implement AccessControl.interfaces.IUser. error Unauthorized: You are not authorized to access this resource. (or similar 'Insufficient privileges') ↓
cause The current authenticated user (or anonymous user) in the security context lacks the necessary permission to perform the requested action on the target object.
fix
1. Verify the active user's roles (
getSecurityManager().getUser().getRoles()). 2. Check the permissions assigned to those roles on the specific object or its parent containers through Zope's management interface. 3. Ensure a security manager is correctly set (setSecurityManager()) for the current request/thread. error AttributeError: 'NoneType' object has no attribute 'checkPermission' (or similar errors when security manager is missing) ↓
cause `getSecurityManager()` is returning `None` because no security manager has been established for the current thread or context. `AccessControl` relies on a thread-local security manager to be present.
fix
Explicitly set a security manager using
AccessControl.SecurityManagement.setSecurityManager(my_security_manager_instance) before performing security-sensitive operations. In a Zope application, this is typically handled automatically by the Zope request lifecycle. Warnings
breaking AccessControl versions 7.x require Python 3.10 or newer. Users migrating from older Python 3 versions (e.g., 3.8, 3.9) or Python 2 will encounter incompatibility errors. ↓
fix Upgrade Python environment to 3.10+ or use an older AccessControl version compatible with your Python version (e.g., AccessControl 6.x for Python 3.9, 5.x for Python 3.8).
gotcha AccessControl is designed specifically for Zope applications and is tightly coupled with the Zope Object Database (ZODB) and its request lifecycle. It is not a standalone, general-purpose security library (e.g., like Flask-Security or Django-Auth) and attempting to use it outside a proper Zope context will require extensive mocking or lead to unexpected behavior. ↓
fix Ensure you are developing within a Zope application environment or prepare a comprehensive mock setup that simulates Zope's security context, object acquisition, and ZODB integration.
gotcha Using `AccessControl.User.UnrestrictedUser` in production code can be a significant security risk. As its name implies, this user bypasses all permission checks, effectively granting full administrative access. It is primarily intended for testing, bootstrapping, or highly controlled administrative scripts. ↓
fix Avoid using `UnrestrictedUser` in user-facing production code. Instead, define specific user roles and permissions, and ensure security contexts are correctly established for authenticated users with appropriate privileges.
Imports
- setSecurityManager
from AccessControl.SecurityManagement import setSecurityManager - getSecurityManager
from AccessControl.SecurityManagement import getSecurityManager - UnrestrictedUser wrong
from AccessControl.SecurityManagement import UnrestrictedUsercorrectfrom AccessControl.User import UnrestrictedUser - view
from AccessControl.Permissions import view
Quickstart
import os
from AccessControl.SecurityManagement import setSecurityManager, getSecurityManager
from AccessControl.User import UnrestrictedUser
from AccessControl.Permissions import view as ViewPermission
# 1. Define a mock Security Manager and User for demonstration
# In a real Zope app, these would be provided by the Zope environment.
class MockUser(UnrestrictedUser):
def __init__(self, id, password, roles, domains, permissions=None):
super().__init__(id, password, roles, domains)
self._permissions = permissions if permissions is not None else {}
def getRoles(self):
return self._roles
def has_permission(self, permission_name, context):
# Simplified check: Manager role allows everything, otherwise check specific permissions.
if 'Manager' in self.getRoles():
return True
return permission_name in self._permissions.get(context.__class__.__name__, [])
class MockSecurityManager:
def __init__(self, user):
self._user = user
def getUser(self):
return self._user
def checkPermission(self, permission_name, context_object):
# In a real Zope app, this involves complex role/permission mappings.
return self._user.has_permission(permission_name, context_object)
def validate(self, granted_roles, context_object, permission_name):
# Simplified for demonstration. Real method involves deep Zope security context.
return self._user.has_permission(permission_name, context_object)
# 2. Define a mock context object that can be secured
class Document:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"<Document: {self.name}>"
# 3. Create mock users with different roles and permissions
admin_user = MockUser('admin', 'pwd', ['Manager'], 'all', permissions={'Document': [ViewPermission, 'Edit']})
editor_user = MockUser('editor', 'pwd', ['Editor'], 'local', permissions={'Document': ['Edit']})
viewer_user = MockUser('viewer', 'pwd', ['Viewer'], 'local', permissions={'Document': [ViewPermission]})
# 4. Create a document to test permissions against
my_document = Document("Secret Report")
print("--- Admin User Context ---")
setSecurityManager(MockSecurityManager(admin_user))
sm = getSecurityManager()
current_user = sm.getUser()
print(f"Current User: {current_user.getUserName()} (Roles: {current_user.getRoles()})")
print(f"Can '{ViewPermission}' on {my_document}? {sm.checkPermission(ViewPermission, my_document)}")
print(f"Can 'Edit' on {my_document}? {sm.checkPermission('Edit', my_document)}")
print("\n--- Viewer User Context ---")
setSecurityManager(MockSecurityManager(viewer_user))
sm = getSecurityManager()
current_user = sm.getUser()
print(f"Current User: {current_user.getUserName()} (Roles: {current_user.getRoles()})")
print(f"Can '{ViewPermission}' on {my_document}? {sm.checkPermission(ViewPermission, my_document)}")
print(f"Can 'Edit' on {my_document}? {sm.checkPermission('Edit', my_document)}")
print("\n--- Editor User Context ---")
setSecurityManager(MockSecurityManager(editor_user))
sm = getSecurityManager()
current_user = sm.getUser()
print(f"Current User: {current_user.getUserName()} (Roles: {current_user.getRoles()})")
print(f"Can '{ViewPermission}' on {my_document}? {sm.checkPermission(ViewPermission, my_document)}")
print(f"Can 'Edit' on {my_document}? {sm.checkPermission('Edit', my_document)}")
# In a real Zope app, you might restore the default security manager or a different one
# setSecurityManager(None) # Clears the thread-local manager