Zope Security Framework
Zope security provides a generic mechanism to implement security policies on Python objects. It is part of the larger Zope ecosystem and defines roles, permissions, and security checks. As of April 2026, the current version is 8.3, and it follows the Zope release cadence with major releases typically every 2-6 months for actively supported versions.
Common errors
-
AccessControl.unauthorized.Unauthorized: You are not authorized to access this resource.
cause The current user or interaction lacks the necessary permissions to access a protected object or method. This can be due to missing role assignments, incorrect permission declarations, or attempting to access an unprotected resource that defaults to 'deny'.fixEnsure the current `IInteraction` (user) has the required roles for the permission protecting the resource. Verify that the object or method has the correct `ClassSecurityInfo` declarations (e.g., `public()`, `protected()`). If testing outside a full Zope environment, ensure a security manager is properly set up with an appropriate principal. -
AttributeError: 'SecurityProxy' object has no attribute '_some_private_attr'
cause Attempting to access an attribute or method on a security-proxied object that starts with an underscore (`_`). Security proxies automatically deny access to such attributes as a fundamental security measure.fixDo not prefix attributes or methods intended for public or protected access with an underscore. Refactor your code to expose data or functionality through explicitly declared public or protected methods. -
ModuleNotFoundError: No module named 'some_external_module'
cause This error occurs within a Zope 'through the web' (TTW) Python script when trying to import a Python module that has not been explicitly declared as safe for restricted code.fixTo make external modules available to TTW Python scripts, create a Zope Product (e.g., `Products/MyGlobalModules/__init__.py`) and use `from Products.PythonScripts.Utility import allow_module; allow_module('some_external_module')` within its `__init__.py`. Restart Zope for the changes to take effect.
Warnings
- breaking Major Zope releases (e.g., Zope 4 to 5, or 5 to 6) often introduce breaking changes that can affect `zope.security` and its usage. For instance, Zope 6.0b1 replaced `pkg_resources` namespaces with PEP 420 native namespaces, requiring `zc.buildout` version 5 or higher.
- gotcha By default, Zope's security policy denies access to any object or method that does not have explicit security declarations. Additionally, attributes or methods whose names begin with an underscore (`_`) are always denied access from restricted code.
- gotcha Using `security.setDefaultAccess('allow')` within a `ClassSecurityInfo` assertion should be done with extreme caution. This reverses the default deny-all policy to an allow-all policy for any attributes not explicitly protected, potentially exposing sensitive data or functionality.
- gotcha When using Python scripts 'through the web' (TTW) in Zope, security assertions for external Python modules (i.e., making them importable by restricted code) must be placed within an `__init__.py` file of a Zope 'Product' directory. Simply adding assertions in the module itself will not work.
Install
-
pip install zope.security
Imports
- ClassSecurityInfo
from AccessControl.SecurityInfo import ClassSecurityInfo
- getSecurityManager
from zope.security.management import getSecurityManager
from AccessControl.SecurityManagement import getSecurityManager
- checkPermission
from AccessControl.Permission import checkPermission
from zope.security.permission import checkPermission
- IUnauthorized
from zope.security.interfaces import IUnauthorized
- ACCESS_PUBLIC
from AccessControl.SecurityInfo import ACCESS_PUBLIC
Quickstart
import os
from AccessControl.SecurityInfo import ClassSecurityInfo, ACCESS_PUBLIC
from AccessControl.SecurityManagement import setSecurityManager, getSecurityManager, noSecurityManager
from AccessControl.users import UnrestrictedUser, nobody
# Define a simple permission
VIEW_FOO_PERMISSION = 'View Foo'
# A dummy object to secure
class MySecuredObject:
security = ClassSecurityInfo()
security.declareObjectPublic() # Allow access to the object itself
security.declareProtected(VIEW_FOO_PERMISSION, 'foo_data')
def __init__(self, data):
self._data = data
def foo_data(self):
return self._data
# --- Example Usage ---
# 1. Setup a security manager (usually done by Zope)
# For standalone testing, we can simulate an interaction
# Create a principal (user)
class TestUser(UnrestrictedUser):
def __init__(self, id, roles=()):
super().__init__(id, '', roles, '')
self._roles = roles
def getRoles(self):
return self._roles
# User with permission
user_with_permission = TestUser('editor', roles=('Manager', VIEW_FOO_PERMISSION))
# User without permission
user_without_permission = TestUser('viewer', roles=())
# Create a secured object
obj = MySecuredObject('Secret Foo Content')
print(f"Object data: {obj.foo_data()}") # Access from unrestricted context is fine
try:
# Simulate an interaction for user_with_permission
setSecurityManager(user_with_permission)
sm = getSecurityManager()
print(f"User '{sm.getUser().getId()}' has permission '{VIEW_FOO_PERMISSION}': {sm.checkPermission(VIEW_FOO_PERMISSION, obj)}")
# In a real Zope context, calling obj.foo_data() would be checked here
except Exception as e:
print(f"Error with user_with_permission: {e}")
finally:
noSecurityManager() # Clean up
print("---------------------")
try:
# Simulate an interaction for user_without_permission
setSecurityManager(user_without_permission)
sm = getSecurityManager()
print(f"User '{sm.getUser().getId()}' has permission '{VIEW_FOO_PERMISSION}': {sm.checkPermission(VIEW_FOO_PERMISSION, obj)}")
# Attempting to access obj.foo_data() here would raise Unauthorized in a Zope context
except Exception as e:
# In a real Zope context, this would likely be an IUnauthorized or similar
print(f"Expected error for user_without_permission (no permission): {e}")
finally:
noSecurityManager() # Clean up