AccessControl 7.4__tar.gz → 7.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {accesscontrol-7.4 → accesscontrol-7.6}/.manylinux-install.sh +3 -10
- {accesscontrol-7.4 → accesscontrol-7.6}/.pre-commit-config.yaml +14 -1
- {accesscontrol-7.4 → accesscontrol-7.6}/CHANGES.rst +44 -0
- accesscontrol-7.6/COPYRIGHT.txt +1 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/PKG-INFO +47 -4
- {accesscontrol-7.4 → accesscontrol-7.6}/docs/AccessControl.rst +14 -14
- {accesscontrol-7.4 → accesscontrol-7.6}/pyproject.toml +16 -16
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/SecurityInfo.py +114 -2
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/SimpleObjectPolicies.py +8 -2
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/__init__.py +2 -1
- accesscontrol-7.6/src/AccessControl/frozen.py +57 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/meta.zcml +1 -1
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/actual_python.py +2 -2
- accesscontrol-7.6/src/AccessControl/tests/public_module/__init__.py +11 -0
- accesscontrol-7.6/src/AccessControl/tests/testModuleSecurity.py +335 -0
- accesscontrol-7.6/src/AccessControl/tests/test_frozen.py +124 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl.egg-info/PKG-INFO +47 -4
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl.egg-info/SOURCES.txt +2 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/tox.ini +0 -2
- accesscontrol-7.4/COPYRIGHT.txt +0 -1
- accesscontrol-7.4/src/AccessControl/tests/public_module/__init__.py +0 -7
- accesscontrol-7.4/src/AccessControl/tests/testModuleSecurity.py +0 -113
- {accesscontrol-7.4 → accesscontrol-7.6}/.manylinux.sh +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/CONTRIBUTING.md +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/HISTORY.rst +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/LICENSE.txt +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/MANIFEST.in +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/README.rst +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/buildout.cfg +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/docs/requestmethod.rst +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/include/Acquisition/Acquisition.h +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/include/ExtensionClass/ExtensionClass.h +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/include/ExtensionClass/_compat.h +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/setup.cfg +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/setup.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/AuthEncoding.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/ImplC.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/ImplPython.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/Implementation.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/Owned.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/Permission.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/PermissionMapping.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/PermissionRole.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/Permissions.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/Role.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/SecurityManagement.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/SecurityManager.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/SpecialUsers.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/User.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/ZopeGuards.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/ZopeSecurityPolicy.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/_compat.h +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/cAccessControl.c +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/class_init.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/configure.zcml +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/interfaces.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/logger_wrapper.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/metaconfigure.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/owner.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/permissions.zcml +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/requestmethod.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/rolemanager.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/safe_formatter.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/security.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tainted.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/__init__.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/mixed_module/__init__.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/mixed_module/submodule/__init__.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/private_module/__init__.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/private_module/submodule/__init__.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/public_module/submodule/__init__.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testClassSecurityInfo.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testImplementation.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testPermissionMapping.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testPermissionRole.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testSecurityManager.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testZCML.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testZopeGuards.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/testZopeSecurityPolicy.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_owner.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_requestmethod.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_rolemanager.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_safe_formatter.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_safeiter.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_tainted.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_userfolder.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/tests/test_users.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/unauthorized.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/userfolder.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl/users.py +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl.egg-info/dependency_links.txt +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl.egg-info/entry_points.txt +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl.egg-info/requires.txt +0 -0
- {accesscontrol-7.4 → accesscontrol-7.6}/src/AccessControl.egg-info/top_level.txt +0 -0
|
@@ -28,7 +28,6 @@ yum -y install libffi-devel
|
|
|
28
28
|
|
|
29
29
|
tox_env_map() {
|
|
30
30
|
case $1 in
|
|
31
|
-
*"cp310"*) echo 'py310';;
|
|
32
31
|
*"cp311"*) echo 'py311';;
|
|
33
32
|
*"cp312"*) echo 'py312';;
|
|
34
33
|
*"cp313"*) echo 'py313';;
|
|
@@ -41,19 +40,13 @@ tox_env_map() {
|
|
|
41
40
|
# Compile wheels
|
|
42
41
|
for PYBIN in /opt/python/*/bin; do
|
|
43
42
|
if \
|
|
44
|
-
[[ "${PYBIN}" == *"cp310/"* ]] || \
|
|
45
43
|
[[ "${PYBIN}" == *"cp311/"* ]] || \
|
|
46
44
|
[[ "${PYBIN}" == *"cp312/"* ]] || \
|
|
47
45
|
[[ "${PYBIN}" == *"cp313/"* ]] || \
|
|
48
46
|
[[ "${PYBIN}" == *"cp314/"* ]] || \
|
|
49
|
-
[[ "${PYBIN}" == *"cp315/"* ]]
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"${PYBIN}/pip" wheel /io/ --pre -w wheelhouse/
|
|
53
|
-
else
|
|
54
|
-
"${PYBIN}/pip" install -e /io/
|
|
55
|
-
"${PYBIN}/pip" wheel /io/ -w wheelhouse/
|
|
56
|
-
fi
|
|
47
|
+
[[ "${PYBIN}" == *"cp315/"* ]] ; then
|
|
48
|
+
"${PYBIN}/pip" install -e /io/
|
|
49
|
+
"${PYBIN}/pip" wheel /io/ -w wheelhouse/
|
|
57
50
|
if [ `uname -m` == 'aarch64' ]; then
|
|
58
51
|
cd /io/
|
|
59
52
|
${PYBIN}/pip install tox
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
# https://github.com/zopefoundation/meta/tree/master/src/zope/meta/c-code
|
|
3
3
|
minimum_pre_commit_version: '3.6'
|
|
4
4
|
repos:
|
|
5
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
6
|
+
rev: v6.0.0
|
|
7
|
+
hooks:
|
|
8
|
+
- id: check-case-conflict
|
|
9
|
+
- id: check-merge-conflict
|
|
10
|
+
- id: check-toml
|
|
11
|
+
- id: check-yaml
|
|
12
|
+
- id: end-of-file-fixer
|
|
13
|
+
- id: trailing-whitespace
|
|
5
14
|
- repo: https://github.com/pycqa/isort
|
|
6
15
|
rev: "8.0.1"
|
|
7
16
|
hooks:
|
|
@@ -15,7 +24,7 @@ repos:
|
|
|
15
24
|
rev: v3.21.2
|
|
16
25
|
hooks:
|
|
17
26
|
- id: pyupgrade
|
|
18
|
-
args: [--
|
|
27
|
+
args: [--py311-plus]
|
|
19
28
|
- repo: https://github.com/isidentical/teyit
|
|
20
29
|
rev: 0.4.3
|
|
21
30
|
hooks:
|
|
@@ -27,3 +36,7 @@ repos:
|
|
|
27
36
|
- id: flake8
|
|
28
37
|
additional_dependencies:
|
|
29
38
|
- flake8-debugger == 4.1.2
|
|
39
|
+
- repo: https://github.com/sphinx-contrib/sphinx-lint
|
|
40
|
+
rev: v1.0.2
|
|
41
|
+
hooks:
|
|
42
|
+
- id: sphinx-lint
|
|
@@ -4,9 +4,53 @@ Change log
|
|
|
4
4
|
For changes before version 3.0, see ``HISTORY.rst``.
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
7.6 (2026-10-30)
|
|
8
|
+
----------------
|
|
9
|
+
|
|
10
|
+
- Add ``freeze_security_declarations``. Call it once all code has been
|
|
11
|
+
loaded, for example when Zope has started. Afterwards, any change to
|
|
12
|
+
module security declarations, for example with ``allow_module`` or
|
|
13
|
+
``ModuleSecurityInfo``, raises ``Forbidden``. The same is true for
|
|
14
|
+
``allow_class``, ``allow_type`` and other changes to
|
|
15
|
+
``ContainerAssertions``. Dangerous modules like ``os``, ``subprocess``,
|
|
16
|
+
``AccessControl`` itself, and third-party network libraries like
|
|
17
|
+
``requests`` and ``httpx``, that are
|
|
18
|
+
fully accessible from restricted code, for example with ``allow_module``,
|
|
19
|
+
are logged as a warning. Pass ``dangerous_modules`` to change which
|
|
20
|
+
modules are dangerous. Calling it a second time does nothing. Call
|
|
21
|
+
``check_dangerous_modules`` to check other modules, also after the freeze.
|
|
22
|
+
|
|
23
|
+
- Remove module security declaration for ``sets``.
|
|
24
|
+
This module only existed in Python 2.
|
|
25
|
+
|
|
26
|
+
- Add additional safeguards to ``SecurityInfo.allow_class`` / ``allow_module``
|
|
27
|
+
and ``SimpleObjectPolicies.allow_type`` to prevent use from untrusted code.
|
|
28
|
+
|
|
29
|
+
- Add support for Python 3.15.
|
|
30
|
+
|
|
31
|
+
- Drop support for Python 3.10.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
7.5 (2026-08-20)
|
|
35
|
+
----------------
|
|
36
|
+
|
|
37
|
+
- Add final support for Python 3.15.
|
|
38
|
+
|
|
39
|
+
- Switch to PyPI Trusted Publishing.
|
|
40
|
+
|
|
41
|
+
|
|
7
42
|
7.4 (2026-07-13)
|
|
8
43
|
----------------
|
|
9
44
|
|
|
45
|
+
- Prevent information disclosure through the ``format`` and ``format_map``
|
|
46
|
+
methods of ``str`` subclasses: the guards which route these methods to the
|
|
47
|
+
safe formatter only covered ``str`` itself, so a subclass instance could be
|
|
48
|
+
used to read otherwise inaccessible objects via attribute access and
|
|
49
|
+
subscription in a format string
|
|
50
|
+
(fixes `GHSA-pq59-9fq7-m886
|
|
51
|
+
<https://github.com/zopefoundation/AccessControl/security/advisories/GHSA-pq59-9fq7-m886>`_,
|
|
52
|
+
CVE-2026-77401).
|
|
53
|
+
|
|
10
54
|
- Fix a parity defect between the Python and C implementations of
|
|
11
55
|
``guarded_getattr``: the pure-Python implementation keyed the container
|
|
12
56
|
assertion on ``type(value.__self__)`` instead of ``type(inst)``, so under
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Zope Foundation and Contributors
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AccessControl
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.6
|
|
4
4
|
Summary: Security framework for Zope
|
|
5
5
|
Author-email: Zope Foundation and contributors <zope-dev@zope.dev>
|
|
6
6
|
Maintainer-email: Plone Foundation and contributors <zope-dev@zope.dev>
|
|
@@ -16,14 +16,13 @@ Classifier: Framework :: Zope :: 5
|
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
24
22
|
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
25
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
|
-
Requires-Python: >=3.
|
|
25
|
+
Requires-Python: >=3.11
|
|
27
26
|
Description-Content-Type: text/x-rst
|
|
28
27
|
License-File: LICENSE.txt
|
|
29
28
|
Requires-Dist: Acquisition
|
|
@@ -73,9 +72,53 @@ Change log
|
|
|
73
72
|
For changes before version 3.0, see ``HISTORY.rst``.
|
|
74
73
|
|
|
75
74
|
|
|
75
|
+
7.6 (2026-10-30)
|
|
76
|
+
----------------
|
|
77
|
+
|
|
78
|
+
- Add ``freeze_security_declarations``. Call it once all code has been
|
|
79
|
+
loaded, for example when Zope has started. Afterwards, any change to
|
|
80
|
+
module security declarations, for example with ``allow_module`` or
|
|
81
|
+
``ModuleSecurityInfo``, raises ``Forbidden``. The same is true for
|
|
82
|
+
``allow_class``, ``allow_type`` and other changes to
|
|
83
|
+
``ContainerAssertions``. Dangerous modules like ``os``, ``subprocess``,
|
|
84
|
+
``AccessControl`` itself, and third-party network libraries like
|
|
85
|
+
``requests`` and ``httpx``, that are
|
|
86
|
+
fully accessible from restricted code, for example with ``allow_module``,
|
|
87
|
+
are logged as a warning. Pass ``dangerous_modules`` to change which
|
|
88
|
+
modules are dangerous. Calling it a second time does nothing. Call
|
|
89
|
+
``check_dangerous_modules`` to check other modules, also after the freeze.
|
|
90
|
+
|
|
91
|
+
- Remove module security declaration for ``sets``.
|
|
92
|
+
This module only existed in Python 2.
|
|
93
|
+
|
|
94
|
+
- Add additional safeguards to ``SecurityInfo.allow_class`` / ``allow_module``
|
|
95
|
+
and ``SimpleObjectPolicies.allow_type`` to prevent use from untrusted code.
|
|
96
|
+
|
|
97
|
+
- Add support for Python 3.15.
|
|
98
|
+
|
|
99
|
+
- Drop support for Python 3.10.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
7.5 (2026-08-20)
|
|
103
|
+
----------------
|
|
104
|
+
|
|
105
|
+
- Add final support for Python 3.15.
|
|
106
|
+
|
|
107
|
+
- Switch to PyPI Trusted Publishing.
|
|
108
|
+
|
|
109
|
+
|
|
76
110
|
7.4 (2026-07-13)
|
|
77
111
|
----------------
|
|
78
112
|
|
|
113
|
+
- Prevent information disclosure through the ``format`` and ``format_map``
|
|
114
|
+
methods of ``str`` subclasses: the guards which route these methods to the
|
|
115
|
+
safe formatter only covered ``str`` itself, so a subclass instance could be
|
|
116
|
+
used to read otherwise inaccessible objects via attribute access and
|
|
117
|
+
subscription in a format string
|
|
118
|
+
(fixes `GHSA-pq59-9fq7-m886
|
|
119
|
+
<https://github.com/zopefoundation/AccessControl/security/advisories/GHSA-pq59-9fq7-m886>`_,
|
|
120
|
+
CVE-2026-77401).
|
|
121
|
+
|
|
79
122
|
- Fix a parity defect between the Python and C implementations of
|
|
80
123
|
``guarded_getattr``: the pure-Python implementation keyed the container
|
|
81
124
|
assertion on ``type(value.__self__)`` instead of ``type(inst)``, so under
|
|
@@ -30,15 +30,15 @@ Types of access
|
|
|
30
30
|
|
|
31
31
|
A "type of access" is a named grouping of 0 or more of the
|
|
32
32
|
permissions defined by an object. All objects have one predefined
|
|
33
|
-
type of access called Full Access (all permissions defined by that
|
|
34
|
-
object). A user who has the special role "Manager" always has Full
|
|
35
|
-
Access to all objects at or below the level in the object hierarchy
|
|
33
|
+
type of access called Full Access (all permissions defined by that
|
|
34
|
+
object). A user who has the special role "Manager" always has Full
|
|
35
|
+
Access to all objects at or below the level in the object hierarchy
|
|
36
36
|
at which the user is defined.
|
|
37
37
|
|
|
38
38
|
New types of access may be defined as combinations of the
|
|
39
39
|
various permissions defined by a given object. These new
|
|
40
40
|
types of access may be defined by the programmer, or by
|
|
41
|
-
users at runtime.
|
|
41
|
+
users at runtime.
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
|
|
@@ -50,13 +50,13 @@ A role is a name that ties users (authentication of identity)
|
|
|
50
50
|
to permissions (authorization for that identity) in the system.
|
|
51
51
|
Roles may be defined in any Folder (or Folderish) object in the
|
|
52
52
|
system. Sub folders can make use of roles defined higher in the
|
|
53
|
-
hierarchy. These roles can be assigned to users. All users,
|
|
54
|
-
including non-authenticated users have the built-in role of
|
|
55
|
-
"Anonymous".
|
|
53
|
+
hierarchy. These roles can be assigned to users. All users,
|
|
54
|
+
including non-authenticated users have the built-in role of
|
|
55
|
+
"Anonymous".
|
|
56
56
|
|
|
57
|
-
Principia objects allow the association of defined roles
|
|
58
|
-
with a single "type of access" each, in the context of that
|
|
59
|
-
object. A single role is associated with one and only one
|
|
57
|
+
Principia objects allow the association of defined roles
|
|
58
|
+
with a single "type of access" each, in the context of that
|
|
59
|
+
object. A single role is associated with one and only one
|
|
60
60
|
type of access in the context of a given object.
|
|
61
61
|
|
|
62
62
|
|
|
@@ -191,14 +191,14 @@ Example:
|
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
The developer may also predefine useful types of access, by
|
|
194
|
-
specifying an __ac_types__ attribute. This should be a tuple of
|
|
195
|
-
tuples, where each tuple represents a type of access and contains
|
|
196
|
-
a string name as its first element and a list of permission names
|
|
194
|
+
specifying an __ac_types__ attribute. This should be a tuple of
|
|
195
|
+
tuples, where each tuple represents a type of access and contains
|
|
196
|
+
a string name as its first element and a list of permission names
|
|
197
197
|
as its second element.
|
|
198
198
|
|
|
199
199
|
By default, only "Full Access" is defined (by the RoleManager mixin).
|
|
200
200
|
If you wish to override __ac_types__ to provide convenient types of
|
|
201
|
-
access, you must always be sure to define "Full Access" as containing
|
|
201
|
+
access, you must always be sure to define "Full Access" as containing
|
|
202
202
|
the names of all possible permissions for your object.
|
|
203
203
|
|
|
204
204
|
Example:
|
|
@@ -9,11 +9,11 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
|
|
10
10
|
[project]
|
|
11
11
|
name = "AccessControl"
|
|
12
|
-
version = "7.
|
|
12
|
+
version = "7.6"
|
|
13
13
|
description = "Security framework for Zope"
|
|
14
14
|
keywords = ["security", "access", "authorization"]
|
|
15
15
|
dynamic = ["readme"]
|
|
16
|
-
requires-python = ">=3.
|
|
16
|
+
requires-python = ">=3.11"
|
|
17
17
|
license = "ZPL-2.1"
|
|
18
18
|
authors = [
|
|
19
19
|
{ name = "Zope Foundation and contributors", email = "zope-dev@zope.dev" },
|
|
@@ -22,20 +22,19 @@ maintainers = [
|
|
|
22
22
|
{ name = "Plone Foundation and contributors", email = "zope-dev@zope.dev" },
|
|
23
23
|
]
|
|
24
24
|
classifiers = [
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"Programming Language :: Python :: Implementation :: CPython",
|
|
25
|
+
"Development Status :: 6 - Mature",
|
|
26
|
+
"Environment :: Web Environment",
|
|
27
|
+
"Framework :: Zope",
|
|
28
|
+
"Framework :: Zope :: 5",
|
|
29
|
+
"Operating System :: OS Independent",
|
|
30
|
+
"Programming Language :: Python",
|
|
31
|
+
"Programming Language :: Python :: 3",
|
|
32
|
+
"Programming Language :: Python :: 3.11",
|
|
33
|
+
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Programming Language :: Python :: 3.13",
|
|
35
|
+
"Programming Language :: Python :: 3.14",
|
|
36
|
+
"Programming Language :: Python :: 3.15",
|
|
37
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
39
38
|
]
|
|
40
39
|
dependencies = [
|
|
41
40
|
"Acquisition",
|
|
@@ -108,4 +107,5 @@ readme = {file = ["README.rst", "CHANGES.rst"]}
|
|
|
108
107
|
|
|
109
108
|
[tool.zest-releaser]
|
|
110
109
|
create-wheel = false
|
|
110
|
+
extra-message = ""
|
|
111
111
|
upload-pypi = false
|
|
@@ -44,6 +44,7 @@ from logging import getLogger
|
|
|
44
44
|
from Acquisition import Implicit
|
|
45
45
|
from Persistence import Persistent
|
|
46
46
|
|
|
47
|
+
from AccessControl import frozen
|
|
47
48
|
from AccessControl.class_init import InitializeClass
|
|
48
49
|
from AccessControl.ImplPython import _what_not_even_god_should_do
|
|
49
50
|
|
|
@@ -258,8 +259,8 @@ class ClassSecurityInformation(ClassSecurityInfo):
|
|
|
258
259
|
access = 0
|
|
259
260
|
|
|
260
261
|
|
|
261
|
-
_moduleSecurity =
|
|
262
|
-
_appliedModuleSecurity =
|
|
262
|
+
_moduleSecurity = frozen.FreezableDict()
|
|
263
|
+
_appliedModuleSecurity = frozen.FreezableDict()
|
|
263
264
|
|
|
264
265
|
|
|
265
266
|
def secureModule(mname, *imp):
|
|
@@ -333,6 +334,17 @@ class _ModuleSecurityInfo(SecurityInfo):
|
|
|
333
334
|
|
|
334
335
|
return getattr(self, 'access', 0)
|
|
335
336
|
|
|
337
|
+
def _setaccess(self, names, access):
|
|
338
|
+
frozen.check_not_frozen()
|
|
339
|
+
super()._setaccess(names, access)
|
|
340
|
+
|
|
341
|
+
setDefaultAccess__roles__ = ACCESS_PRIVATE
|
|
342
|
+
|
|
343
|
+
def setDefaultAccess(self, access):
|
|
344
|
+
"""Declare default attribute access policy."""
|
|
345
|
+
frozen.check_not_frozen()
|
|
346
|
+
super().setDefaultAccess(access)
|
|
347
|
+
|
|
336
348
|
apply__roles__ = ACCESS_PRIVATE
|
|
337
349
|
|
|
338
350
|
def apply(self, dict):
|
|
@@ -380,11 +392,111 @@ def allow_module(module_name):
|
|
|
380
392
|
dot = module_name.find('.', dot + 1)
|
|
381
393
|
|
|
382
394
|
|
|
395
|
+
allow_module.__roles__ = ACCESS_PRIVATE
|
|
396
|
+
|
|
397
|
+
# Modules that should never be fully accessible from restricted code.
|
|
398
|
+
# A declaration for one of these, or a submodule, is logged by
|
|
399
|
+
# check_dangerous_modules, which freeze_security_declarations calls.
|
|
400
|
+
# PLEASE NOTE: This listing cannot ever be complete and it cannot guard
|
|
401
|
+
# against malicious or sloppy code exposing other unsafe modules! Its
|
|
402
|
+
# purpose is just informational, it is not a safe catch-all.
|
|
403
|
+
DANGEROUS_MODULES = frozenset((
|
|
404
|
+
# processes and code execution
|
|
405
|
+
'_posixsubprocess', '_thread', 'asyncio', 'atexit', 'bdb', 'builtins',
|
|
406
|
+
'code', 'codeop', 'concurrent', 'copyreg', 'cProfile', 'ctypes',
|
|
407
|
+
'_ctypes', 'doctest', 'faulthandler', 'gc', 'importlib', 'inspect',
|
|
408
|
+
'logging', 'marshal', 'multiprocessing', 'nt', 'operator', 'os', 'pdb',
|
|
409
|
+
'pickle', '_pickle', 'pkgutil', 'posix', 'profile', 'pty', 'pydoc',
|
|
410
|
+
'runpy', 'shelve', 'signal', 'site', 'subprocess', 'sys', 'threading',
|
|
411
|
+
'timeit', 'trace', 'traceback', 'types', 'unittest', 'webbrowser',
|
|
412
|
+
'zipimport',
|
|
413
|
+
# filesystem
|
|
414
|
+
'bz2', 'codecs', 'compileall', 'configparser', 'dbm', 'ensurepip',
|
|
415
|
+
'fcntl', 'filecmp', 'fileinput', 'genericpath', 'glob', 'gzip', 'io',
|
|
416
|
+
'_io', 'linecache', 'lzma', 'mailbox', 'mmap', 'netrc', 'ntpath',
|
|
417
|
+
'pathlib', 'posixpath', 'py_compile', 'shutil', 'sqlite3', 'sysconfig',
|
|
418
|
+
'tarfile', 'tempfile', 'venv', 'zipapp', 'zipfile',
|
|
419
|
+
# network
|
|
420
|
+
'ftplib', 'http', 'imaplib', 'poplib', 'select', 'selectors', 'smtplib',
|
|
421
|
+
'socket', 'socketserver', 'ssl', 'urllib', 'wsgiref', 'xmlrpc',
|
|
422
|
+
# information about the system, or process wide state
|
|
423
|
+
'getpass', 'grp', 'locale', 'platform', 'pwd', 'resource',
|
|
424
|
+
# Zope: security declarations and policy, switching users or sites,
|
|
425
|
+
# transactions, the database
|
|
426
|
+
'AccessControl', 'App', 'transaction', 'ZODB', 'Zope2',
|
|
427
|
+
'zope.component.hooks', 'zope.interface',
|
|
428
|
+
# third-party network libraries: requests from the server itself can
|
|
429
|
+
# reach internal services, and httpx can use local Unix sockets
|
|
430
|
+
'aiohttp', 'httpx', 'pycurl', 'requests', 'urllib3',
|
|
431
|
+
))
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def freeze_security_declarations(dangerous_modules=DANGEROUS_MODULES):
|
|
435
|
+
"""Refuse changes to security declarations from now on.
|
|
436
|
+
|
|
437
|
+
Call this once all code has been loaded, for example when Zope has
|
|
438
|
+
started. Afterwards, ModuleSecurityInfo, allow_module, allow_class and
|
|
439
|
+
allow_type raise Forbidden for any change, so new modules, classes and
|
|
440
|
+
types cannot be opened up to restricted code.
|
|
441
|
+
|
|
442
|
+
Normal class security declarations with ClassSecurityInfo still work,
|
|
443
|
+
because classes may be imported later, for example when loading objects
|
|
444
|
+
from the database.
|
|
445
|
+
|
|
446
|
+
Pending declarations are applied first, because importing a module from
|
|
447
|
+
restricted code would otherwise still need to change them. Dangerous
|
|
448
|
+
modules that are fully accessible are logged as a warning, see
|
|
449
|
+
check_dangerous_modules.
|
|
450
|
+
|
|
451
|
+
Calling this when security declarations are already frozen does nothing.
|
|
452
|
+
"""
|
|
453
|
+
if frozen.is_frozen():
|
|
454
|
+
return
|
|
455
|
+
# Most of these modules have likely already been imported, because the
|
|
456
|
+
# declarations are usually made in the module itself or its package.
|
|
457
|
+
# So this is fast.
|
|
458
|
+
for name in sorted(_moduleSecurity):
|
|
459
|
+
try:
|
|
460
|
+
secureModule(name, {}, {})
|
|
461
|
+
except ImportError:
|
|
462
|
+
LOG.info(f'Could not import {name!r} to apply its'
|
|
463
|
+
' module security declarations.')
|
|
464
|
+
|
|
465
|
+
check_dangerous_modules(dangerous_modules)
|
|
466
|
+
frozen.freeze()
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def check_dangerous_modules(dangerous_modules=DANGEROUS_MODULES):
|
|
470
|
+
"""Log a warning for dangerous modules accessible from restricted code.
|
|
471
|
+
|
|
472
|
+
Only modules that are fully accessible are logged, for example with
|
|
473
|
+
allow_module, not modules where only specific names are public.
|
|
474
|
+
A submodule of a dangerous module is dangerous as well. Pass
|
|
475
|
+
dangerous_modules to check other modules, for example ``{'my.package'}``.
|
|
476
|
+
"""
|
|
477
|
+
for name in sorted(set(_moduleSecurity) | set(_appliedModuleSecurity)):
|
|
478
|
+
modsec = _appliedModuleSecurity.get(name) or _moduleSecurity[name]
|
|
479
|
+
access = getattr(modsec, 'access', 0)
|
|
480
|
+
if not access or isinstance(access, dict):
|
|
481
|
+
# Only specific names are accessible.
|
|
482
|
+
continue
|
|
483
|
+
parts = name.split('.')
|
|
484
|
+
for index in range(1, len(parts) + 1):
|
|
485
|
+
if '.'.join(parts[:index]) in dangerous_modules:
|
|
486
|
+
LOG.warning(
|
|
487
|
+
f'Module {name!r} is accessible from restricted code.')
|
|
488
|
+
break
|
|
489
|
+
|
|
490
|
+
|
|
383
491
|
def allow_class(Class):
|
|
384
492
|
"""Allow a class and all of its methods to be used from a
|
|
385
493
|
restricted Script. The argument Class must be a class."""
|
|
494
|
+
frozen.check_not_frozen()
|
|
386
495
|
Class._security = sec = ClassSecurityInfo()
|
|
387
496
|
sec.declareObjectPublic()
|
|
388
497
|
sec.setDefaultAccess(1)
|
|
389
498
|
sec.apply(Class)
|
|
390
499
|
InitializeClass(Class)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
allow_class.__roles__ = ACCESS_PRIVATE
|
|
@@ -61,6 +61,8 @@ from BTrees.OOBTree import OOBTree
|
|
|
61
61
|
from BTrees.OOBTree import OOBucket
|
|
62
62
|
from BTrees.OOBTree import OOSet
|
|
63
63
|
|
|
64
|
+
from AccessControl.frozen import FreezableDict
|
|
65
|
+
|
|
64
66
|
|
|
65
67
|
_noroles = [] # this is imported in various places
|
|
66
68
|
_marker = object()
|
|
@@ -84,12 +86,13 @@ _marker = object()
|
|
|
84
86
|
# The boolean values behave as above, but the functions do not.
|
|
85
87
|
# The value returned for attribute access is the result of
|
|
86
88
|
# calling the function with the object and the attribute name.
|
|
87
|
-
|
|
89
|
+
# Changes are refused once security declarations are frozen.
|
|
90
|
+
ContainerAssertions = FreezableDict({
|
|
88
91
|
type(()): 1,
|
|
89
92
|
bytes: 1,
|
|
90
93
|
str: 1,
|
|
91
94
|
range: 1,
|
|
92
|
-
}
|
|
95
|
+
})
|
|
93
96
|
|
|
94
97
|
Containers = ContainerAssertions.get
|
|
95
98
|
|
|
@@ -106,6 +109,9 @@ def allow_type(Type, allowed=1):
|
|
|
106
109
|
ContainerAssertions[Type] = allowed
|
|
107
110
|
|
|
108
111
|
|
|
112
|
+
allow_type.__roles__ = () # Only accessible from trusted code
|
|
113
|
+
|
|
114
|
+
|
|
109
115
|
for tree_type, has_values in [
|
|
110
116
|
(OOBTree, 1),
|
|
111
117
|
(OOBucket, 1),
|
|
@@ -22,6 +22,7 @@ from AccessControl.SecurityInfo import ClassSecurityInfo
|
|
|
22
22
|
from AccessControl.SecurityInfo import ModuleSecurityInfo
|
|
23
23
|
from AccessControl.SecurityInfo import allow_class
|
|
24
24
|
from AccessControl.SecurityInfo import allow_module
|
|
25
|
+
from AccessControl.SecurityInfo import freeze_security_declarations
|
|
25
26
|
from AccessControl.SecurityInfo import secureModule
|
|
26
27
|
from AccessControl.SecurityManagement import getSecurityManager
|
|
27
28
|
from AccessControl.SecurityManagement import setSecurityPolicy
|
|
@@ -36,7 +37,7 @@ ModuleSecurityInfo('AccessControl').declarePublic('getSecurityManager') # NOQA
|
|
|
36
37
|
|
|
37
38
|
# allow imports of utility_builtins
|
|
38
39
|
|
|
39
|
-
for name in ('string', 'math', 'random'
|
|
40
|
+
for name in ('string', 'math', 'random'):
|
|
40
41
|
ModuleSecurityInfo(name).setDefaultAccess('allow')
|
|
41
42
|
|
|
42
43
|
ModuleSecurityInfo('DateTime').declarePublic('DateTime') # NOQA: D001
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
##############################################################################
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2026 Zope Foundation and Contributors.
|
|
4
|
+
#
|
|
5
|
+
# This software is subject to the provisions of the Zope Public License,
|
|
6
|
+
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
|
7
|
+
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
|
8
|
+
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
9
|
+
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
|
10
|
+
# FOR A PARTICULAR PURPOSE
|
|
11
|
+
#
|
|
12
|
+
##############################################################################
|
|
13
|
+
"""Refuse changes to security declarations once they are frozen.
|
|
14
|
+
|
|
15
|
+
See AccessControl.SecurityInfo.freeze_security_declarations.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from zExceptions import Forbidden
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_frozen = False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def freeze():
|
|
25
|
+
global _frozen
|
|
26
|
+
_frozen = True
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def is_frozen():
|
|
30
|
+
return _frozen
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def check_not_frozen():
|
|
34
|
+
if _frozen:
|
|
35
|
+
raise Forbidden('Security declarations are frozen.')
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _guarded_dict_method(name):
|
|
39
|
+
method = getattr(dict, name)
|
|
40
|
+
|
|
41
|
+
def guarded(self, *args, **kwargs):
|
|
42
|
+
check_not_frozen()
|
|
43
|
+
return method(self, *args, **kwargs)
|
|
44
|
+
return guarded
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class FreezableDict(dict):
|
|
48
|
+
"""dict that refuses changes once security declarations are frozen."""
|
|
49
|
+
|
|
50
|
+
__setitem__ = _guarded_dict_method('__setitem__')
|
|
51
|
+
__delitem__ = _guarded_dict_method('__delitem__')
|
|
52
|
+
__ior__ = _guarded_dict_method('__ior__')
|
|
53
|
+
clear = _guarded_dict_method('clear')
|
|
54
|
+
pop = _guarded_dict_method('pop')
|
|
55
|
+
popitem = _guarded_dict_method('popitem')
|
|
56
|
+
setdefault = _guarded_dict_method('setdefault')
|
|
57
|
+
update = _guarded_dict_method('update')
|
|
@@ -127,9 +127,9 @@ def f7():
|
|
|
127
127
|
iter_ = access() # iterate twice on the same view
|
|
128
128
|
assert list(iter_) == list(iter_)
|
|
129
129
|
|
|
130
|
-
assert sorted([
|
|
130
|
+
assert sorted([*getattr(d, meth)()]) == expected[kind]
|
|
131
131
|
assert sorted(k for k in getattr(d, meth)()) == expected[kind]
|
|
132
|
-
assert {
|
|
132
|
+
assert {**d} == d
|
|
133
133
|
|
|
134
134
|
assert 1 in d
|
|
135
135
|
assert 1 in d.keys()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# test module, public
|
|
2
|
+
|
|
3
|
+
from Acquisition import aq_base # Foil the old ZopeSecurityPolicy # NOQA: F401
|
|
4
|
+
|
|
5
|
+
from AccessControl.SecurityInfo import allow_class # NOQA: F401
|
|
6
|
+
from AccessControl.SecurityInfo import allow_module # NOQA: F401
|
|
7
|
+
from AccessControl.SimpleObjectPolicies import allow_type # NOQA: F401
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def pub():
|
|
11
|
+
pass
|