diff options
| author | Chris McDonough <chrism@plope.com> | 2010-12-28 21:02:36 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2010-12-28 21:02:36 -0500 |
| commit | fcfc5aebc259fa34d8d2313adde7c2f57bab2e53 (patch) | |
| tree | c52e454f30ca7453da814e57635accc302d61b2b /docs/tutorials/wiki/authorization.rst | |
| parent | e8f26928bf5c8fb8490a72436718cedf8fe19281 (diff) | |
| parent | 02c43fe07f1ffe0cc27e539618ed8d96014cddee (diff) | |
| download | pyramid-fcfc5aebc259fa34d8d2313adde7c2f57bab2e53.tar.gz pyramid-fcfc5aebc259fa34d8d2313adde7c2f57bab2e53.tar.bz2 pyramid-fcfc5aebc259fa34d8d2313adde7c2f57bab2e53.zip | |
Merge branch 'master' into viewderiver
Diffstat (limited to 'docs/tutorials/wiki/authorization.rst')
| -rw-r--r-- | docs/tutorials/wiki/authorization.rst | 236 |
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 |
