Security ======== ``repoze.bfg`` provides an optional declarative security system that prevents views that are protected by a :term:`permission` from being rendered when the user represented by the request does not have the appropriate level of access in a context. Jargon ------ To learn about the jargon tossed around in this chapter, you may want to review the :ref:`glossary`. Enabling a Security Policy -------------------------- By default, ``repoze.bfg`` enables no security policy. All views are accessible by completely anonymous users. However, if you add the following bit of code to your application's ``configure.zcml``, you will enable a security policy:: The above insrcutable stanza enables the ``RemoteUserACLSecurityPolicy`` to be in effect for every request to your application. The ``RemoteUserACLSecurityPolicy`` is a policy which compares the ``REMOTE_USER`` variable passed in the reqest's environment (as the sole *principal*) against any *ACL* found in model data when attempting to call some *view*. The policy either allows the view that the permission was declared for to be called, or returns a ``401 Unathorized`` response code to the upstream WSGI server. Protecting Views with Permissions --------------------------------- You declaratively protected a particular view with a permisson via the ``configure.zcml`` application registry. For example, the following declaration protects the view named "add_entry.html" when invoked against an IBlog context with the ``add`` permission:: If a security policy is in place when this view is found during normal application operations, the user will need to possess the ``add`` permission against the context to be able to invoke the ``blog_entry_add_view`` view. Permission names are just strings. They hold no special significance to the system. You can name permissions whatever you like. Assigning ACLs to your Model Objects ------------------------------------ When ``repoze.bfg`` determines whether a user possesses a particular permission in a context, it examines the ACL associated with the context. An ACL is associated with a context by virtue of the ``__acl__`` attribute of the model object representing the context. This attribute can be defined on the model *instance* (if you need instance-level security), or it can be defined on the model *class* (if you just need type-level security). For example, an ACL might be attached to model for a blog via its class:: from repoze.bfg.security import Everyone from repoze.bfg.security import Allow from zope.location.interfaces import ILocation from zope.location.location import Location class IBlog(Interface): pass class Blog(dict, Location): __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ] implements(IBlog, ILocation) The above ACL indicates that the Everyone principal (a system-defined principal) is allowed to view the blog, the ``group:editors`` principal is allowed to add to and edit the blog. ACL Inheritance --------------- While the security policy is in place, if a model object does not have an ACL when it is the context, its *parent* is consulted for an ACL. If that object does not have an ACL, *its* parent is consulted for an ACL, ad infinitum, until we've reached the root and there are no more parents left. The *first* ACL found by the security policy will be used as the effective ACL. No combination of ACLs found during traversal or backtracking is done. Location-Awareness ------------------ In order to allow the security machinery to perform ACL inheritance, model objects should provide *location-awareness*. Objects have parents when they define an ``__parent__`` attribute which points at their parent object. The root object's ``__parent__`` is ``None``. An object with a ``__parent__`` attribute and a ``__name__`` attribute is said to be *location-aware*. If the root object in a ``repoze.bfg`` application declares that it implements the ``ILocation`` interface, it is assumed that the objects in the rest of the model are location-aware. Even if they are not explictly, if the root object is marked as ``ILocation``, the bfg framework will wrap each object during traversal in a *location proxy*, which will wrap each object found during traversal in a proxy object that has both the ``__name__`` and ``__parent__`` attributes, but otherwise acts the same as your model object. You can of course supply ``__name__`` and ``__parent__`` attributes explicitly on all of your model objects, and no location proxying will be performed.