summaryrefslogtreecommitdiff
path: root/docs/narr/sessions.rst
diff options
context:
space:
mode:
authorAlexandre Bourget <alexandre.bourget@savoirfairelinux.com>2011-03-24 12:07:09 -0400
committerAlexandre Bourget <alexandre.bourget@savoirfairelinux.com>2011-03-24 12:07:09 -0400
commit95e799d074de2e81914d513b4c331df1e738c00e (patch)
treeb3039037533610d8c86d82bb28f139d8a3777013 /docs/narr/sessions.rst
parent22d3253a26767501827d86b56db3a9b79bef6c4e (diff)
parentb596e1812627c359908759d7a8d83c339f08e385 (diff)
downloadpyramid-95e799d074de2e81914d513b4c331df1e738c00e.tar.gz
pyramid-95e799d074de2e81914d513b4c331df1e738c00e.tar.bz2
pyramid-95e799d074de2e81914d513b4c331df1e738c00e.zip
Merge remote branch 'source/master'
Conflicts: docs/narr/hooks.rst
Diffstat (limited to 'docs/narr/sessions.rst')
-rw-r--r--docs/narr/sessions.rst192
1 files changed, 187 insertions, 5 deletions
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst
index de9add3b7..97e3ebc55 100644
--- a/docs/narr/sessions.rst
+++ b/docs/narr/sessions.rst
@@ -3,13 +3,18 @@
.. _sessions_chapter:
-Session Objects
-===============
+Sessions
+========
A :term:`session` is a namespace which is valid for some period of
continual activity that can be used to represent a user's interaction
with a web application.
+This chapter describes how to configure sessions, what session
+implementations :app:`Pyramid` provides out of the box, how to store and
+retrieve data from sessions, and two session-specific features: flash
+messages, and cross-site request forgery attack prevention.
+
.. _using_the_default_session_factory:
Using The Default Session Factory
@@ -32,12 +37,12 @@ limitation:
representation of the session is fewer than 4000. This is
suitable only for very small data sets.
-It is, however, digitally signed, and thus its data cannot easily be
+It is digitally signed, however, and thus its data cannot easily be
tampered with.
You can configure this session factory in your :app:`Pyramid`
application by using the ``session_factory`` argument to the
-:class:`pyramid.config.Configurator` class:
+:class:`~pyramid.config.Configurator` class:
.. code-block:: python
:linenos:
@@ -113,7 +118,7 @@ documentation.
Some gotchas:
- Keys and values of session data must be *pickleable*. This means,
- typically, that they must be instances of basic types of objects,
+ typically, that they are instances of basic types of objects,
such as strings, lists, dictionaries, tuples, integers, etc. If you
place an object in a session data key or value that is not
pickleable, an error will be raised when the session is serialized.
@@ -162,3 +167,180 @@ both types are available in
:class:`pyramid.interfaces.ISession`. You might use the cookie
implementation in the :mod:`pyramid.session` module as inspiration.
+.. index::
+ single: flash messages
+
+Flash Messages
+--------------
+
+"Flash messages" are simply a queue of message strings stored in the
+:term:`session`. To use flash messaging, you must enable a :term:`session
+factory` as described in :ref:`using_the_default_session_factory` or
+:ref:`using_alternate_session_factories`.
+
+Flash messaging has two main uses: to display a status message only once to
+the user after performing an internal redirect, and to allow generic code to
+log messages for single-time display without having direct access to an HTML
+template. The user interface consists of a number of methods of the
+:term:`session` object.
+
+Using the ``session.flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To add a message to a flash message queue, use a session object's ``flash()``
+method:
+
+.. code-block:: python
+
+ request.session.flash('mymessage')
+
+The ``flash()`` method appends a message to a flash queue, creating the queue
+if necessary.
+
+``flash()`` accepts three arguments:
+
+.. method:: flash(message, queue='', allow_duplicate=True)
+
+The ``message`` argument is required. It represents a message you wish to
+later display to a user. It is usually a string but the ``message`` you
+provide is not modified in any way.
+
+The ``queue`` argument allows you to choose a queue to which to append
+the message you provide. This can be used to push different kinds of
+messages into flash storage for later display in different places on a
+page. You can pass any name for your queue, but it must be a string.
+Each queue is independent, and can be popped by ``pop_flash()`` or
+examined via ``peek_flash()`` separately. ``queue`` defaults to the
+empty string. The empty string represents the default flash message
+queue.
+
+.. code-block:: python
+
+ request.session.flash(msg, 'myappsqueue')
+
+The ``allow_duplicate`` argument defaults to ``True``. If this is
+``False``, and you attempt to add a message value which is already
+present in the queue, it will not be added.
+
+Using the ``session.pop_flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once one or more messages have been added to a flash queue by the
+``session.flash()`` API, the ``session.pop_flash()`` API can be used to
+pop an entire queue and return it for use.
+
+To pop a particular queue of messages from the flash object, use the session
+object's ``pop_flash()`` method. This returns a list of the messages
+that were added to the flash queue, and empties the queue.
+
+.. method:: pop_flash(queue='')
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.pop_flash()
+ ['info message']
+
+Calling ``session.pop_flash()`` again like above without a corresponding call
+to ``session.flash()`` will return an empty list, because the queue has already
+been popped.
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.pop_flash()
+ ['info message']
+ >>> request.session.pop_flash()
+ []
+
+Using the ``session.peek_flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once one or more messages has been added to a flash queue by the
+``session.flash()`` API, the ``session.peek_flash()`` API can be used to
+"peek" at that queue. Unlike ``session.pop_flash()``, the queue is not
+popped from flash storage.
+
+.. method:: peek_flash(queue='')
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.peek_flash()
+ ['info message']
+ >>> request.session.peek_flash()
+ ['info message']
+ >>> request.session.pop_flash()
+ ['info message']
+ >>> request.session.peek_flash()
+ []
+
+.. index::
+ single: preventing cross-site request forgery attacks
+ single: cross-site request forgery attacks, prevention
+
+Preventing Cross-Site Request Forgery Attacks
+---------------------------------------------
+
+`Cross-site request forgery
+<http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a
+phenomenon whereby a user with an identity on your website might click on a
+URL or button on another website which unwittingly redirects the user to your
+application to perform some command that requires elevated privileges.
+
+You can avoid most of these attacks by making sure that the correct *CSRF
+token* has been set in an :app:`Pyramid` session object before performing any
+actions in code which requires elevated privileges that is invoked via a form
+post. To use CSRF token support, you must enable a :term:`session factory`
+as described in :ref:`using_the_default_session_factory` or
+:ref:`using_alternate_session_factories`.
+
+Using the ``session.get_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To get the current CSRF token from the session, use the
+``session.get_csrf_token()`` method.
+
+.. code-block:: python
+
+ token = request.session.get_csrf_token()
+
+The ``session.get_csrf_token()`` method accepts no arguments. It returns a
+CSRF *token* string. If ``session.get_csrf_token()`` or
+``session.new_csrf_token()`` was invoked previously for this session, the
+existing token will be returned. If no CSRF token previously existed for
+this session, a new token will be will be set into the session and returned.
+The newly created token will be opaque and randomized.
+
+You can use the returned token as the value of a hidden field in a form that
+posts to a method that requires elevated privileges. The handler for the
+form post should use ``session.get_csrf_token()`` *again* to obtain the
+current CSRF token related to the user from the session, and compare it to
+the value of the hidden form field. For example, if your form rendering
+included the CSRF token obtained via ``session.get_csrf_token()`` as a hidden
+input field named ``csrf_token``:
+
+.. code-block:: python
+ :linenos:
+
+ token = request.session.get_csrf_token()
+ if token != request.POST['csrf_token']:
+ raise ValueError('CSRF token did not match')
+
+Using the ``session.new_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To explicitly add a new CSRF token to the session, use the
+``session.new_csrf_token()`` method. This differs only from
+``session.get_csrf_token()`` inasmuch as it clears any existing CSRF token,
+creates a new CSRF token, sets the token into the session, and returns the
+token.
+
+.. code-block:: python
+
+ token = request.session.new_csrf_token()
+
+