diff options
| author | Theron Luhn <theron@luhn.com> | 2019-04-15 19:32:11 -0700 |
|---|---|---|
| committer | Theron Luhn <theron@luhn.com> | 2019-04-15 19:32:11 -0700 |
| commit | 5497c0f7166308031b3cc3ce2510d22eb214b2ef (patch) | |
| tree | 5cc4552b14cef319b027fea9065fd4b464466d4f /src | |
| parent | 600ffe25e1d332852f31756a38f6052d876b0c90 (diff) | |
| download | pyramid-5497c0f7166308031b3cc3ce2510d22eb214b2ef.tar.gz pyramid-5497c0f7166308031b3cc3ce2510d22eb214b2ef.tar.bz2 pyramid-5497c0f7166308031b3cc3ce2510d22eb214b2ef.zip | |
Move ACLHelper to pyramid.authorizations.
Diffstat (limited to 'src')
| -rw-r--r-- | src/pyramid/authorization.py | 131 | ||||
| -rw-r--r-- | src/pyramid/security.py | 129 |
2 files changed, 130 insertions, 130 deletions
diff --git a/src/pyramid/authorization.py b/src/pyramid/authorization.py index 19b96e3d1..cb629e257 100644 --- a/src/pyramid/authorization.py +++ b/src/pyramid/authorization.py @@ -2,7 +2,11 @@ from zope.interface import implementer from pyramid.interfaces import IAuthorizationPolicy -from pyramid.security import ACLHelper +from pyramid.location import lineage + +from pyramid.security import ACLAllowed, ACLDenied, Allow, Deny, Everyone + +from pyramid.util import is_nonstr_iter @implementer(IAuthorizationPolicy) @@ -75,3 +79,128 @@ class ACLAuthorizationPolicy(object): return self.helper.principals_allowed_by_permission( context, permission ) + + +class ACLHelper: + """ A helper for use with constructing a :term:`security policy` which + consults an :term:`ACL` object attached to a :term:`context` to determine + authorization information about a :term:`principal` or multiple principals. + If the context is part of a :term:`lineage`, the context's parents are + consulted for ACL information too. + + """ + + 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. + + When checking if principals are allowed, the security policy consults + the ``context`` for an ACL first. If no ACL exists on the context, or + one does exist but the ACL does not explicitly allow or deny access for + any of the effective principals, consult the context's parent ACL, and + 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` + ACE is found matching any principal in ``principals``, stop + processing by returning an + :class:`pyramid.security.ACLDenied` instance (equals + ``False``) immediately. If any + :data:`pyramid.security.Allow` ACE is found matching any + principal, stop processing by returning an + :class:`pyramid.security.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``). + + """ + acl = '<No ACL found on any object in resource lineage>' + + for location in lineage(context): + try: + acl = location.__acl__ + except AttributeError: + continue + + if acl and callable(acl): + acl = acl() + + for ace in acl: + ace_action, ace_principal, ace_permissions = ace + if ace_principal in principals: + if not is_nonstr_iter(ace_permissions): + ace_permissions = [ace_permissions] + if permission in ace_permissions: + if ace_action == Allow: + return ACLAllowed( + ace, acl, permission, principals, location + ) + else: + return ACLDenied( + ace, acl, permission, principals, location + ) + + # default deny (if no ACL in lineage at all, or if none of the + # principals were mentioned in any ACE we found) + return ACLDenied( + '<default deny>', acl, permission, principals, context + ) + + def principals_allowed_by_permission(self, context, permission): + """ Return the set of principals explicitly granted the permission + named ``permission`` according to the ACL directly attached to the + ``context`` as well as inherited ACLs based on the :term:`lineage`. + + When computing principals allowed by a permission, we compute the set + 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 + 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 + 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() + + for location in reversed(list(lineage(context))): + # NB: we're walking *up* the object graph from the root + try: + acl = location.__acl__ + except AttributeError: + continue + + allowed_here = set() + denied_here = set() + + if acl and callable(acl): + acl = acl() + + for ace_action, ace_principal, ace_permissions in acl: + if not is_nonstr_iter(ace_permissions): + ace_permissions = [ace_permissions] + if (ace_action == Allow) and (permission in ace_permissions): + if ace_principal not in denied_here: + allowed_here.add(ace_principal) + if (ace_action == Deny) and (permission in ace_permissions): + denied_here.add(ace_principal) + if ace_principal == Everyone: + # clear the entire allowed set, as we've hit a + # deny of Everyone ala (Deny, Everyone, ALL) + allowed = set() + break + elif ace_principal in allowed: + allowed.remove(ace_principal) + + allowed.update(allowed_here) + + return allowed diff --git a/src/pyramid/security.py b/src/pyramid/security.py index 5d157d219..5d8e916d7 100644 --- a/src/pyramid/security.py +++ b/src/pyramid/security.py @@ -9,10 +9,6 @@ from pyramid.interfaces import ( IViewClassifier, ) -from pyramid.location import lineage - -from pyramid.util import is_nonstr_iter - from pyramid.threadlocal import get_current_registry Everyone = 'system.Everyone' @@ -415,128 +411,3 @@ class LegacySecurityPolicy: authz = self._get_authz_policy(request) principals = authn.effective_principals(request) return authz.permits(context, principals, permission) - - -class ACLHelper: - """ A helper for use with constructing a :term:`security policy` which - consults an :term:`ACL` object attached to a :term:`context` to determine - authorization information about a :term:`principal` or multiple principals. - If the context is part of a :term:`lineage`, the context's parents are - consulted for ACL information too. - - """ - - 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. - - When checking if principals are allowed, the security policy consults - the ``context`` for an ACL first. If no ACL exists on the context, or - one does exist but the ACL does not explicitly allow or deny access for - any of the effective principals, consult the context's parent ACL, and - 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` - ACE is found matching any principal in ``principals``, stop - processing by returning an - :class:`pyramid.security.ACLDenied` instance (equals - ``False``) immediately. If any - :data:`pyramid.security.Allow` ACE is found matching any - principal, stop processing by returning an - :class:`pyramid.security.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``). - - """ - acl = '<No ACL found on any object in resource lineage>' - - for location in lineage(context): - try: - acl = location.__acl__ - except AttributeError: - continue - - if acl and callable(acl): - acl = acl() - - for ace in acl: - ace_action, ace_principal, ace_permissions = ace - if ace_principal in principals: - if not is_nonstr_iter(ace_permissions): - ace_permissions = [ace_permissions] - if permission in ace_permissions: - if ace_action == Allow: - return ACLAllowed( - ace, acl, permission, principals, location - ) - else: - return ACLDenied( - ace, acl, permission, principals, location - ) - - # default deny (if no ACL in lineage at all, or if none of the - # principals were mentioned in any ACE we found) - return ACLDenied( - '<default deny>', acl, permission, principals, context - ) - - def principals_allowed_by_permission(self, context, permission): - """ Return the set of principals explicitly granted the permission - named ``permission`` according to the ACL directly attached to the - ``context`` as well as inherited ACLs based on the :term:`lineage`. - - When computing principals allowed by a permission, we compute the set - 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 - 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 - 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() - - for location in reversed(list(lineage(context))): - # NB: we're walking *up* the object graph from the root - try: - acl = location.__acl__ - except AttributeError: - continue - - allowed_here = set() - denied_here = set() - - if acl and callable(acl): - acl = acl() - - for ace_action, ace_principal, ace_permissions in acl: - if not is_nonstr_iter(ace_permissions): - ace_permissions = [ace_permissions] - if (ace_action == Allow) and (permission in ace_permissions): - if ace_principal not in denied_here: - allowed_here.add(ace_principal) - if (ace_action == Deny) and (permission in ace_permissions): - denied_here.add(ace_principal) - if ace_principal == Everyone: - # clear the entire allowed set, as we've hit a - # deny of Everyone ala (Deny, Everyone, ALL) - allowed = set() - break - elif ace_principal in allowed: - allowed.remove(ace_principal) - - allowed.update(allowed_here) - - return allowed |
