`` div:
.. code-block:: xml
:linenos:
Logout
Giving Our Root Model Object an ACL
-----------------------------------
We need to give our root model object an :term:`ACL`. This ACL will
be sufficient to provide enough information to the :mod:`pyramid`
security machinery to challenge a user who doesn't have appropriate
credentials when he attempts to invoke the ``add_page`` or
``edit_page`` views.
We need to perform some imports at module scope in our ``models.py``
file:
.. code-block:: python
:linenos:
from pyramid.security import Allow
from pyramid.security import Everyone
Our root model is a ``Wiki`` object. We'll add the following line at
class scope to our ``Wiki`` class:
.. code-block:: python
:linenos:
__acl__ = [ (Allow, Everyone, 'view'),
(Allow, 'group:editors', 'edit') ]
It's only happenstance that we're assigning this ACL at class scope.
An ACL can be attached to an object *instance* too; this is how "row
level security" can be achieved in :mod:`pyramid` applications. We
actually only need *one* ACL for the entire system, however, because
our security requirements are simple, so this feature is not
demonstrated.
Our resulting ``models.py`` file will now look like so:
.. literalinclude:: src/authorization/tutorial/models.py
:linenos:
:language: python
Adding ``permission`` Declarations to our ``bfg_view`` Decorators
-----------------------------------------------------------------
To protect each of our views with a particular permission, we need to
pass a ``permission`` argument to each of our
:class:`pyramid.view.bfg_view` decorators. To do so, within
``views.py``:
- We add ``permission='view'`` to the decorator attached to the
``view_wiki`` view function. This makes the assertion that only
users who possess the effective ``view`` permission at the time of
the request may invoke this view. We've granted
:data:`pyramid.security.Everyone` the view permission at the root
model via its ACL, so everyone will be able to invoke the
``view_wiki`` view.
- We add ``permission='view'`` to the decorator attached to the
``view_page`` view function. This makes the assertion that only
users who possess the effective ``view`` permission at the time of
the request may invoke this view. We've granted
:data:`pyramid.security.Everyone` the view permission at the root
model via its ACL, so everyone will be able to invoke the
``view_page`` view.
- We add ``permission='edit'`` to the decorator attached to the
``add_page`` view function. This makes the assertion that only
users who possess the effective ``edit`` permission at the time of
the request may invoke this view. We've granted the
``group:editors`` principal the ``edit`` permission at the root
model via its ACL, so only the a user whom is a member of the group
named ``group:editors`` will able to invoke the ``add_page`` view.
We've likewise given the ``editor`` user membership to this group
via thes ``security.py`` file by mapping him to the
``group:editors`` group in the ``GROUPS`` data structure (``GROUPS =
{'editor':['group:editors']}``); the ``groupfinder`` function
consults the ``GROUPS`` data structure. This means that the
``editor`` user can add pages.
- We add ``permission='edit'`` to the ``bfg_view`` decorator attached
to the ``edit_page`` view function. This makes the assertion that
only users who possess the effective ``edit`` permission at the time
of the request may invoke this view. We've granted the
``group:editors`` principal the ``edit`` permission at the root
model via its ACL, so only the a user whom is a member of the group
named ``group:editors`` will able to invoke the ``edit_page`` view.
We've likewise given the ``editor`` user membership to this group
via thes ``security.py`` file by mapping him to the
``group:editors`` group in the ``GROUPS`` data structure (``GROUPS =
{'editor':['group:editors']}``); the ``groupfinder`` function
consults the ``GROUPS`` data structure. This means that the
``editor`` user can edit pages.
Viewing the Application in a Browser
------------------------------------
We can finally examine our application in a browser. The views we'll
try are as follows:
- Visiting ``http://localhost:6543/`` in a browser invokes the
``view_wiki`` view. This always redirects to the ``view_page`` view
of the FrontPage page object. It is executable by any user.
- Visiting ``http://localhost:6543/FrontPage/`` in a browser invokes
the ``view_page`` view of the front page page object. This is
because it's the :term:`default view` (a view without a ``name``)
for ``Page`` objects. It is executable by any user.
- Visiting ``http://localhost:6543/FrontPage/edit_page`` in a browser
invokes the edit view for the front page object. It is executable
by only the ``editor`` user. If a different user (or the anonymous
user) invokes it, a login form will be displayed. Supplying the
credentials with the username ``editor``, password ``editor`` will
show the edit page form being displayed.
- Visiting ``http://localhost:6543/add_page/SomePageName`` in a
browser invokes the add view for a page. It is executable by only
the ``editor`` user. If a different user (or the anonymous user)
invokes it, a login form will be displayed. Supplying the
credentials with the username ``editor``, password ``editor`` will
show the edit page form being displayed.
Seeing Our Changes To ``views.py`` and our Templates
----------------------------------------------------
Our ``views.py`` module will look something like this when we're done:
.. literalinclude:: src/authorization/tutorial/views.py
:linenos:
:language: python
Our ``edit.pt`` template will look something like this when we're done:
.. literalinclude:: src/authorization/tutorial/templates/edit.pt
:linenos:
:language: xml
Our ``view.pt`` template will look something like this when we're done:
.. literalinclude:: src/authorization/tutorial/templates/view.pt
:linenos:
:language: xml
Revisiting the Application
---------------------------
When we revisit the application in a browser, and log in (as a result
of hitting an edit or add page and submitting the login form with the
``editor`` credentials), we'll see a Logout link in the upper right
hand corner. When we click it, we're logged out, and redirected back
to the front page.