summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorCarlos de la Guardia <cguardia@yahoo.com>2012-04-06 18:28:18 -0700
committerCarlos de la Guardia <cguardia@yahoo.com>2012-04-06 18:28:18 -0700
commiteb6d456db87d81a9041aefce7e963be23f200851 (patch)
tree1b0e695997529d3b0020eac0af7846a3c101a1c7 /docs
parentd806f9babf869d1eaf0ec19fb6d0b3a14c5ae92d (diff)
parent89e011e72ae8bbec1e6d91cfbe7be83e2352d6fd (diff)
downloadpyramid-eb6d456db87d81a9041aefce7e963be23f200851.tar.gz
pyramid-eb6d456db87d81a9041aefce7e963be23f200851.tar.bz2
pyramid-eb6d456db87d81a9041aefce7e963be23f200851.zip
Merge pull request #524 from ppaez/sql-wiki-authorization
Sql wiki authorization
Diffstat (limited to 'docs')
-rw-r--r--docs/tutorials/wiki2/authorization.rst255
-rw-r--r--docs/tutorials/wiki2/design.rst2
2 files changed, 130 insertions, 127 deletions
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index 3573e06af..14b075ce6 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -12,19 +12,27 @@ to allow only people who possess a specific username (`editor`)
to add and edit wiki pages but we'll continue allowing anyone with access to
the server to view pages.
-We will do the following steps:
+We will also add a login page and a logout link on all the
+pages. The login page will be shown when a user is denied
+access to any of the views that require a permission, instead of
+a default "403 Forbidden" page.
-* Add a :term:`root factory` with an :term:`ACL` (``models.py``,
+We will implement the access control with the following steps:
+
+* Add users and groups (``security.py``, a new module).
+* Add an :term:`ACL` (``models.py`` and
``__init__.py``).
* Add an :term:`authentication policy` and an :term:`authorization policy`
(``__init__.py``).
-* Add an authentication policy callback (new ``security.py`` module).
-* Add routes for /login and /logout (``__init__.py``).
-* Add ``login`` and ``logout`` views (``views.py``).
* Add :term:`permission` declarations to the ``edit_page`` and ``add_page``
views (``views.py``).
+
+Then we will add the login and logout feature:
+
+* Add routes for /login and /logout (``__init__.py``).
+* Add ``login`` and ``logout`` views (``views.py``).
+* Add a login template (``login.pt``).
* Make the existing views return a ``logged_in`` flag to the renderer (``views.py``).
-* Add a login template (new ``login.pt``).
* Add a "Logout" link to be shown when logged in and viewing or editing a page
(``view.pt``, ``edit.pt``).
@@ -32,8 +40,40 @@ The source code for this tutorial stage can be browsed at
`http://github.com/Pylons/pyramid/tree/1.3-branch/docs/tutorials/wiki2/src/authorization/
<http://github.com/Pylons/pyramid/tree/1.3-branch/docs/tutorials/wiki2/src/authorization/>`_.
-Adding A Root Factory
-~~~~~~~~~~~~~~~~~~~~~
+Access Control
+--------------
+
+Add users and groups
+~~~~~~~~~~~~~~~~~~~~
+
+Create a new ``tutorial/tutorial/security.py`` module with the
+following content:
+
+.. literalinclude:: src/authorization/tutorial/security.py
+ :linenos:
+ :language: python
+
+The ``groupfinder`` function accepts a userid and a request and
+returns one of these values:
+
+- If the userid exists in the system, it 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, it will
+ return ``None``.
+
+For example, ``groupfinder('editor', request )`` returns ['group:editor'],
+``groupfinder('viewer', request)`` returns [], and ``groupfinder('admin', request)``
+returns ``None``. We will use ``groupfinder()`` as an :term:`authentication policy`
+"callback" that will provide the :term:`principal` or principals
+for a user.
+
+In a production system, user and group
+data will most often come from a database, but here we use "dummy"
+data to represent user and groups sources.
+
+Add an ACL
+~~~~~~~~~~
Open ``tutorial/tutorial/models.py`` and add the following import
statement at the head:
@@ -50,13 +90,22 @@ Add the following class definition:
:linenos:
:language: python
-The ``RootFactory`` class is a :term:`root factory` that will be used by
-:app:`Pyramid` to construct the :term:`context` of each request to
-our application. The context is attached to the request
-object passed to our view callables as the ``context`` attribute,
-and will be decorated with security declarations. By using a custom
-root factory to generate our contexts, we can use the
-declarative security features of :app:`Pyramid`.
+We import :data:`~pyramid.security.Allow`, an action that
+means that permission is allowed:, and
+:data:`~pyramid.security.Everyone`, a special :term:`principal`
+that is associated to all requests. Both are used in the
+:term:`ACE` entries that make up the ACL.
+
+The ACL is a list that needs to be named `__acl__` and be an
+attribute of a class. We define an :term:`ACL` with two
+:term:`ACE` entries: the first entry allows any user the `view`
+permission. The second entry allows the ``group:editors``
+principal the `edit` permission.
+
+The ``RootFactory`` class that contains the ACL is a :term:`root factory`.
+We need to associate it to our :app:`Pyramid` application, so the ACL is
+provided to each view as the :term:`context` of each request, as
+the ``context`` attribute.
Open ``tutorial/tutorial/__init__.py`` and add a ``root_factory``
parameter to our :term:`Configurator` constructor, that points to
@@ -70,13 +119,9 @@ the class we created above:
(Only the highlighted line needs to be added.)
-The context object generated by our root factory will possess an ``__acl__``
-attribute that allows :data:`pyramid.security.Everyone` (a special principal)
-to view all pages, while allowing only a :term:`principal` named
-``group:editors`` to edit and add pages. The ``__acl__`` attribute attached
-to a context is interpreted specially by :app:`Pyramid` as an access control
-list during view callable execution. See :ref:`assigning_acls` for more
-information about what an :term:`ACL` represents.
+We are now providing the ACL to the application. See
+:ref:`assigning_acls` for more information about what an
+:term:`ACL` represents.
.. note::
@@ -85,17 +130,10 @@ information about what an :term:`ACL` represents.
the ``factory`` argument to
:meth:`pyramid.config.Configurator.add_route` for more info.
-Add an Authorization Policy and an Authentication Policy
+Add an Authentication Policy and an Authorization Policy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-For any :app:`Pyramid` application to perform authorization, we need to add a
-``security.py`` module (we'll do that shortly) and we'll need to change our
-``__init__.py`` file to add an :term:`authentication policy` and an
-:term:`authorization policy` which uses the ``security.py`` file for a
-*callback*.
-
-We'll enable an ``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy``
-to implement declarative security checking. Open ``tutorial/__init__.py`` and
+Open ``tutorial/__init__.py`` and
add these import statements:
.. literalinclude:: src/authorization/tutorial/__init__.py
@@ -113,46 +151,40 @@ Now add those policies to the configuration:
(Only the highlighted lines need to be added.)
+We are enabling an ``AuthTktAuthenticationPolicy``, it is based in an auth
+ticket that may be included in the request, and an ``ACLAuthorizationPolicy``
+that uses an ACL to determine the allow or deny outcome for a view.
+
Note that the
:class:`pyramid.authentication.AuthTktAuthenticationPolicy` constructor
accepts 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
-``groupfinder`` function in the current directory's ``security.py`` file. We
-haven't added that module yet, but we're about to.
+represented by this policy: it is required. The ``callback`` is the
+``groupfinder()`` function the we created before.
-Adding an authentication policy callback
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Add permission declarations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Create a new ``tutorial/tutorial/security.py`` module with the
-following content:
+Add a ``permission='edit'`` parameter to the ``@view_config``
+decorator for ``add_page()`` and ``edit_page()``, for example:
-.. literalinclude:: src/authorization/tutorial/security.py
+.. code-block:: python
:linenos:
- :language: python
+ :emphasize-lines: 2
-``groupfinder()`` is an :term:`authentication policy`
-"callback"; it is a function that accepts a userid and a request and
-returns one of these values:
+ @view_config(route_name='add_page', renderer='templates/edit.pt',
+ permission='edit')
-- If the userid exists in 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``.
+(Only the highlighted line needs to be added.)
-We've given the ``editor`` user membership to the ``group:editors`` by
-mapping him to this group in the ``GROUPS`` data structure above.
-Since the ``groupfinder`` function
-consults the ``GROUPS`` data structure, this will mean that, as a
-result of the ACL attached to the :term:`context` object returned by
-the root factory, and the permission associated with the ``add_page``
-and ``edit_page`` views, the ``editor`` user should be able to add and
-edit pages.
+The result is that only users who possess the ``edit``
+permission at the time of the request may invoke those two views.
-In a production system, user and group
-data will most often come from a database, but here we use "dummy"
-data to represent user and groups sources.
+We are done with the changes needed to control access. The
+changes that follow will add the login and logout feature.
+
+Login, Logout
+-------------
Add routes for /login and /logout
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,87 +206,70 @@ We'll also add a ``logout`` view callable to our application and
provide a link to it. This view will clear the credentials of the
logged in user and redirect back to the front page.
-The ``login`` view callable will look something like this:
+Add the following import statements to the
+head of ``tutorial/tutorial/views.py``:
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 89-115
+ :lines: 9-16,18,24-25
:linenos:
+ :emphasize-lines: 3,6-9,11
:language: python
-The ``logout`` view callable will look something like this:
+(Only the highlighted lines need to be added.)
+
+:meth:`~pyramid.view.forbidden_view_config` will be used
+to customize the default 403 Forbidden page.
+:meth:`~pyramid.security.remember` and
+:meth:`~pyramid.security.forget` help to create and
+expire an auth ticket cookie.
+
+Now add the ``login`` and ``logout`` views:
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 117-121
+ :lines: 89-121
:linenos:
:language: python
-The ``login`` view callable is decorated with two decorators, a
+``login()`` is decorated with two decorators, a
``@view_config`` decorator, which associates it with the ``login``
-route, and a ``@forbidden_view_config`` decorator which turns it in to
-an :term:`exception view`. The one which associates it with the
-``login`` route makes it visible when we visit ``/login``. The other
-one makes it a :term:`forbidden view`. The forbidden view is
+route and makes it visible when we visit ``/login``,
+and a ``@forbidden_view_config`` decorator which turns it into
+an :term:`forbidden view`. The forbidden view is
displayed whenever Pyramid or your application raises an
:class:`pyramid.httpexceptions.HTTPForbidden` exception. In this
-case, we'll be relying on the forbidden view to show the login form
-whenever someone attempts to execute an action which they're not yet
+case we'll show the login form whenever someone attempts
+to execute an action which they're not yet
authorized to perform.
-The ``logout`` view callable is decorated with a ``@view_config`` decorator
-which associates it with the ``logout`` route. This makes it visible when we
+``logout()`` is decorated with a ``@view_config`` decorator
+which associates it with the ``logout`` route. This makes it match when we
visit ``/logout``.
-We'll need to import some stuff to service the needs of these two functions:
-the ``pyramid.view.forbidden_view_config`` class, a number of values from the
-``pyramid.security`` module, and a value from our newly added
-``tutorial.security`` package. Add the following import statements to the
-head of ``tutorial/tutorial/views.py``:
-
-.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 9-18,24-25
- :linenos:
- :emphasize-lines: 3,7-8,12
- :language: python
-
-(Only the highlighted lines need to be added.)
-
-Add permission declarations
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Add a ``permission='edit'`` parameter to the ``@view_config``
-decorator for ``add_page()`` and ``edit_page()``, for example:
-
-.. code-block:: python
- :linenos:
- :emphasize-lines: 2
-
- @view_config(route_name='add_page', renderer='templates/edit.pt',
- permission='edit')
+Adding the ``login.pt`` Template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(Only the highlighted line needs to be added.)
+Create ``tutorial/tutorial/templates/login.pt`` with the following
+content:
-The result is that only users who possess the ``edit``
-permission at the time of the request may invoke those two views.
+.. literalinclude:: src/authorization/tutorial/templates/login.pt
+ :language: xml
-We've granted the ``group:editors`` :term:`principal` the ``edit``
-permission in the :term:`root factory` via its ACL, so only a user who
-is a member of the group named ``group:editors`` will be able to
-invoke the views associated with the ``add_page`` or ``edit_page``
-routes.
+The above template is referred to within the login view we just
+added to ``views.py``.
Return a logged_in flag to the renderer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Add the following import statement to the head of
+Add the following line to the import at the head of
``tutorial/tutorial/views.py``:
-.. code-block:: python
+.. literalinclude:: src/authorization/tutorial/views.py
+ :lines: 14-18
:linenos:
+ :emphasize-lines: 4
+ :language: python
- from pyramid.security import (
- authenticated_userid,
- )
-
+(Only the highlighted line needs to be added.)
Add a ``logged_in`` parameter to the return value of
``view_page()``, ``edit_page()`` and ``add_page()``,
@@ -275,18 +290,6 @@ like this:
if the user is not authenticated, or some user id it the user
is authenticated.
-Adding the ``login.pt`` Template
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Create ``tutorial/tutorial/templates/login.pt`` with the following
-content:
-
-.. literalinclude:: src/authorization/tutorial/templates/login.pt
- :language: xml
-
-The above template is referred to within the login view we just
-added to ``views.py``.
-
Add a "Logout" link when logged in
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -306,7 +309,7 @@ the logout view. The above element will not be included if ``logged_in``
is ``None``, such as when a user is not authenticated.
Seeing Our Changes
-~~~~~~~~~~~~~~~~~~
+------------------
Our ``tutorial/tutorial/__init__.py`` will look something like this
when we're done:
@@ -347,7 +350,7 @@ something like this when we're done:
(Only the highlighted lines need to be added.)
Viewing the Application in a Browser
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+------------------------------------
We can finally examine our application in a browser (See
:ref:`wiki2-start-the-application`). Launch a browser and visit
diff --git a/docs/tutorials/wiki2/design.rst b/docs/tutorials/wiki2/design.rst
index 1ff000549..4481153a3 100644
--- a/docs/tutorials/wiki2/design.rst
+++ b/docs/tutorials/wiki2/design.rst
@@ -87,7 +87,7 @@ listed in the following table:
| | | | | |
| | | | | |
+----------------------+-----------------------+-------------+------------+------------+
-| /edit_page/PageName | Display edit form | edit_page | edit.pt | edit |
+| /PageName/edit_page | Display edit form | edit_page | edit.pt | edit |
| | with existing | | | |
| | content. | | | |
| | | | | |