{"id":8803,"library":"zope-security","title":"Zope Security Framework","description":"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.","status":"active","version":"8.3","language":"en","source_language":"en","source_url":"https://github.com/zopefoundation/zope.security","tags":["zope","security","access-control","permissions","roles","framework"],"install":[{"cmd":"pip install zope.security","lang":"bash","label":"Install latest stable version"}],"dependencies":[{"reason":"Core component providing `ClassSecurityInfo` and other fundamental security mechanisms.","package":"AccessControl","optional":false},{"reason":"Often used within a Zope application context, though `zope.security` can be used standalone.","package":"Zope","optional":true}],"imports":[{"symbol":"ClassSecurityInfo","correct":"from AccessControl.SecurityInfo import ClassSecurityInfo"},{"note":"While `zope.security.management` exists for new interactions, `AccessControl.SecurityManagement.getSecurityManager` is typically used for the active security manager in classic Zope contexts.","wrong":"from zope.security.management import getSecurityManager","symbol":"getSecurityManager","correct":"from AccessControl.SecurityManagement import getSecurityManager"},{"note":"The `checkPermission` function has been moved to `zope.security.permission` in more recent Zope versions. Always prefer `zope.security.permission` for direct checks.","wrong":"from AccessControl.Permission import checkPermission","symbol":"checkPermission","correct":"from zope.security.permission import checkPermission"},{"symbol":"IUnauthorized","correct":"from zope.security.interfaces import IUnauthorized"},{"symbol":"ACCESS_PUBLIC","correct":"from AccessControl.SecurityInfo import ACCESS_PUBLIC"}],"quickstart":{"code":"import os\nfrom AccessControl.SecurityInfo import ClassSecurityInfo, ACCESS_PUBLIC\nfrom AccessControl.SecurityManagement import setSecurityManager, getSecurityManager, noSecurityManager\nfrom AccessControl.users import UnrestrictedUser, nobody\n\n# Define a simple permission\nVIEW_FOO_PERMISSION = 'View Foo'\n\n# A dummy object to secure\nclass MySecuredObject:\n    security = ClassSecurityInfo()\n    security.declareObjectPublic() # Allow access to the object itself\n    security.declareProtected(VIEW_FOO_PERMISSION, 'foo_data')\n\n    def __init__(self, data):\n        self._data = data\n\n    def foo_data(self):\n        return self._data\n\n# --- Example Usage ---\n\n# 1. Setup a security manager (usually done by Zope)\n# For standalone testing, we can simulate an interaction\n\n# Create a principal (user)\nclass TestUser(UnrestrictedUser):\n    def __init__(self, id, roles=()):\n        super().__init__(id, '', roles, '')\n        self._roles = roles\n\n    def getRoles(self):\n        return self._roles\n\n# User with permission\nuser_with_permission = TestUser('editor', roles=('Manager', VIEW_FOO_PERMISSION))\n\n# User without permission\nuser_without_permission = TestUser('viewer', roles=())\n\n# Create a secured object\nobj = MySecuredObject('Secret Foo Content')\n\nprint(f\"Object data: {obj.foo_data()}\") # Access from unrestricted context is fine\n\ntry:\n    # Simulate an interaction for user_with_permission\n    setSecurityManager(user_with_permission)\n    sm = getSecurityManager()\n    print(f\"User '{sm.getUser().getId()}' has permission '{VIEW_FOO_PERMISSION}': {sm.checkPermission(VIEW_FOO_PERMISSION, obj)}\")\n    # In a real Zope context, calling obj.foo_data() would be checked here\nexcept Exception as e:\n    print(f\"Error with user_with_permission: {e}\")\nfinally:\n    noSecurityManager() # Clean up\n\nprint(\"---------------------\")\n\ntry:\n    # Simulate an interaction for user_without_permission\n    setSecurityManager(user_without_permission)\n    sm = getSecurityManager()\n    print(f\"User '{sm.getUser().getId()}' has permission '{VIEW_FOO_PERMISSION}': {sm.checkPermission(VIEW_FOO_PERMISSION, obj)}\")\n    # Attempting to access obj.foo_data() here would raise Unauthorized in a Zope context\nexcept Exception as e:\n    # In a real Zope context, this would likely be an IUnauthorized or similar\n    print(f\"Expected error for user_without_permission (no permission): {e}\")\nfinally:\n    noSecurityManager() # Clean up\n","lang":"python","description":"This quickstart demonstrates how to define and check permissions using `zope.security` (via `AccessControl`). It sets up a basic secured object with a custom permission and then simulates two different user interactions: one with the required permission and one without. It uses `ClassSecurityInfo` for declarative security and `getSecurityManager().checkPermission()` for programmatic checks. Note that in a full Zope application, the interaction and permission checks are often handled implicitly by the Zope Publisher."},"warnings":[{"fix":"Consult the specific Zope release notes (e.g., Zope 6.x `CHANGES.rst` on GitHub) for migration guides. Update build tools like `zc.buildout` and review Python version compatibility.","message":"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.","severity":"breaking","affected_versions":"Zope 6.0b1 and later, affecting projects migrating from older Zope versions."},{"fix":"Always provide explicit security declarations (e.g., using `ClassSecurityInfo.public()` or `declareProtected()`) for methods/attributes intended for external access. Avoid leading underscores for publicly accessible members.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Prefer explicit security declarations for each method or attribute. Use `setDefaultAccess('allow')` only when absolutely certain of its implications and that all sensitive parts are explicitly protected.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Create a Zope Product (a directory in `Products` with an `__init__.py`). In its `__init__.py`, use `Products.PythonScripts.Utility.allow_module('your_module_name')` to declare external modules as safe for import by TTW scripts. Restart Zope after changes.","message":"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.","severity":"gotcha","affected_versions":"All versions, specifically for TTW Python scripts"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure 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.","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'.","error":"AccessControl.unauthorized.Unauthorized: You are not authorized to access this resource."},{"fix":"Do 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.","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.","error":"AttributeError: 'SecurityProxy' object has no attribute '_some_private_attr'"},{"fix":"To 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.","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.","error":"ModuleNotFoundError: No module named 'some_external_module'"}]}