From 1395359d653df5507146a44ccab6f0e2ab85ac65 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 12 Jan 2020 20:30:41 -0600 Subject: move acl helper apis from pyramid.security to pyramid.authorization --- src/pyramid/authorization.py | 42 +++++++++- src/pyramid/security.py | 181 ++++++++++++++++++++++++------------------- 2 files changed, 143 insertions(+), 80 deletions(-) diff --git a/src/pyramid/authorization.py b/src/pyramid/authorization.py index b7c5834f9..4a040e9e4 100644 --- a/src/pyramid/authorization.py +++ b/src/pyramid/authorization.py @@ -1,10 +1,50 @@ +import warnings from zope.interface import implementer from pyramid.interfaces import IAuthorizationPolicy from pyramid.location import lineage -from pyramid.security import ACLAllowed, ACLDenied, Allow, Deny, Everyone from pyramid.util import is_nonstr_iter +# the simplest way to deprecate the attributes in security.py is to +# leave them defined there and then import/re-export them here because +# otherwise there is a difficult-to-resolve circular import between +# the two modules - in the future when we remove the deprecated code and +# move it to live here, we will be able to remove this +with warnings.catch_warnings(): + warnings.simplefilter('ignore') + from pyramid.security import ( + ACLAllowed as _ACLAllowed, + ACLDenied as _ACLDenied, + AllPermissionsList as _AllPermissionsList, + Allow, + Authenticated, + Deny, + Everyone, + ) + + +Everyone = Everyone # api +Authenticated = Authenticated # api +Allow = Allow # api +Deny = Deny # api + + +class AllPermissionsList(_AllPermissionsList): + pass + + +ALL_PERMISSIONS = AllPermissionsList() # api +DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS) # api + +# subclass to fix __qualname__ +class ACLAllowed(_ACLAllowed): + pass + + +# subclass to fix __qualname__ +class ACLDenied(_ACLDenied): + pass + @implementer(IAuthorizationPolicy) class ACLAuthorizationPolicy(object): diff --git a/src/pyramid/security.py b/src/pyramid/security.py index 5e803aa0a..7b27c45f4 100644 --- a/src/pyramid/security.py +++ b/src/pyramid/security.py @@ -11,28 +11,6 @@ from pyramid.interfaces import ( ) from pyramid.threadlocal import get_current_registry -Everyone = 'system.Everyone' -Authenticated = 'system.Authenticated' -Allow = 'Allow' -Deny = 'Deny' - - -class AllPermissionsList(object): - """ Stand in 'permission list' to represent all permissions """ - - def __iter__(self): - return iter(()) - - def __contains__(self, other): - return True - - def __eq__(self, other): - return isinstance(other, self.__class__) - - -ALL_PERMISSIONS = AllPermissionsList() -DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS) - NO_PERMISSION_REQUIRED = '__no_permission_required__' @@ -129,6 +107,8 @@ def principals_allowed_by_permission(context, permission): reg = get_current_registry() policy = reg.queryUtility(IAuthorizationPolicy) if policy is None: + from pyramid.authorization import Everyone # noqa: F811 + return [Everyone] return policy.principals_allowed_by_permission(context, permission) @@ -231,62 +211,6 @@ class Allowed(PermitsResult): boolval = 1 -class ACLPermitsResult(PermitsResult): - def __new__(cls, ace, acl, permission, principals, context): - """ - Create a new instance. - - :param ace: The :term:`ACE` that matched, triggering the result. - :param acl: The :term:`ACL` containing ``ace``. - :param permission: The required :term:`permission`. - :param principals: The list of :term:`principals ` provided. - :param context: The :term:`context` providing the :term:`lineage` - searched. - - """ - fmt = ( - '%s permission %r via ACE %r in ACL %r on context %r for ' - 'principals %r' - ) - inst = PermitsResult.__new__( - cls, fmt, cls.__name__, permission, ace, acl, context, principals - ) - inst.permission = permission - inst.ace = ace - inst.acl = acl - inst.principals = principals - inst.context = context - return inst - - -class ACLDenied(ACLPermitsResult, Denied): - """ - An instance of ``ACLDenied`` is a specialization of - :class:`pyramid.security.Denied` that represents that a security check - made explicitly against ACL was denied. It evaluates equal to all - boolean false types. It also has the following attributes: ``acl``, - ``ace``, ``permission``, ``principals``, and ``context``. These - attributes indicate the security values involved in the request. Its - ``__str__`` method prints a summary of these attributes for debugging - purposes. The same summary is available as the ``msg`` attribute. - - """ - - -class ACLAllowed(ACLPermitsResult, Allowed): - """ - An instance of ``ACLAllowed`` is a specialization of - :class:`pyramid.security.Allowed` that represents that a security check - made explicitly against ACL was allowed. It evaluates equal to all - boolean true types. It also has the following attributes: ``acl``, - ``ace``, ``permission``, ``principals``, and ``context``. These - attributes indicate the security values involved in the request. Its - ``__str__`` method prints a summary of these attributes for debugging - purposes. The same summary is available as the ``msg`` attribute. - - """ - - class SecurityAPIMixin: """ Mixin for Request class providing auth-related properties. """ @@ -398,9 +322,11 @@ class AuthenticationAPIMixin(object): Return the list of 'effective' :term:`principal` identifiers for the ``request``. If no :term:`authentication policy` is in effect, this will return a one-element list containing the - :data:`pyramid.security.Everyone` principal. + :data:`pyramid.authorization.Everyone` principal. """ + from pyramid.authorization import Everyone # noqa: F811 + security = _get_security_policy(self) if security is not None and isinstance(security, LegacySecurityPolicy): authn = security._get_authn_policy(self) @@ -456,3 +382,100 @@ class LegacySecurityPolicy: authz = self._get_authz_policy(request) principals = authn.effective_principals(request) return authz.permits(context, principals, permission) + + +Everyone = 'system.Everyone' +Authenticated = 'system.Authenticated' +Allow = 'Allow' +Deny = 'Deny' + + +class AllPermissionsList(object): + """ Stand in 'permission list' to represent all permissions """ + + def __iter__(self): + return iter(()) + + def __contains__(self, other): + return True + + def __eq__(self, other): + return isinstance(other, self.__class__) + + +ALL_PERMISSIONS = AllPermissionsList() +DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS) + + +class ACLPermitsResult(PermitsResult): + def __new__(cls, ace, acl, permission, principals, context): + """ + Create a new instance. + + :param ace: The :term:`ACE` that matched, triggering the result. + :param acl: The :term:`ACL` containing ``ace``. + :param permission: The required :term:`permission`. + :param principals: The list of :term:`principals ` provided. + :param context: The :term:`context` providing the :term:`lineage` + searched. + + """ + fmt = ( + '%s permission %r via ACE %r in ACL %r on context %r for ' + 'principals %r' + ) + inst = PermitsResult.__new__( + cls, fmt, cls.__name__, permission, ace, acl, context, principals + ) + inst.permission = permission + inst.ace = ace + inst.acl = acl + inst.principals = principals + inst.context = context + return inst + + +class ACLDenied(ACLPermitsResult, Denied): + """ + An instance of ``ACLDenied`` is a specialization of + :class:`pyramid.security.Denied` that represents that a security check + made explicitly against ACL was denied. It evaluates equal to all + boolean false types. It also has the following attributes: ``acl``, + ``ace``, ``permission``, ``principals``, and ``context``. These + attributes indicate the security values involved in the request. Its + ``__str__`` method prints a summary of these attributes for debugging + purposes. The same summary is available as the ``msg`` attribute. + + """ + + +class ACLAllowed(ACLPermitsResult, Allowed): + """ + An instance of ``ACLAllowed`` is a specialization of + :class:`pyramid.security.Allowed` that represents that a security check + made explicitly against ACL was allowed. It evaluates equal to all + boolean true types. It also has the following attributes: ``acl``, + ``ace``, ``permission``, ``principals``, and ``context``. These + attributes indicate the security values involved in the request. Its + ``__str__`` method prints a summary of these attributes for debugging + purposes. The same summary is available as the ``msg`` attribute. + + """ + + +for attr in ( + 'ALL_PERMISSIONS', + 'DENY_ALL', + 'ACLAllowed', + 'ACLDenied', + 'AllPermissionsList', + 'Allow', + 'Authenticated', + 'Deny', + 'Everyone', +): + deprecated( + attr, + '"pyramid.security.{attr}" is deprecated in Pyramid 2.0. Adjust your ' + 'import to "pyramid.authorization.{attr}"'.format(attr=attr), + ) -- cgit v1.2.3 From 791730715832038c1666683e37fef8bb67830045 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 12 Jan 2020 20:49:35 -0600 Subject: move doc references from pyramid.security to pyramid.authorization --- docs/api/request.rst | 2 +- docs/narr/advanced-features.rst | 2 +- docs/narr/security.rst | 67 ++++++++++++++++---------------- docs/narr/viewconfig.rst | 2 +- src/pyramid/authentication.py | 16 ++++---- src/pyramid/authorization.py | 30 +++++++-------- src/pyramid/config/routes.py | 2 +- src/pyramid/config/views.py | 2 +- src/pyramid/httpexceptions.py | 2 +- src/pyramid/interfaces.py | 4 +- src/pyramid/security.py | 2 +- tests/test_authentication.py | 40 ++++++++++---------- tests/test_authorization.py | 84 ++++++++++++++++++++--------------------- tests/test_predicates.py | 4 +- 14 files changed, 130 insertions(+), 129 deletions(-) diff --git a/docs/api/request.rst b/docs/api/request.rst index 59d85ac2a..ed7f91e91 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -202,7 +202,7 @@ currently authenticated, but this depends on the :term:`authentication policy` in effect. If no :term:`authentication policy` is in effect, this will return a sequence containing only the - :attr:`pyramid.security.Everyone` principal. + :attr:`pyramid.authorization.Everyone` principal. .. method:: invoke_subrequest(request, use_tweens=False) diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst index 8d99f7291..6e819ff5b 100644 --- a/docs/narr/advanced-features.rst +++ b/docs/narr/advanced-features.rst @@ -34,7 +34,7 @@ For our example above, you can do this instead: .. code-block:: python :linenos: - @view_config(route_name="items", effective_principals=pyramid.security.Authenticated) + @view_config(route_name="items", effective_principals=pyramid.authorization.Authenticated) def auth_view(request): # do one thing diff --git a/docs/narr/security.rst b/docs/narr/security.rst index ac64cba0a..fd291a9db 100644 --- a/docs/narr/security.rst +++ b/docs/narr/security.rst @@ -330,14 +330,13 @@ Pyramid provides :class:`pyramid.authorization.ACLHelper` to assist with an ACL-based implementation of ``permits``. Application-specific code should construct a list of principals for the user and call :meth:`pyramid.authorization.ACLHelper.permits`, which will return an -:class:`pyramid.security.ACLAllowed` or :class:`pyramid.security.ACLDenied` +:class:`pyramid.authorization.ACLAllowed` or :class:`pyramid.authorization.ACLDenied` object. An implementation might look like this: .. code-block:: python :linenos: - from pyramid.security import Everyone, Authenticated - from pyramid.authorization import ACLHelper + from pyramid.authorization import ACLHelper, Everyone, Authenticated class SecurityPolicy: def permits(self, request, context, permission): @@ -358,8 +357,8 @@ For example, an ACL might be attached to the resource for a blog via its class: .. code-block:: python :linenos: - from pyramid.security import Allow - from pyramid.security import Everyone + from pyramid.authorization import Allow + from pyramid.authorization import Everyone class Blog(object): __acl__ = [ @@ -374,8 +373,8 @@ Or, if your resources are persistent, an ACL might be specified via the .. code-block:: python :linenos: - from pyramid.security import Allow - from pyramid.security import Everyone + from pyramid.authorization import Allow + from pyramid.authorization import Everyone class Blog(object): pass @@ -401,8 +400,8 @@ properties of the instance. .. code-block:: python :linenos: - from pyramid.security import Allow - from pyramid.security import Everyone + from pyramid.authorization import Allow + from pyramid.authorization import Everyone class Blog(object): def __acl__(self): @@ -435,8 +434,8 @@ Here's an example ACL: .. code-block:: python :linenos: - from pyramid.security import Allow - from pyramid.security import Everyone + from pyramid.authorization import Allow + from pyramid.authorization import Everyone __acl__ = [ (Allow, Everyone, 'view'), @@ -444,7 +443,7 @@ Here's an example ACL: (Allow, 'group:editors', 'edit'), ] -The example ACL indicates that the :data:`pyramid.security.Everyone` +The example ACL indicates that the :data:`pyramid.authorization.Everyone` principal—a special system-defined principal indicating, literally, everyone—is allowed to view the blog, and the ``group:editors`` principal is allowed to add to and edit the blog. @@ -453,8 +452,8 @@ Each element of an ACL is an :term:`ACE`, or access control entry. For example, in the above code block, there are three ACEs: ``(Allow, Everyone, 'view')``, ``(Allow, 'group:editors', 'add')``, and ``(Allow, 'group:editors', 'edit')``. -The first element of any ACE is either :data:`pyramid.security.Allow`, or -:data:`pyramid.security.Deny`, representing the action to take when the ACE +The first element of any ACE is either :data:`pyramid.authorization.Allow`, or +:data:`pyramid.authorization.Deny`, representing the action to take when the ACE matches. The second element is a :term:`principal`. The third argument is a permission or sequence of permission names. @@ -467,9 +466,9 @@ dictated by the ACL*. So if you have an ACL like this: .. code-block:: python :linenos: - from pyramid.security import Allow - from pyramid.security import Deny - from pyramid.security import Everyone + from pyramid.authorization import Allow + from pyramid.authorization import Deny + from pyramid.authorization import Everyone __acl__ = [ (Allow, Everyone, 'view'), @@ -483,9 +482,9 @@ hand, if you have an ACL like this: .. code-block:: python :linenos: - from pyramid.security import Everyone - from pyramid.security import Allow - from pyramid.security import Deny + from pyramid.authorization import Everyone + from pyramid.authorization import Allow + from pyramid.authorization import Deny __acl__ = [ (Deny, Everyone, 'view'), @@ -503,8 +502,8 @@ can collapse this into a single ACE, as below. .. code-block:: python :linenos: - from pyramid.security import Allow - from pyramid.security import Everyone + from pyramid.authorization import Allow + from pyramid.authorization import Everyone __acl__ = [ (Allow, Everyone, 'view'), @@ -520,17 +519,17 @@ can collapse this into a single ACE, as below. Special Principal Names ----------------------- -Special principal names exist in the :mod:`pyramid.security` module. They can +Special principal names exist in the :mod:`pyramid.authorization` module. They can be imported for use in your own code to populate ACLs, e.g., -:data:`pyramid.security.Everyone`. +:data:`pyramid.authorization.Everyone`. -:data:`pyramid.security.Everyone` +:data:`pyramid.authorization.Everyone` Literally, everyone, no matter what. This object is actually a string under the hood (``system.Everyone``). Every user *is* the principal named "Everyone" during every request, even if a security policy is not in use. -:data:`pyramid.security.Authenticated` +:data:`pyramid.authorization.Authenticated` Any user with credentials as determined by the current security policy. You might think of it as any user that is "logged in". This object is actually a @@ -543,12 +542,12 @@ be imported for use in your own code to populate ACLs, e.g., Special Permissions ------------------- -Special permission names exist in the :mod:`pyramid.security` module. These +Special permission names exist in the :mod:`pyramid.authorization` module. These can be imported for use in ACLs. .. _all_permissions: -:data:`pyramid.security.ALL_PERMISSIONS` +:data:`pyramid.authorization.ALL_PERMISSIONS` An object representing, literally, *all* permissions. Useful in an ACL like so: ``(Allow, 'fred', ALL_PERMISSIONS)``. The ``ALL_PERMISSIONS`` object is @@ -565,7 +564,7 @@ Special ACEs ------------ A convenience :term:`ACE` is defined representing a deny to everyone of all -permissions in :data:`pyramid.security.DENY_ALL`. This ACE is often used as +permissions in :data:`pyramid.authorization.DENY_ALL`. This ACE is often used as the *last* ACE of an ACL to explicitly cause inheriting authorization policies to "stop looking up the traversal tree" (effectively breaking any inheritance). For example, an ACL which allows *only* ``fred`` the view permission for a @@ -574,18 +573,18 @@ particular resource, despite what inherited ACLs may say, might look like so: .. code-block:: python :linenos: - from pyramid.security import Allow - from pyramid.security import DENY_ALL + from pyramid.authorization import Allow + from pyramid.authorization import DENY_ALL __acl__ = [ (Allow, 'fred', 'view'), DENY_ALL ] -Under the hood, the :data:`pyramid.security.DENY_ALL` ACE equals the +Under the hood, the :data:`pyramid.authorization.DENY_ALL` ACE equals the following: .. code-block:: python :linenos: - from pyramid.security import ALL_PERMISSIONS + from pyramid.authorization import ALL_PERMISSIONS __acl__ = [ (Deny, Everyone, ALL_PERMISSIONS) ] .. index:: @@ -681,7 +680,7 @@ security within view functions imperatively. It returns instances of objects that are effectively booleans. But these objects are not raw ``True`` or ``False`` objects, and have information attached to them about why the permission was allowed or denied. The object will be one of -:data:`pyramid.security.ACLAllowed`, :data:`pyramid.security.ACLDenied`, +:data:`pyramid.authorization.ACLAllowed`, :data:`pyramid.authorization.ACLDenied`, :data:`pyramid.security.Allowed`, or :data:`pyramid.security.Denied`, as documented in :ref:`security_module`. At the very minimum, these objects will have a ``msg`` attribute, which is a string indicating why the permission was diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 6a49e02a5..659b2470b 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -499,7 +499,7 @@ configured view. :meth:`pyramid.request.Request.effective_principals` method indicates that every principal named in the argument list is present in the current request, this predicate will return True; otherwise it will return False. For - example: ``effective_principals=pyramid.security.Authenticated`` or + example: ``effective_principals=pyramid.authorization.Authenticated`` or ``effective_principals=('fred', 'group:admins')``. .. versionadded:: 1.4a4 diff --git a/src/pyramid/authentication.py b/src/pyramid/authentication.py index 0ccc646c3..8c6c0f981 100644 --- a/src/pyramid/authentication.py +++ b/src/pyramid/authentication.py @@ -11,7 +11,7 @@ from webob.cookies import CookieProfile from zope.interface import implementer from pyramid.interfaces import IAuthenticationPolicy, IDebugLogger -from pyramid.security import Authenticated, Everyone +from pyramid.authorization import Authenticated, Everyone from pyramid.util import ( SimpleSerializer, ascii_, @@ -98,7 +98,7 @@ class CallbackAuthenticationPolicy(object): """ A list of effective principals derived from request. This will return a list of principals including, at least, - :data:`pyramid.security.Everyone`. If there is no authenticated + :data:`pyramid.authorization.Everyone`. If there is no authenticated userid, or the ``callback`` returns ``None``, this will be the only principal: @@ -108,8 +108,9 @@ class CallbackAuthenticationPolicy(object): If the ``callback`` does not return ``None`` and an authenticated userid is found, then the principals will include - :data:`pyramid.security.Authenticated`, the ``authenticated_userid`` - and the list of principals returned by the ``callback``: + :data:`pyramid.authorization.Authenticated`, the + ``authenticated_userid`` and the list of principals returned by the + ``callback``: .. code-block:: python @@ -274,13 +275,14 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy): """ A list of effective principals derived from the identity. This will return a list of principals including, at least, - :data:`pyramid.security.Everyone`. If there is no identity, or + :data:`pyramid.authorization.Everyone`. If there is no identity, or the ``callback`` returns ``None``, this will be the only principal. If the ``callback`` does not return ``None`` and an identity is found, then the principals will include - :data:`pyramid.security.Authenticated`, the ``authenticated_userid`` - and the list of principals returned by the ``callback``. + :data:`pyramid.authorization.Authenticated`, the + ``authenticated_userid`` and the list of principals returned by the + ``callback``. """ effective_principals = [Everyone] diff --git a/src/pyramid/authorization.py b/src/pyramid/authorization.py index 4a040e9e4..87e6b8767 100644 --- a/src/pyramid/authorization.py +++ b/src/pyramid/authorization.py @@ -69,9 +69,9 @@ class ACLAuthorizationPolicy(object): def permits(self, context, principals, permission): """ Return an instance of - :class:`pyramid.security.ACLAllowed` instance if the policy + :class:`pyramid.authorization.ACLAllowed` instance if the policy permits access, return an instance of - :class:`pyramid.security.ACLDenied` if not.""" + :class:`pyramid.authorization.ACLDenied` if not.""" return self.helper.permits(context, principals, permission) def principals_allowed_by_permission(self, context, permission): @@ -94,9 +94,9 @@ class ACLHelper: """ def permits(self, context, principals, permission): - """ Return an instance of :class:`pyramid.security.ACLAllowed` if the - ACL allows access a user with the given principals, return an instance - of :class:`pyramid.security.ACLDenied` if not. + """ Return an instance of :class:`pyramid.authorization.ACLAllowed` if + the ACL allows access a user with the given principals, return an + instance of :class:`pyramid.authorization.ACLDenied` if not. When checking if principals are allowed, the security policy consults the ``context`` for an ACL first. If no ACL exists on the context, or @@ -105,18 +105,18 @@ class ACLHelper: so on, until the lineage is exhausted or we determine that the policy permits or denies. - During this processing, if any :data:`pyramid.security.Deny` + During this processing, if any :data:`pyramid.authorization.Deny` ACE is found matching any principal in ``principals``, stop processing by returning an - :class:`pyramid.security.ACLDenied` instance (equals + :class:`pyramid.authorization.ACLDenied` instance (equals ``False``) immediately. If any - :data:`pyramid.security.Allow` ACE is found matching any + :data:`pyramid.authorization.Allow` ACE is found matching any principal, stop processing by returning an - :class:`pyramid.security.ACLAllowed` instance (equals + :class:`pyramid.authorization.ACLAllowed` instance (equals ``True``) immediately. If we exhaust the context's :term:`lineage`, and no ACE has explicitly permitted or denied access, return an instance of - :class:`pyramid.security.ACLDenied` (equals ``False``). + :class:`pyramid.authorization.ACLDenied` (equals ``False``). """ acl = '' @@ -160,13 +160,13 @@ class ACLHelper: of principals that are explicitly granted the ``permission`` in the provided ``context``. We do this by walking 'up' the object graph *from the root* to the context. During this walking process, if we - find an explicit :data:`pyramid.security.Allow` ACE for a principal + find an explicit :data:`pyramid.authorization.Allow` ACE for a principal that matches the ``permission``, the principal is included in the allow list. However, if later in the walking process that principal is - mentioned in any :data:`pyramid.security.Deny` ACE for the permission, - the principal is removed from the allow list. If a - :data:`pyramid.security.Deny` to the principal - :data:`pyramid.security.Everyone` is encountered during the walking + mentioned in any :data:`pyramid.authorization.Deny` ACE for the + permission, the principal is removed from the allow list. If a + :data:`pyramid.authorization.Deny` to the principal + :data:`pyramid.authorization.Everyone` is encountered during the walking process that matches the ``permission``, the allow list is cleared for all principals encountered in previous ACLs. The walking process ends after we've processed the any ACL directly attached to ``context``; a diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py index 44fbb9c46..219c67ddc 100644 --- a/src/pyramid/config/routes.py +++ b/src/pyramid/config/routes.py @@ -278,7 +278,7 @@ class RoutesConfiguratorMixin(object): indicates that every principal named in the argument list is present in the current request, this predicate will return True; otherwise it will return False. For example: - ``effective_principals=pyramid.security.Authenticated`` or + ``effective_principals=pyramid.authorization.Authenticated`` or ``effective_principals=('fred', 'group:admins')``. .. versionadded:: 1.4a4 diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index 2cc5e8144..e0e5d8d29 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -718,7 +718,7 @@ class ViewsConfiguratorMixin(object): indicates that every principal named in the argument list is present in the current request, this predicate will return True; otherwise it will return False. For example: - ``effective_principals=pyramid.security.Authenticated`` or + ``effective_principals=pyramid.authorization.Authenticated`` or ``effective_principals=('fred', 'group:admins')``. .. versionadded:: 1.4a4 diff --git a/src/pyramid/httpexceptions.py b/src/pyramid/httpexceptions.py index 51c2e90a0..76e28424a 100644 --- a/src/pyramid/httpexceptions.py +++ b/src/pyramid/httpexceptions.py @@ -755,7 +755,7 @@ class HTTPForbidden(HTTPClientError): argument, ``detail``, should be a string. The value of this string will be used as the ``message`` attribute of the exception object. The second special keyword argument, ``result`` is usually an instance of - :class:`pyramid.security.Denied` or :class:`pyramid.security.ACLDenied` + :class:`pyramid.security.Denied` or :class:`pyramid.authorization.ACLDenied` each of which indicates a reason for the forbidden error. However, ``result`` is also permitted to be just a plain boolean ``False`` object or ``None``. The ``result`` value will be used as the ``result`` diff --git a/src/pyramid/interfaces.py b/src/pyramid/interfaces.py index c4160cc2b..433ac0c9d 100644 --- a/src/pyramid/interfaces.py +++ b/src/pyramid/interfaces.py @@ -554,8 +554,8 @@ class IAuthenticationPolicy(Interface): """ Return a sequence representing the effective principals typically including the :term:`userid` and any groups belonged to by the current user, always including 'system' groups such - as ``pyramid.security.Everyone`` and - ``pyramid.security.Authenticated``. + as ``pyramid.authorization.Everyone`` and + ``pyramid.authorization.Authenticated``. """ diff --git a/src/pyramid/security.py b/src/pyramid/security.py index 7b27c45f4..a5b4ce442 100644 --- a/src/pyramid/security.py +++ b/src/pyramid/security.py @@ -92,7 +92,7 @@ def principals_allowed_by_permission(context, permission): in effect, return a sequence of :term:`principal` ids that possess the permission in the ``context``. If no authorization policy is in effect, this will return a sequence with the single value - :mod:`pyramid.security.Everyone` (the special principal + :mod:`pyramid.authorization.Everyone` (the special principal identifier representing all principals). .. note:: diff --git a/tests/test_authentication.py b/tests/test_authentication.py index ec3aef4ef..5b67a30da 100644 --- a/tests/test_authentication.py +++ b/tests/test_authentication.py @@ -321,15 +321,15 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.authenticated_userid(request), None) def test_effective_principals_None(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest({}) policy = self._makeOne() self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals_userid_only(self): - from pyramid.security import Everyone - from pyramid.security import Authenticated + from pyramid.authorization import Everyone + from pyramid.authorization import Authenticated request = DummyRequest( {'repoze.who.identity': {'repoze.who.userid': 'fred'}} @@ -341,8 +341,8 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): ) def test_effective_principals_userid_and_groups(self): - from pyramid.security import Everyone - from pyramid.security import Authenticated + from pyramid.authorization import Everyone + from pyramid.authorization import Authenticated request = DummyRequest( { @@ -363,7 +363,7 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): ) def test_effective_principals_userid_callback_returns_None(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest( { @@ -381,7 +381,7 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals_repoze_who_userid_is_None(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest( {'repoze.who.identity': {'repoze.who.userid': None}} @@ -390,7 +390,7 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals_repoze_who_userid_is_unclean_Everyone(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest( {'repoze.who.identity': {'repoze.who.userid': 'system.Everyone'}} @@ -401,7 +401,7 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): def test_effective_principals_repoze_who_userid_is_unclean_Authenticated( self, ): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest( { @@ -498,15 +498,15 @@ class TestRemoteUserAuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.authenticated_userid(request), 'fred') def test_effective_principals_None(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest({}) policy = self._makeOne() self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals(self): - from pyramid.security import Everyone - from pyramid.security import Authenticated + from pyramid.authorization import Everyone + from pyramid.authorization import Authenticated request = DummyRequest({'REMOTE_USER': 'fred'}) policy = self._makeOne() @@ -601,14 +601,14 @@ class TestAuthTktAuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.authenticated_userid(request), 'fred') def test_effective_principals_no_cookie_identity(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest({}) policy = self._makeOne(None, None) self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals_callback_returns_None(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest({}) @@ -619,8 +619,8 @@ class TestAuthTktAuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals(self): - from pyramid.security import Everyone - from pyramid.security import Authenticated + from pyramid.authorization import Everyone + from pyramid.authorization import Authenticated request = DummyRequest({}) @@ -1640,14 +1640,14 @@ class TestSessionAuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.authenticated_userid(request), 'fred') def test_effective_principals_no_identity(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest() policy = self._makeOne() self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals_callback_returns_None(self): - from pyramid.security import Everyone + from pyramid.authorization import Everyone request = DummyRequest(session={'userid': 'fred'}) @@ -1658,8 +1658,8 @@ class TestSessionAuthenticationPolicy(unittest.TestCase): self.assertEqual(policy.effective_principals(request), [Everyone]) def test_effective_principals(self): - from pyramid.security import Everyone - from pyramid.security import Authenticated + from pyramid.authorization import Everyone + from pyramid.authorization import Authenticated request = DummyRequest(session={'userid': 'fred'}) diff --git a/tests/test_authorization.py b/tests/test_authorization.py index 399b3da60..aea651501 100644 --- a/tests/test_authorization.py +++ b/tests/test_authorization.py @@ -36,12 +36,12 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(policy.permits(context, [], 'view'), False) def test_permits(self): - from pyramid.security import Deny - from pyramid.security import Allow - from pyramid.security import Everyone - from pyramid.security import Authenticated - from pyramid.security import ALL_PERMISSIONS - from pyramid.security import DENY_ALL + from pyramid.authorization import Deny + from pyramid.authorization import Allow + from pyramid.authorization import Everyone + from pyramid.authorization import Authenticated + from pyramid.authorization import ALL_PERMISSIONS + from pyramid.authorization import DENY_ALL root = DummyContext() community = DummyContext(__name__='community', __parent__=root) @@ -132,7 +132,7 @@ class TestACLAuthorizationPolicy(unittest.TestCase): ) def test_permits_string_permissions_in_acl(self): - from pyramid.security import Allow + from pyramid.authorization import Allow root = DummyContext() root.__acl__ = [(Allow, 'wilma', 'view_stuff')] @@ -145,8 +145,8 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(result, False) def test_principals_allowed_by_permission_direct(self): - from pyramid.security import Allow - from pyramid.security import DENY_ALL + from pyramid.authorization import Allow + from pyramid.authorization import DENY_ALL context = DummyContext() acl = [ @@ -162,8 +162,8 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(result, ['chrism']) def test_principals_allowed_by_permission_callable_acl(self): - from pyramid.security import Allow - from pyramid.security import DENY_ALL + from pyramid.authorization import Allow + from pyramid.authorization import DENY_ALL context = DummyContext() acl = lambda: [ @@ -179,7 +179,7 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(result, ['chrism']) def test_principals_allowed_by_permission_string_permission(self): - from pyramid.security import Allow + from pyramid.authorization import Allow context = DummyContext() acl = [(Allow, 'chrism', 'read_it')] @@ -191,10 +191,10 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(list(result), []) def test_principals_allowed_by_permission(self): - from pyramid.security import Allow - from pyramid.security import Deny - from pyramid.security import DENY_ALL - from pyramid.security import ALL_PERMISSIONS + from pyramid.authorization import Allow + from pyramid.authorization import Deny + from pyramid.authorization import DENY_ALL + from pyramid.authorization import ALL_PERMISSIONS root = DummyContext(__name__='', __parent__=None) community = DummyContext(__name__='community', __parent__=root) @@ -236,8 +236,8 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(result, []) def test_principals_allowed_by_permission_deny_not_permission_in_acl(self): - from pyramid.security import Deny - from pyramid.security import Everyone + from pyramid.authorization import Deny + from pyramid.authorization import Everyone context = DummyContext() acl = [(Deny, Everyone, 'write')] @@ -249,8 +249,8 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(result, []) def test_principals_allowed_by_permission_deny_permission_in_acl(self): - from pyramid.security import Deny - from pyramid.security import Everyone + from pyramid.authorization import Deny + from pyramid.authorization import Everyone context = DummyContext() acl = [(Deny, Everyone, 'read')] @@ -262,7 +262,7 @@ class TestACLAuthorizationPolicy(unittest.TestCase): self.assertEqual(result, []) def test_callable_acl(self): - from pyramid.security import Allow + from pyramid.authorization import Allow context = DummyContext() fn = lambda self: [(Allow, 'bob', 'read')] @@ -290,12 +290,12 @@ class TestACLHelper(unittest.TestCase): def test_acl(self): from pyramid.authorization import ACLHelper - from pyramid.security import Deny - from pyramid.security import Allow - from pyramid.security import Everyone - from pyramid.security import Authenticated - from pyramid.security import ALL_PERMISSIONS - from pyramid.security import DENY_ALL + from pyramid.authorization import Deny + from pyramid.authorization import Allow + from pyramid.authorization import Everyone + from pyramid.authorization import Authenticated + from pyramid.authorization import ALL_PERMISSIONS + from pyramid.authorization import DENY_ALL helper = ACLHelper() root = DummyContext() @@ -386,7 +386,7 @@ class TestACLHelper(unittest.TestCase): def test_string_permissions_in_acl(self): from pyramid.authorization import ACLHelper - from pyramid.security import Allow + from pyramid.authorization import Allow helper = ACLHelper() root = DummyContext() @@ -399,7 +399,7 @@ class TestACLHelper(unittest.TestCase): def test_callable_acl(self): from pyramid.authorization import ACLHelper - from pyramid.security import Allow + from pyramid.authorization import Allow helper = ACLHelper() context = DummyContext() @@ -410,8 +410,8 @@ class TestACLHelper(unittest.TestCase): def test_principals_allowed_by_permission_direct(self): from pyramid.authorization import ACLHelper - from pyramid.security import Allow - from pyramid.security import DENY_ALL + from pyramid.authorization import Allow + from pyramid.authorization import DENY_ALL helper = ACLHelper() context = DummyContext() @@ -428,8 +428,8 @@ class TestACLHelper(unittest.TestCase): def test_principals_allowed_by_permission_callable_acl(self): from pyramid.authorization import ACLHelper - from pyramid.security import Allow - from pyramid.security import DENY_ALL + from pyramid.authorization import Allow + from pyramid.authorization import DENY_ALL helper = ACLHelper() context = DummyContext() @@ -446,7 +446,7 @@ class TestACLHelper(unittest.TestCase): def test_principals_allowed_by_permission_string_permission(self): from pyramid.authorization import ACLHelper - from pyramid.security import Allow + from pyramid.authorization import Allow helper = ACLHelper() context = DummyContext() @@ -459,10 +459,10 @@ class TestACLHelper(unittest.TestCase): def test_principals_allowed_by_permission(self): from pyramid.authorization import ACLHelper - from pyramid.security import Allow - from pyramid.security import Deny - from pyramid.security import DENY_ALL - from pyramid.security import ALL_PERMISSIONS + from pyramid.authorization import Allow + from pyramid.authorization import Deny + from pyramid.authorization import DENY_ALL + from pyramid.authorization import ALL_PERMISSIONS helper = ACLHelper() root = DummyContext(__name__='', __parent__=None) @@ -506,8 +506,8 @@ class TestACLHelper(unittest.TestCase): def test_principals_allowed_by_permission_deny_not_permission_in_acl(self): from pyramid.authorization import ACLHelper - from pyramid.security import Deny - from pyramid.security import Everyone + from pyramid.authorization import Deny + from pyramid.authorization import Everyone helper = ACLHelper() context = DummyContext() @@ -520,8 +520,8 @@ class TestACLHelper(unittest.TestCase): def test_principals_allowed_by_permission_deny_permission_in_acl(self): from pyramid.authorization import ACLHelper - from pyramid.security import Deny - from pyramid.security import Everyone + from pyramid.authorization import Deny + from pyramid.authorization import Everyone helper = ACLHelper() context = DummyContext() diff --git a/tests/test_predicates.py b/tests/test_predicates.py index b0ee65bcf..533667d75 100644 --- a/tests/test_predicates.py +++ b/tests/test_predicates.py @@ -454,7 +454,7 @@ class Test_EffectivePrincipalsPredicate(unittest.TestCase): def _testing_authn_policy(self, userid, groupids=tuple()): from pyramid.interfaces import IAuthenticationPolicy, ISecurityPolicy - from pyramid.security import Everyone, Authenticated + from pyramid.authorization import Everyone, Authenticated from pyramid.security import LegacySecurityPolicy class DummyPolicy: @@ -500,7 +500,7 @@ class Test_EffectivePrincipalsPredicate(unittest.TestCase): self.assertTrue(inst(context, request)) def test_it_call_authentication_policy_provides_superset_implicit(self): - from pyramid.security import Authenticated + from pyramid.authorization import Authenticated request = testing.DummyRequest() self._testing_authn_policy('fred', groupids=('verna', 'bambi')) -- cgit v1.2.3 From 8b6efc3cfbf9accc6bf2a009e124dee2b3c04840 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 12 Jan 2020 20:50:59 -0600 Subject: fix lint --- src/pyramid/authentication.py | 2 +- src/pyramid/authorization.py | 29 +++++++++++++++-------------- src/pyramid/httpexceptions.py | 11 ++++++----- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/pyramid/authentication.py b/src/pyramid/authentication.py index 8c6c0f981..95c01bbea 100644 --- a/src/pyramid/authentication.py +++ b/src/pyramid/authentication.py @@ -10,8 +10,8 @@ import warnings from webob.cookies import CookieProfile from zope.interface import implementer -from pyramid.interfaces import IAuthenticationPolicy, IDebugLogger from pyramid.authorization import Authenticated, Everyone +from pyramid.interfaces import IAuthenticationPolicy, IDebugLogger from pyramid.util import ( SimpleSerializer, ascii_, diff --git a/src/pyramid/authorization.py b/src/pyramid/authorization.py index 87e6b8767..a0524a8cc 100644 --- a/src/pyramid/authorization.py +++ b/src/pyramid/authorization.py @@ -33,9 +33,6 @@ class AllPermissionsList(_AllPermissionsList): pass -ALL_PERMISSIONS = AllPermissionsList() # api -DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS) # api - # subclass to fix __qualname__ class ACLAllowed(_ACLAllowed): pass @@ -46,6 +43,10 @@ class ACLDenied(_ACLDenied): pass +ALL_PERMISSIONS = AllPermissionsList() # api +DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS) # api + + @implementer(IAuthorizationPolicy) class ACLAuthorizationPolicy(object): """ An :term:`authorization policy` which consults an :term:`ACL` @@ -160,17 +161,17 @@ class ACLHelper: of principals that are explicitly granted the ``permission`` in the provided ``context``. We do this by walking 'up' the object graph *from the root* to the context. During this walking process, if we - find an explicit :data:`pyramid.authorization.Allow` ACE for a principal - that matches the ``permission``, the principal is included in the allow - list. However, if later in the walking process that principal is - mentioned in any :data:`pyramid.authorization.Deny` ACE for the - permission, the principal is removed from the allow list. If a - :data:`pyramid.authorization.Deny` to the principal - :data:`pyramid.authorization.Everyone` is encountered during the walking - process that matches the ``permission``, the allow list is cleared for - all principals encountered in previous ACLs. The walking process ends - after we've processed the any ACL directly attached to ``context``; a - set of principals is returned. + find an explicit :data:`pyramid.authorization.Allow` ACE for a + principal that matches the ``permission``, the principal is included in + the allow list. However, if later in the walking process that + principal is mentioned in any :data:`pyramid.authorization.Deny` ACE + for the permission, the principal is removed from the allow list. If + a :data:`pyramid.authorization.Deny` to the principal + :data:`pyramid.authorization.Everyone` is encountered during the + walking process that matches the ``permission``, the allow list is + cleared for all principals encountered in previous ACLs. The walking + process ends after we've processed the any ACL directly attached to + ``context``; a set of principals is returned. """ allowed = set() diff --git a/src/pyramid/httpexceptions.py b/src/pyramid/httpexceptions.py index 76e28424a..dcf61b9e5 100644 --- a/src/pyramid/httpexceptions.py +++ b/src/pyramid/httpexceptions.py @@ -755,11 +755,12 @@ class HTTPForbidden(HTTPClientError): argument, ``detail``, should be a string. The value of this string will be used as the ``message`` attribute of the exception object. The second special keyword argument, ``result`` is usually an instance of - :class:`pyramid.security.Denied` or :class:`pyramid.authorization.ACLDenied` - each of which indicates a reason for the forbidden error. However, - ``result`` is also permitted to be just a plain boolean ``False`` object - or ``None``. The ``result`` value will be used as the ``result`` - attribute of the exception object. It defaults to ``None``. + :class:`pyramid.security.Denied` or + :class:`pyramid.authorization.ACLDenied` each of which indicates a reason + for the forbidden error. However, ``result`` is also permitted to be just + a plain boolean ``False`` object or ``None``. The ``result`` value will + be used as the ``result`` attribute of the exception object. + It defaults to ``None``. The :term:`Forbidden View` can use the attributes of a Forbidden exception as necessary to provide extended information in an error -- cgit v1.2.3 From f486795cb4a92784fa1082bd69bebd84bf6d1366 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 14 Jan 2020 00:02:04 -0600 Subject: update changelog and docs --- CHANGES.rst | 59 ++++++++++++++++++++++++++++++++++++++++++++++ docs/api/authorization.rst | 43 +++++++++++++++++++++++++++++++++ docs/api/security.rst | 46 ++++++++++++++++++++++++++++++------ 3 files changed, 141 insertions(+), 7 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 8159cea36..f1ccdf8e6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,19 @@ Features - Add support for Python 3.8. See https://github.com/Pylons/pyramid/pull/3547 +- New security APIs have been added to support a massive overhaul of the + authentication and authorization system. Read + "Upgrading Authentication/Authorization" in the "What's New in Pyramid 2.0" + document for information about using this new system. + + - ``pyramid.config.Configurator.set_security_policy``. + - ``pyramid.interfaces.ISecurityPolicy`` + - ``pyramid.request.Request.authenticated_identity``. + - ``pyramid.authentication.SessionAuthenticationHelper`` + - ``pyramid.authorization.ACLHelper`` + + See https://github.com/Pylons/pyramid/pull/3465 + - Changed the default ``serializer`` on ``pyramid.session.SignedCookieSessionFactory`` to use ``pyramid.session.JSONSerializer`` instead of @@ -94,9 +107,55 @@ Features and then we want to cache the data for the duration of the request. See https://github.com/Pylons/pyramid/pull/3561 +- Exposed ``pyramid.authorization.ALL_PERMISSIONS`` and + ``pyramid.authorization.DENY_ALL`` such that all of the ACL-related constants + are now importable from the ``pyramid.authorization`` namespace. + See https://github.com/Pylons/pyramid/pull/3563 + Deprecations ------------ +- Deprecated the authentication and authorization interfaces and + principal-based support. See "Upgrading Authentication/Authorization" in + the "What's New in Pyramid 2.0" document for information on equivalent APIs + and notes on upgrading. The following APIs are deprecated as a result of + this change: + + - ``pyramid.config.Configurator.set_authentication_policy`` + - ``pyramid.config.Configurator.set_authorization_policy`` + - ``pyramid.interfaces.IAuthenticationPolicy`` + - ``pyramid.interfaces.IAuthorizationPolicy`` + - ``pyramid.request.Request.effective_principals`` + - ``pyramid.request.Request.unauthenticated_userid`` + - ``pyramid.authentication.AuthTktAuthenticationPolicy`` + - ``pyramid.authentication.RemoteUserAuthenticationPolicy`` + - ``pyramid.authentication.RepozeWho1AuthenticationPolicy`` + - ``pyramid.authentication.SessionAuthenticationPolicy`` + - ``pyramid.authentication.BasicAuthAuthenticationPolicy`` + - ``pyramid.authorization.ACLAuthorizationPolicy`` + - The ``effective_principals`` view and route predicates. + + See https://github.com/Pylons/pyramid/pull/3465 + +- Deprecated ``pyramid.security.principals_allowed_by_permission``. This + method continues to work with the deprecated + ``pyramid.interfaces.IAuthorizationPolicy`` interface but will not work with + the new ``pyramid.interfaces.ISecurityPolicy``. + See https://github.com/Pylons/pyramid/pull/3465 + +- Deprecated several ACL-related aspects of ``pyramid.security``. Equivalent + objects should now be imported from the ``pyramid.authorization`` namespace. + This includes: + + - ``pyramid.security.Everyone`` + - ``pyramid.security.Authenticated`` + - ``pyramid.security.ALL_PERMISSIONS`` + - ``pyramid.security.DENY_ALL`` + - ``pyramid.security.ACLAllowed`` + - ``pyramid.security.ACLDenied`` + + See https://github.com/Pylons/pyramid/pull/3563 + - Deprecated ``pyramid.session.PickleSerializer``. See https://github.com/pylons/pyramid/issues/2709 and https://github.com/pylons/pyramid/pull/3353 diff --git a/docs/api/authorization.rst b/docs/api/authorization.rst index c6b3d090e..fac47490a 100644 --- a/docs/api/authorization.rst +++ b/docs/api/authorization.rst @@ -10,3 +10,46 @@ .. autoclass:: ACLAuthorizationPolicy +Constants +--------- + +.. attribute:: Everyone + + The special principal id named 'Everyone'. This principal id is + granted to all requests. Its actual value is the string + 'system.Everyone'. + +.. attribute:: Authenticated + + The special principal id named 'Authenticated'. This principal id + is granted to all requests which contain any other non-Everyone + principal id (according to the :term:`authentication policy`). + Its actual value is the string 'system.Authenticated'. + +.. attribute:: ALL_PERMISSIONS + + An object that can be used as the ``permission`` member of an ACE + which matches all permissions unconditionally. For example, an + ACE that uses ``ALL_PERMISSIONS`` might be composed like so: + ``('Deny', 'system.Everyone', ALL_PERMISSIONS)``. + +.. attribute:: DENY_ALL + + A convenience shorthand ACE that defines ``('Deny', + 'system.Everyone', ALL_PERMISSIONS)``. This is often used as the + last ACE in an ACL in systems that use an "inheriting" security + policy, representing the concept "don't inherit any other ACEs". + +Return Values +------------- + +.. autoclass:: ACLDenied + :members: msg + + .. automethod:: __new__ + +.. autoclass:: ACLAllowed + :members: msg + + .. automethod:: __new__ + diff --git a/docs/api/security.rst b/docs/api/security.rst index edb66472e..3350f8207 100644 --- a/docs/api/security.rst +++ b/docs/api/security.rst @@ -10,7 +10,7 @@ Authentication API Functions .. autofunction:: forget -.. autofunction:: remember(request, userid, **kwargs) +.. autofunction:: remember Authorization API Functions --------------------------- @@ -22,12 +22,24 @@ Authorization API Functions Constants --------- +.. attribute:: NO_PERMISSION_REQUIRED + + A special permission which indicates that the view should always + be executable by entirely anonymous users, regardless of the + default permission, bypassing any :term:`authorization policy` + that may be in effect. Its actual value is the string + '__no_permission_required__'. + .. attribute:: Everyone The special principal id named 'Everyone'. This principal id is granted to all requests. Its actual value is the string 'system.Everyone'. + .. deprecated:: 2.0 + + Moved to :data:`pyramid.authorization.Everyone`. + .. attribute:: Authenticated The special principal id named 'Authenticated'. This principal id @@ -35,6 +47,10 @@ Constants principal id (according to the :term:`authentication policy`). Its actual value is the string 'system.Authenticated'. + .. deprecated:: 2.0 + + Moved to :data:`pyramid.authorization.Authenticated`. + .. attribute:: ALL_PERMISSIONS An object that can be used as the ``permission`` member of an ACE @@ -42,6 +58,10 @@ Constants ACE that uses ``ALL_PERMISSIONS`` might be composed like so: ``('Deny', 'system.Everyone', ALL_PERMISSIONS)``. + .. deprecated:: 2.0 + + Moved to :data:`pyramid.authorization.ALL_PERMISSIONS`. + .. attribute:: DENY_ALL A convenience shorthand ACE that defines ``('Deny', @@ -49,13 +69,9 @@ Constants last ACE in an ACL in systems that use an "inheriting" security policy, representing the concept "don't inherit any other ACEs". -.. attribute:: NO_PERMISSION_REQUIRED + .. deprecated:: 2.0 - A special permission which indicates that the view should always - be executable by entirely anonymous users, regardless of the - default permission, bypassing any :term:`authorization policy` - that may be in effect. Its actual value is the string - '__no_permission_required__'. + Moved to :data:`pyramid.authorization.DENY_ALL`. Return Values ------------- @@ -66,12 +82,20 @@ Return Values 'read')`` that means allow access. A sequence of ACEs makes up an ACL. It is a string, and its actual value is "Allow". + .. deprecated:: 2.0 + + Moved to :data:`pyramid.authorization.Allow`. + .. attribute:: Deny The ACE "action" (the first element in an ACE e.g. ``(Deny, 'george', 'read')`` that means deny access. A sequence of ACEs makes up an ACL. It is a string, and its actual value is "Deny". + .. deprecated:: 2.0 + + Moved to :data:`pyramid.authorization.Deny`. + .. autoclass:: Denied :members: msg @@ -85,10 +109,18 @@ Return Values .. autoclass:: ACLDenied :members: msg + .. deprecated:: 2.0 + + Moved to :data:`pyramid.authorization.ACLDenied`. + .. automethod:: __new__ .. autoclass:: ACLAllowed :members: msg + .. deprecated:: 2.0 + + Moved to :data:`pyramid.authorization.ACLAllowed`. + .. automethod:: __new__ -- cgit v1.2.3 From 32fca41e49875764ff7faf04f430a75344035d96 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 14 Jan 2020 15:52:54 -0600 Subject: Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Éric Araujo --- docs/api/authorization.rst | 5 ++--- docs/api/security.rst | 15 +++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/docs/api/authorization.rst b/docs/api/authorization.rst index fac47490a..ec5dd4d36 100644 --- a/docs/api/authorization.rst +++ b/docs/api/authorization.rst @@ -17,14 +17,14 @@ Constants The special principal id named 'Everyone'. This principal id is granted to all requests. Its actual value is the string - 'system.Everyone'. + ``'system.Everyone'``. .. attribute:: Authenticated The special principal id named 'Authenticated'. This principal id is granted to all requests which contain any other non-Everyone principal id (according to the :term:`authentication policy`). - Its actual value is the string 'system.Authenticated'. + Its actual value is the string ``'system.Authenticated'``. .. attribute:: ALL_PERMISSIONS @@ -52,4 +52,3 @@ Return Values :members: msg .. automethod:: __new__ - diff --git a/docs/api/security.rst b/docs/api/security.rst index 3350f8207..7bfdbd0ad 100644 --- a/docs/api/security.rst +++ b/docs/api/security.rst @@ -28,13 +28,13 @@ Constants be executable by entirely anonymous users, regardless of the default permission, bypassing any :term:`authorization policy` that may be in effect. Its actual value is the string - '__no_permission_required__'. + ``'__no_permission_required__'``. .. attribute:: Everyone - The special principal id named 'Everyone'. This principal id is + The special principal id named ``Everyone``. This principal id is granted to all requests. Its actual value is the string - 'system.Everyone'. + ``'system.Everyone'``. .. deprecated:: 2.0 @@ -42,10 +42,10 @@ Constants .. attribute:: Authenticated - The special principal id named 'Authenticated'. This principal id + The special principal id named ``Authenticated``. This principal id is granted to all requests which contain any other non-Everyone principal id (according to the :term:`authentication policy`). - Its actual value is the string 'system.Authenticated'. + Its actual value is the string ``'system.Authenticated'``. .. deprecated:: 2.0 @@ -80,7 +80,7 @@ Return Values The ACE "action" (the first element in an ACE e.g. ``(Allow, Everyone, 'read')`` that means allow access. A sequence of ACEs makes up an - ACL. It is a string, and its actual value is "Allow". + ACL. It is a string, and its actual value is ``'Allow'``. .. deprecated:: 2.0 @@ -90,7 +90,7 @@ Return Values The ACE "action" (the first element in an ACE e.g. ``(Deny, 'george', 'read')`` that means deny access. A sequence of ACEs - makes up an ACL. It is a string, and its actual value is "Deny". + makes up an ACL. It is a string, and its actual value is ``'Deny'``. .. deprecated:: 2.0 @@ -123,4 +123,3 @@ Return Values Moved to :data:`pyramid.authorization.ACLAllowed`. .. automethod:: __new__ - -- cgit v1.2.3 From 1d6d0fcb2ce9bdb51fdb84b926b2f7c9b80763d2 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 14 Jan 2020 23:01:01 -0600 Subject: Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Éric Araujo --- docs/api/authorization.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/authorization.rst b/docs/api/authorization.rst index ec5dd4d36..7bf245500 100644 --- a/docs/api/authorization.rst +++ b/docs/api/authorization.rst @@ -15,13 +15,13 @@ Constants .. attribute:: Everyone - The special principal id named 'Everyone'. This principal id is + The special principal id named ``Everyone``. This principal id is granted to all requests. Its actual value is the string ``'system.Everyone'``. .. attribute:: Authenticated - The special principal id named 'Authenticated'. This principal id + The special principal id named ``Authenticated``. This principal id is granted to all requests which contain any other non-Everyone principal id (according to the :term:`authentication policy`). Its actual value is the string ``'system.Authenticated'``. -- cgit v1.2.3 From eb7046c8eeb8c9b598260ae8c8976187a8f84953 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 14 Jan 2020 23:01:44 -0600 Subject: fix comment --- src/pyramid/authorization.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pyramid/authorization.py b/src/pyramid/authorization.py index a0524a8cc..42171088f 100644 --- a/src/pyramid/authorization.py +++ b/src/pyramid/authorization.py @@ -29,16 +29,15 @@ Allow = Allow # api Deny = Deny # api +# subclasses to fix __module__ class AllPermissionsList(_AllPermissionsList): pass -# subclass to fix __qualname__ class ACLAllowed(_ACLAllowed): pass -# subclass to fix __qualname__ class ACLDenied(_ACLDenied): pass -- cgit v1.2.3 From 592cadd9c20ce410d9ab7b9a748ec59dff001f65 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 16 Jan 2020 10:34:45 -0600 Subject: update docs with pyramid.authorizatio imports after syncing master --- docs/api/authorization.rst | 24 ++++++++++++++++++++++ .../authorization/tutorial/resources.py | 4 ++-- .../authorization/tutorial/security.py | 7 +++++-- .../quick_tutorial/authorization/tutorial/views.py | 4 ++-- docs/quick_tutorial/databases/tutorial/models.py | 2 +- docs/tutorials/wiki/authorization.rst | 8 ++++---- .../src/authorization/tutorial/models/__init__.py | 4 ++-- .../wiki/src/authorization/tutorial/security.py | 4 ++-- .../wiki/src/tests/tutorial/models/__init__.py | 4 ++-- docs/tutorials/wiki/src/tests/tutorial/security.py | 4 ++-- docs/tutorials/wiki2/authorization.rst | 4 ++-- .../wiki2/src/authorization/tutorial/routes.py | 8 ++++---- .../wiki2/src/authorization/tutorial/security.py | 8 ++++---- docs/tutorials/wiki2/src/tests/tutorial/routes.py | 2 +- .../tutorials/wiki2/src/tests/tutorial/security.py | 8 ++++---- docs/whatsnew-2.0.rst | 2 +- 16 files changed, 62 insertions(+), 35 deletions(-) diff --git a/docs/api/authorization.rst b/docs/api/authorization.rst index 7bf245500..be040f055 100644 --- a/docs/api/authorization.rst +++ b/docs/api/authorization.rst @@ -19,6 +19,10 @@ Constants granted to all requests. Its actual value is the string ``'system.Everyone'``. + .. versionadded:: 2.0 + + Moved from ``pyramid.security`` into ``pyramid.authorization``. + .. attribute:: Authenticated The special principal id named ``Authenticated``. This principal id @@ -26,6 +30,10 @@ Constants principal id (according to the :term:`authentication policy`). Its actual value is the string ``'system.Authenticated'``. + .. versionadded:: 2.0 + + Moved from ``pyramid.security`` into ``pyramid.authorization``. + .. attribute:: ALL_PERMISSIONS An object that can be used as the ``permission`` member of an ACE @@ -33,6 +41,10 @@ Constants ACE that uses ``ALL_PERMISSIONS`` might be composed like so: ``('Deny', 'system.Everyone', ALL_PERMISSIONS)``. + .. versionadded:: 2.0 + + Moved from ``pyramid.security`` into ``pyramid.authorization``. + .. attribute:: DENY_ALL A convenience shorthand ACE that defines ``('Deny', @@ -40,6 +52,10 @@ Constants last ACE in an ACL in systems that use an "inheriting" security policy, representing the concept "don't inherit any other ACEs". + .. versionadded:: 2.0 + + Moved from ``pyramid.security`` into ``pyramid.authorization``. + Return Values ------------- @@ -48,7 +64,15 @@ Return Values .. automethod:: __new__ + .. versionadded:: 2.0 + + Moved from ``pyramid.security`` into ``pyramid.authorization``. + .. autoclass:: ACLAllowed :members: msg .. automethod:: __new__ + + .. versionadded:: 2.0 + + Moved from ``pyramid.security`` into ``pyramid.authorization``. diff --git a/docs/quick_tutorial/authorization/tutorial/resources.py b/docs/quick_tutorial/authorization/tutorial/resources.py index 0cb656f12..b125cf083 100644 --- a/docs/quick_tutorial/authorization/tutorial/resources.py +++ b/docs/quick_tutorial/authorization/tutorial/resources.py @@ -1,4 +1,4 @@ -from pyramid.security import Allow, Everyone +from pyramid.authorization import Allow, Everyone class Root(object): @@ -6,4 +6,4 @@ class Root(object): (Allow, 'group:editors', 'edit')] def __init__(self, request): - pass \ No newline at end of file + pass diff --git a/docs/quick_tutorial/authorization/tutorial/security.py b/docs/quick_tutorial/authorization/tutorial/security.py index 5b3e04a5f..53e3536fc 100644 --- a/docs/quick_tutorial/authorization/tutorial/security.py +++ b/docs/quick_tutorial/authorization/tutorial/security.py @@ -1,7 +1,10 @@ import bcrypt from pyramid.authentication import AuthTktCookieHelper -from pyramid.authorization import ACLHelper -from pyramid.security import Authenticated, Everyone +from pyramid.authorization import ( + ACLHelper, + Authenticated, + Everyone, +) def hash_password(pw): diff --git a/docs/quick_tutorial/authorization/tutorial/views.py b/docs/quick_tutorial/authorization/tutorial/views.py index 3876efb1c..b9c828086 100644 --- a/docs/quick_tutorial/authorization/tutorial/views.py +++ b/docs/quick_tutorial/authorization/tutorial/views.py @@ -2,13 +2,13 @@ from pyramid.httpexceptions import HTTPFound from pyramid.security import ( remember, forget, - ) +) from pyramid.view import ( view_config, view_defaults, forbidden_view_config - ) +) from .security import ( USERS, diff --git a/docs/quick_tutorial/databases/tutorial/models.py b/docs/quick_tutorial/databases/tutorial/models.py index 8e6649d49..bbfd480bb 100644 --- a/docs/quick_tutorial/databases/tutorial/models.py +++ b/docs/quick_tutorial/databases/tutorial/models.py @@ -1,4 +1,4 @@ -from pyramid.security import Allow, Everyone +from pyramid.authorization import Allow, Everyone from sqlalchemy import ( Column, diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 995dfa729..3c9913d8c 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -108,8 +108,8 @@ For our application we've defined a list of a few principals: - ``u:`` - ``group:editor`` -- :attr:`pyramid.security.Authenticated` -- :attr:`pyramid.security.Everyone` +- :attr:`pyramid.authorization.Authenticated` +- :attr:`pyramid.authorization.Everyone` Various wiki pages will grant some of these principals access to edit existing or add new pages. @@ -176,9 +176,9 @@ Add the following lines to the ``Wiki`` class: :emphasize-lines: 4-7 :language: python -We import :data:`~pyramid.security.Allow`, an action which means that +We import :data:`~pyramid.authorization.Allow`, an action which means that permission is allowed. -We also import :data:`~pyramid.security.Everyone`, a special :term:`principal` that is associated to all requests. +We also import :data:`~pyramid.authorization.Everyone`, a special :term:`principal` that is associated to all requests. Both are used in the :term:`ACE` entries that make up the ACL. The ACL is a list that needs to be named ``__acl__`` and be an attribute of a class. diff --git a/docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py index 64ae4bf5c..580ea41c5 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py @@ -1,11 +1,11 @@ from persistent import Persistent from persistent.mapping import PersistentMapping - -from pyramid.security import ( +from pyramid.authorization import ( Allow, Everyone, ) + class Wiki(PersistentMapping): __name__ = None __parent__ = None diff --git a/docs/tutorials/wiki/src/authorization/tutorial/security.py b/docs/tutorials/wiki/src/authorization/tutorial/security.py index 9f51aa54c..f4445578e 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/security.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/security.py @@ -1,7 +1,7 @@ import bcrypt from pyramid.authentication import AuthTktCookieHelper -from pyramid.authorization import ACLHelper -from pyramid.security import ( +from pyramid.authorization import ( + ACLHelper, Authenticated, Everyone, ) diff --git a/docs/tutorials/wiki/src/tests/tutorial/models/__init__.py b/docs/tutorials/wiki/src/tests/tutorial/models/__init__.py index 64ae4bf5c..580ea41c5 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/models/__init__.py +++ b/docs/tutorials/wiki/src/tests/tutorial/models/__init__.py @@ -1,11 +1,11 @@ from persistent import Persistent from persistent.mapping import PersistentMapping - -from pyramid.security import ( +from pyramid.authorization import ( Allow, Everyone, ) + class Wiki(PersistentMapping): __name__ = None __parent__ = None diff --git a/docs/tutorials/wiki/src/tests/tutorial/security.py b/docs/tutorials/wiki/src/tests/tutorial/security.py index 9f51aa54c..f4445578e 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/security.py +++ b/docs/tutorials/wiki/src/tests/tutorial/security.py @@ -1,7 +1,7 @@ import bcrypt from pyramid.authentication import AuthTktCookieHelper -from pyramid.authorization import ACLHelper -from pyramid.security import ( +from pyramid.authorization import ( + ACLHelper, Authenticated, Everyone, ) diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst index 001bde935..38b9b7373 100644 --- a/docs/tutorials/wiki2/authorization.rst +++ b/docs/tutorials/wiki2/authorization.rst @@ -30,7 +30,7 @@ identifiers that are easier to generalize. The permissions are then written against the principals without focusing on the exact user involved. :app:`Pyramid` defines two builtin principals used in every application: -:attr:`pyramid.security.Everyone` and :attr:`pyramid.security.Authenticated`. +:attr:`pyramid.authorization.Everyone` and :attr:`pyramid.authorization.Authenticated`. On top of these we have already mentioned the required principals for this application in the original design. The user has two possible roles: ``editor`` or ``basic``. These will be prefixed by the string ``role:`` to avoid clashing @@ -40,7 +40,7 @@ Open the file ``tutorial/security.py`` and edit it as follows: .. literalinclude:: src/authorization/tutorial/security.py :linenos: - :emphasize-lines: 2,5-8,17,42-53 + :emphasize-lines: 2-6,17,42-53 :language: python Only the highlighted lines need to be added. diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/routes.py b/docs/tutorials/wiki2/src/authorization/tutorial/routes.py index f016d7541..f7bbe6011 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/routes.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/routes.py @@ -1,11 +1,11 @@ +from pyramid.authorization import ( + Allow, + Everyone, +) from pyramid.httpexceptions import ( HTTPNotFound, HTTPSeeOther, ) -from pyramid.security import ( - Allow, - Everyone, -) from . import models diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/security.py b/docs/tutorials/wiki2/src/authorization/tutorial/security.py index 7a99fb9e9..5a9d4bbf2 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/security.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/security.py @@ -1,11 +1,11 @@ from pyramid.authentication import AuthTktCookieHelper -from pyramid.authorization import ACLHelper -from pyramid.csrf import CookieCSRFStoragePolicy -from pyramid.request import RequestLocalCache -from pyramid.security import ( +from pyramid.authorization import ( + ACLHelper, Authenticated, Everyone, ) +from pyramid.csrf import CookieCSRFStoragePolicy +from pyramid.request import RequestLocalCache from . import models diff --git a/docs/tutorials/wiki2/src/tests/tutorial/routes.py b/docs/tutorials/wiki2/src/tests/tutorial/routes.py index f016d7541..7070884d3 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/routes.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/routes.py @@ -2,7 +2,7 @@ from pyramid.httpexceptions import ( HTTPNotFound, HTTPSeeOther, ) -from pyramid.security import ( +from pyramid.authorization import ( Allow, Everyone, ) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security.py b/docs/tutorials/wiki2/src/tests/tutorial/security.py index 7a99fb9e9..5a9d4bbf2 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/security.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/security.py @@ -1,11 +1,11 @@ from pyramid.authentication import AuthTktCookieHelper -from pyramid.authorization import ACLHelper -from pyramid.csrf import CookieCSRFStoragePolicy -from pyramid.request import RequestLocalCache -from pyramid.security import ( +from pyramid.authorization import ( + ACLHelper, Authenticated, Everyone, ) +from pyramid.csrf import CookieCSRFStoragePolicy +from pyramid.request import RequestLocalCache from . import models diff --git a/docs/whatsnew-2.0.rst b/docs/whatsnew-2.0.rst index d5f825c43..a58f317d7 100644 --- a/docs/whatsnew-2.0.rst +++ b/docs/whatsnew-2.0.rst @@ -95,4 +95,4 @@ The new :attr:`pyramid.request.Request.authenticated_identity` property will output the same result as :attr:`pyramid.request.Request.authenticated_userid`. If using a security policy, :attr:`pyramid.request.Request.unauthenticated_userid` will return the same value as :attr:`pyramid.request.Request.authenticated_userid`. -:attr:`pyramid.request.Request.effective_principals` will always return a one-element list containing the :data:`pyramid.security.Everyone` principal, as there is no equivalent in the new security policy. +:attr:`pyramid.request.Request.effective_principals` will always return a one-element list containing the :data:`pyramid.authorization.Everyone` principal, as there is no equivalent in the new security policy. -- cgit v1.2.3