Source code for pyramid.security

from zope.interface import providedBy

from pyramid.interfaces import (
    IAuthenticationPolicy,
    IAuthorizationPolicy,
    ISecuredView,
    IViewClassifier,
    )

from pyramid.compat import map_
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 ()
    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__'

[docs]def has_permission(permission, context, request): """ Provided a permission (a string or unicode object), a context (a :term:`resource` instance) and a request object, return an instance of :data:`pyramid.security.Allowed` if the permission is granted in this context to the user implied by the request. Return an instance of :mod:`pyramid.security.Denied` if this permission is not granted in this context to this user. This function delegates to the current authentication and authorization policies. Return :data:`pyramid.security.Allowed` unconditionally if no authentication policy has been configured in this application.""" try: reg = request.registry except AttributeError: reg = get_current_registry() # b/c authn_policy = reg.queryUtility(IAuthenticationPolicy) if authn_policy is None: return Allowed('No authentication policy in use.') authz_policy = reg.queryUtility(IAuthorizationPolicy) if authz_policy is None: raise ValueError('Authentication policy registered without ' 'authorization policy') # should never happen principals = authn_policy.effective_principals(request) return authz_policy.permits(context, principals, permission)
[docs]def authenticated_userid(request): """ Return the userid of the currently authenticated user or ``None`` if there is no :term:`authentication policy` in effect or there is no currently authenticated user.""" try: reg = request.registry except AttributeError: reg = get_current_registry() # b/c policy = reg.queryUtility(IAuthenticationPolicy) if policy is None: return None return policy.authenticated_userid(request)
[docs]def unauthenticated_userid(request): """ Return an object which represents the *claimed* (not verified) user id of the credentials present in the request. ``None`` if there is no :term:`authentication policy` in effect or there is no user data associated with the current request. This differs from :func:`~pyramid.security.authenticated_userid`, because the effective authentication policy will not ensure that a record associated with the userid exists in persistent storage.""" try: reg = request.registry except AttributeError: reg = get_current_registry() # b/c policy = reg.queryUtility(IAuthenticationPolicy) if policy is None: return None return policy.unauthenticated_userid(request)
[docs]def effective_principals(request): """ Return the list of 'effective' :term:`principal` identifiers for the ``request``. This will include the userid of the currently authenticated user if a user is currently authenticated. If no :term:`authentication policy` is in effect, this will return an empty sequence.""" try: reg = request.registry except AttributeError: reg = get_current_registry() # b/c policy = reg.queryUtility(IAuthenticationPolicy) if policy is None: return [Everyone] return policy.effective_principals(request)
[docs]def principals_allowed_by_permission(context, permission): """ Provided a ``context`` (a resource object), and a ``permission`` (a string or unicode object), if a :term:`authorization policy` is 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 identifier representing all principals). .. note:: even if an :term:`authorization policy` is in effect, some (exotic) authorization policies may not implement the required machinery for this function; those will cause a :exc:`NotImplementedError` exception to be raised when this function is invoked. """ reg = get_current_registry() policy = reg.queryUtility(IAuthorizationPolicy) if policy is None: return [Everyone] return policy.principals_allowed_by_permission(context, permission)
[docs]def view_execution_permitted(context, request, name=''): """ If the view specified by ``context`` and ``name`` is protected by a :term:`permission`, check the permission associated with the view using the effective authentication/authorization policies and the ``request``. Return a boolean result. If no :term:`authorization policy` is in effect, or if the view is not protected by a permission, return ``True``.""" try: reg = request.registry except AttributeError: reg = get_current_registry() # b/c provides = [IViewClassifier] + map_(providedBy, (request, context)) view = reg.adapters.lookup(provides, ISecuredView, name=name) if view is None: return Allowed( 'Allowed: view name %r in context %r (no permission defined)' % (name, context)) return view.__permitted__(context, request)
[docs]def remember(request, principal, **kw): """ Return a sequence of header tuples (e.g. ``[('Set-Cookie', 'foo=abc')]``) suitable for 'remembering' a set of credentials implied by the data passed as ``principal`` and ``*kw`` using the current :term:`authentication policy`. Common usage might look like so within the body of a view function (``response`` is assumed to be a :term:`WebOb` -style :term:`response` object computed previously by the view code):: from pyramid.security import remember headers = remember(request, 'chrism', password='123', max_age='86400') response.headerlist.extend(headers) return response If no :term:`authentication policy` is in use, this function will always return an empty sequence. If used, the composition and meaning of ``**kw`` must be agreed upon by the calling code and the effective authentication policy.""" try: reg = request.registry except AttributeError: reg = get_current_registry() # b/c policy = reg.queryUtility(IAuthenticationPolicy) if policy is None: return [] else: return policy.remember(request, principal, **kw)
[docs]def forget(request): """ Return a sequence of header tuples (e.g. ``[('Set-Cookie', 'foo=abc')]``) suitable for 'forgetting' the set of credentials possessed by the currently authenticated user. A common usage might look like so within the body of a view function (``response`` is assumed to be an :term:`WebOb` -style :term:`response` object computed previously by the view code):: from pyramid.security import forget headers = forget(request) response.headerlist.extend(headers) return response If no :term:`authentication policy` is in use, this function will always return an empty sequence.""" try: reg = request.registry except AttributeError: reg = get_current_registry() # b/c policy = reg.queryUtility(IAuthenticationPolicy) if policy is None: return [] else: return policy.forget(request)
class PermitsResult(int): def __new__(cls, s, *args): inst = int.__new__(cls, cls.boolval) inst.s = s inst.args = args return inst @property def msg(self): return self.s % self.args def __str__(self): return self.msg def __repr__(self): return '<%s instance at %s with msg %r>' % (self.__class__.__name__, id(self), self.msg)
[docs]class Denied(PermitsResult): """ An instance of ``Denied`` is returned when a security-related API or other :app:`Pyramid` code denies an action unrelated to an ACL check. It evaluates equal to all boolean false types. It has an attribute named ``msg`` describing the circumstances for the deny.""" boolval = 0
[docs]class Allowed(PermitsResult): """ An instance of ``Allowed`` is returned when a security-related API or other :app:`Pyramid` code allows an action unrelated to an ACL check. It evaluates equal to all boolean true types. It has an attribute named ``msg`` describing the circumstances for the allow.""" boolval = 1
class ACLPermitsResult(int): def __new__(cls, ace, acl, permission, principals, context): inst = int.__new__(cls, cls.boolval) inst.permission = permission inst.ace = ace inst.acl = acl inst.principals = principals inst.context = context return inst @property def msg(self): s = ('%s permission %r via ACE %r in ACL %r on context %r for ' 'principals %r') return s % (self.__class__.__name__, self.permission, self.ace, self.acl, self.context, self.principals) def __str__(self): return self.msg def __repr__(self): return '<%s instance at %s with msg %r>' % (self.__class__.__name__, id(self), self.msg)
[docs]class ACLDenied(ACLPermitsResult): """ An instance of ``ACLDenied`` 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.""" boolval = 0
[docs]class ACLAllowed(ACLPermitsResult): """ An instance of ``ACLAllowed`` 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.""" boolval = 1