summaryrefslogtreecommitdiff
path: root/docs/tutorials/wiki/authorization.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/tutorials/wiki/authorization.rst')
-rw-r--r--docs/tutorials/wiki/authorization.rst236
1 files changed, 121 insertions, 115 deletions
diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst
index 062c553b5..1b66ace96 100644
--- a/docs/tutorials/wiki/authorization.rst
+++ b/docs/tutorials/wiki/authorization.rst
@@ -2,14 +2,13 @@
Adding Authorization
====================
-Our application currently allows anyone with access to the server to
-view, edit, and add pages to our wiki. For purposes of demonstration
-we'll change our application to allow people whom are members of a
-*group* named ``group:editors`` to add and edit wiki pages but we'll
-continue allowing anyone with access to the server to view pages.
-:app:`Pyramid` provides facilities for *authorization* and
-*authentication*. We'll make use of both features to provide security
-to our application.
+Our application currently allows anyone with access to the server to view,
+edit, and add pages to our wiki. For purposes of demonstration we'll change
+our application to allow people whom are members of a *group* named
+``group:editors`` to add and edit wiki pages but we'll continue allowing
+anyone with access to the server to view pages. :app:`Pyramid` provides
+facilities for *authorization* and *authentication*. We'll make use of both
+features to provide security to our application.
The source code for this tutorial stage can be browsed via
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/
@@ -19,33 +18,29 @@ The source code for this tutorial stage can be browsed via
Configuring a ``pyramid`` Authentication Policy
--------------------------------------------------
-For any :app:`Pyramid` application to perform authorization, we
-need to add a ``security.py`` module and we'll need to change our
-:term:`application registry` to add an :term:`authentication policy`
-and a :term:`authorization policy`.
+For any :app:`Pyramid` application to perform authorization, we need to add a
+``security.py`` module and we'll need to change our :term:`application
+registry` to add an :term:`authentication policy` and a :term:`authorization
+policy`.
-Changing ``configure.zcml``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Adding Authentication and Authorization Policies
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We'll change our ``configure.zcml`` file to enable an
-``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to
-enable declarative security checking. We'll also add a new view
-stanza, which specifies a :term:`forbidden view`. This configures our
-login view to show up when :app:`Pyramid` detects that a view
-invocation can not be authorized. When you're done, your
-``configure.zcml`` will look like so:
+We'll change our package's ``__init__.py`` file to enable an
+``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to enable
+declarative security checking. When you're done, your ``__init__.py`` will
+look like so:
-.. literalinclude:: src/authorization/tutorial/configure.zcml
+.. literalinclude:: src/authorization/tutorial/__init__.py
:linenos:
- :language: xml
+ :language: python
-Note that the ``authtktauthenticationpolicy`` tag has two attributes:
-``secret`` and ``callback``. ``secret`` is a string representing an
-encryption key used by the "authentication ticket" machinery
-represented by this policy: it is required. The ``callback`` is a
-string, representing a :term:`dotted Python name`, which points at the
-``groupfinder`` function in the current directory's ``security.py``
-file. We haven't added that module yet, but we're about to.
+Note that the creation of an ``AuthTktAuthenticationPolicy`` requires two
+arguments: ``secret`` and ``callback``. ``secret`` is a string representing
+an encryption key used by the "authentication ticket" machinery represented
+by this policy: it is required. The ``callback`` is a reference to a
+``groupfinder`` function in the ``tutorial`` package's ``security.py`` file.
+We haven't added that module yet, but we're about to.
Adding ``security.py``
~~~~~~~~~~~~~~~~~~~~~~
@@ -59,14 +54,13 @@ content:
:language: python
The ``groupfinder`` function defined here is an authorization policy
-"callback"; it is a callable that accepts a userid and a request. If
-the userid exists in the set of users known by the system, the
-callback will return a sequence of group identifiers (or an empty
-sequence if the user isn't a member of any groups). If the userid
-*does not* exist in the system, the callback will return ``None``. In
-a production system this data will most often come from a database,
-but here we use "dummy" data to represent user and groups
-sources. Note that the ``editor`` user is a member of the
+"callback"; it is a callable that accepts a userid and a request. If the
+userid exists in the set of users known by the system, the callback will
+return a sequence of group identifiers (or an empty sequence if the user
+isn't a member of any groups). If the userid *does not* exist in the system,
+the callback will return ``None``. In a production system this data will
+most often come from a database, but here we use "dummy" data to represent
+user and groups sources. Note that the ``editor`` user is a member of the
``group:editors`` group in our dummy group data (the ``GROUPS`` data
structure).
@@ -88,6 +82,26 @@ and logout views. Add a file named ``login.py`` to your application
:linenos:
:language: python
+Note that the ``login`` view callable in the ``login.py`` file has *two* view
+configuration decorators. The order of these decorators is unimportant.
+Each just adds a different :term:`view configuration` for the ``login`` view
+callable.
+
+The first view configuration decorator configures the ``login`` view callable
+so it will be invoked when someone visits ``/login`` (when the context is a
+Wiki and the view name is ``login``). The second decorator (with context of
+``pyramid.exceptions.Forbidden``) specifies a :term:`forbidden view`. This
+configures our login view to be presented to the user when :app:`Pyramid`
+detects that a view invocation can not be authorized. Because we've
+configured a forbidden view, the ``login`` view callable will be invoked
+whenever one of our users tries to execute a view callable that they are not
+allowed to invoke as determined by the :term:`authorization policy` in use.
+In our application, for example, this means that if a user has not logged in,
+and he tries to add or edit a Wiki page, he will be shown the login form.
+Before being allowed to continue on to the add or edit form, he will have to
+provide credentials that give him permission to add or edit via this login
+form.
+
Changing Existing Views
~~~~~~~~~~~~~~~~~~~~~~~
@@ -142,17 +156,15 @@ class="main_content">`` div:
<a href="${request.application_url}/logout">Logout</a>
</span>
-Giving Our Root Model Object an ACL
------------------------------------
+Giving Our Root Resource an ACL
+-------------------------------
-We need to give our root model object an :term:`ACL`. This ACL will
-be sufficient to provide enough information to the :app:`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 give our root resource object an :term:`ACL`. This ACL will be
+sufficient to provide enough information to the :app:`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:
+We need to perform some imports at module scope in our ``models.py`` file:
.. code-block:: python
:linenos:
@@ -160,8 +172,8 @@ file:
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:
+Our root resource object is a ``Wiki`` instance. We'll add the following
+line at class scope to our ``Wiki`` class:
.. code-block:: python
:linenos:
@@ -169,12 +181,11 @@ class scope to our ``Wiki`` class:
__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 :app:`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.
+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 :app:`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:
@@ -185,76 +196,71 @@ Our resulting ``models.py`` file will now look like so:
Adding ``permission`` Declarations to our ``view_config`` 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.view_config` decorators. To do so, within
-``views.py``:
+To protect each of our views with a particular permission, we need to pass a
+``permission`` argument to each of our :class:`pyramid.view.view_config`
+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_wiki``
+ view function. This makes the assertion that only users who possess the
+ ``view`` permission against the context resource 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
+- 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 against the context resource 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 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.
+ :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 against the context resource 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 decorator attached to the ``edit_page``
+ view function. This makes the assertion that only users who possess the
+ effective ``edit`` permission against the context resource 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:
+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/`` in a browser invokes the ``view_wiki``
+ view. This always redirects to the ``view_page`` view of the ``FrontPage``
+ page resource. 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/`` in a browser invokes the
+ ``view_page`` view of the ``FrontPage`` Page resource. This is because
+ it's the :term:`default view` (a view without a ``name``) for ``Page``
+ resources. 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/FrontPage/edit_page`` in a browser invokes
+ the edit view for the ``FrontPage`` Page resource. 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