session module

Synopsis

The session module provides way to group HTTP requests into "sessions" so that information can be maintained between an individual user's requests to various parts of a web site - for example, so that a user can "log in" to the web site and their username remembered as they navigate the site.

Usage

The base Session class is not used directly, since it has no way of storing the data associated with a session. Instead, one of the classes derived from it are used. The choice of subclass determines what storage method is used - the module provides FileSession and GenericSQLSession, or you can write your own.

To store data in the session, you simply use it as a mapping. For example:

if "basket" in self.session:
  self.session["basket"].append(newitem)
else:
  self.session["basket"] = [newitem]

Sessions are identified by a unique 8-character hexadecimal string, which is usually generated randomly. This is paired with another 8-character hexadecimal string which is a keyed hash generated using the identifier and a secret key unique to the individual web site. The hash simply makes it a bit more difficult for an attacker to guess a valid session identifier. The id and hash are stored in the session under the keys id and hash, so don't try to use these keys for storing your own data.

The session identifier and hash are passed from request to request either using cookies or by embedding the data at the start of the path in the URL. Which method to use depends on the situation - cookies are better, but some users disable cookies in their browsers. An especially important point to note is that if session identifiers are stored in URLs, any external links must go through a doorway page which forwards the user (using something like <meta http-equiv="refresh"...> rather than HTTP redirects) to the external page, because otherwise the session information may get passed to the external site in the HTTP Referer header.

To create and maintain the session, a session class should be instantiated at the start of processing a request, and its save method called at the end of processing.

Example:

class Handler(wt.Handler):
  def process(self, req):
    self.session = session.FileSession(req, "s3cr3t")
    if not self.session.relocated:
      wt.Handler.process(self, req)
      self.session.save()

Apache Configuration

If you are passing the session identifier in the URL, then you will need to configure your web server so that it knows what to do with this identifier. If you are not embedding the session identifier in the URL, then no extra configuration of the web server is required.

Using Apache, you should use mod_rewrite to extract the session identifier from the URL and pass it in the SESSION environment variable. The URL is then modified to remove the identifier so that the web server can find the requested page.

Example using httpd.conf:

<VirtualHost 192.168.0.1>
  ServerName www.example.com
   ...
  RewriteEngine on
  RewriteRule ^/([A-Fa-f0-9]{16})(/.*)$ $2 [E=SESSION:$1]
<VirtualHost>

Example using an .htaccesss file in the web root directory:

RewriteEngine on
RewriteBase /
RewriteRule ^([A-Fa-f0-9]{16})(/.*)$ $2 [E=SESSION:$1]

If you are using the wt templating module in conjunction with the session module, you should simply put the single session RewriteRule line before the wt RewriteCond line, e.g.:

RewriteEngine on
RewriteBase /
RewriteRule ^([A-Fa-f0-9]{16})(/.*)$ $2 [E=SESSION:$1]
RewriteCond %{DOCUMENT_ROOT}/wt/$1.py -f
RewriteRule ^(.*)$ /wt/$1.py [E=WT_TEMPLATE_URL:/$1,E=WT_TEMPLATE_FILENAME:%{DOCUMENT_ROOT}/$1]

class: Error(Exception)

The base class for all exceptions defined by the session module.

class: Session(dict)

Session objects manage the session as well as providing a container to store data associated with the session. This class is not used directly, but is subclassed depending on what method is being used to store the session data.

Public Instance Variables

relocated

The relocated map references a true value if URL-based sessions are being used and a Location header has been set to redirect the user's browser to a new URL.

created

The number of seconds since the epoch (i.e. time.time() value) when this session was created.

new

new references a true value if the session was created during this request (i.e. there was no pre-existing session).

surl

This variable is only present if session identifiers are being embedded in URLs for the current session. If it is present, it is the URL prefix that is used for this purpose - e.g. /0a33817bc823781f/.

Public Methods

__init__(self, req, secret, cookie="jonsid", url=0, root="",
         referer=None, sid=None, shash=None, secure=0, domain=None)

req: cgi.Request instance
secret: string
cookie: string
url: true or false value
root: string
referer: string
sid: string
shash: string
secure: true or false value
domain: string

This method may be overridden by subclasses. It creates a new Session instance. secret is a secret key (i.e. any arbitrary string that you do not disclose) which is used for keying the hash used to verify session identifiers (see _make_hash). This value should be unique for each web site, unless you are deliberately trying to share session identifiers between sites.

cookie is the name of the session cookie which is used to store the session identifier. There is usually no need to change this from the default of jonsid. If you do not wish to use cookies to identify the session then set this parameter to None. If secure is true then the 'secure' flag of the cookie will be set, which tells browsers not to send the cookie if the connection is not encrypted. If domain is set then this will be used as the 'domain' parameter for the cookie.

If you wish to use session identifiers embedded in URLs then set url to a true value. You may then optionally also set root to be the web root at which sessions are anchored (i.e. a string to put before the session identifier in the url). root should begin with a / character but should not end in one. When using session identifiers in URLs, the session identifier will be looked for in environment variables matching (REDIRECT_){1,4}SESSION. Instructions on how to configure Apache to provide this variable are shown above.

You can optionally use the HTTP Referer header to help with session verification when using session identifiers in urls. If you set the referer parameter to a non-empty string (for example, the host name of your web site) and the user's browser sends a Referer header which does not contain that string, then the session is invalidated. This helps avoid unwanted session sharing in the situation where a user emails a URL to a friend. Note that this is not a security measure but just a helpful heuristic, since the contents of this header are under user control.

Finally, if you wish to identify the session in some other way, you can set cookie to None and url to 0 and then pass in the session identifier in sid. You may optionally also pass in the identifier hash in shash - if you do then the session identifier will be ignored and a new session created if the hash does not match the identifier. If you omit the shash parameter then the identifier will be assumed correct.

After initialisation has completed, the session dictionary contains the session identifier under key id, the identifier hash under key hash, and if the session was not new, any stored information from previous requests.

save(self)

This method may be overridden by subclasses. It stores the information from the current session's dictionary so that it may be retrieved in later requests. The default implementation does nothing.

Public Static Methods

tidy()

This method may be overridden by subclasses. It is used to delete session information that has expired, and should therefore be called periodically, perhaps from a cron job. Subclass versions of this method may require different parameters to the function - you cannot call this method without knowing the particulars of the particular subclass being used. The default implementation does nothing.

Protected Instance Variables

_req

The cgi.Request instance passed to the session's __init__ method.

Protected Methods

_make_hash(self, sid, secret)

sid: string
secret: string
Returns: string

This method may be overridden by subclasses. It returns the 8-character hexadecimal string which is a keyed hash of the session identifier sid and the secret key secret. The default implementation uses HMAC-SHA, and should not usually need to be overridden.

_create(self, secret)

secret: string

This method may be overridden by subclasses. It creates a new unique 8-character hexadecimal session identifier and initialises it in whatever storage system is being used. self["id"] should be set to the session identifier. Optionally, self["hash"] may also be set to the identifier hash. If the hash is not set then _make_hash will be called subsequently to determine it. The default implementation simply sets self["id"] to a random identifier.

_load(self)

This method may be overridden by subclasses. It updates the session's dictionary with whatever information the storage system has recorded about the session with identifier self["id"]. It should return 1 if the session identifier was located in the storage system, or 0 if it was not (in which case a new session will be created). The default implementation simply returns 1.

Note that this method should only return 0 if the session information could not be located because it did not exist. If any other error occurs (e.g. an I/O error while searching for the session), then an exception should be raised as usual.

class: FileSession(Session)

The FileSession class is a subclass of Session that uses the filesystem to store session data.

Public Methods

__init__(self, req, secret, basedir=None, **kwargs)

req: cgi.Request instance
secret: string
basedir: string

Creates a new FileSession instance. Session data will be stored using individual files in the filesystem, under the basedir directory. If basedir is not specified then the environment variable TMPDIR is used instead, or if there is no such environment variable then /tmp is used. A directory is created under this named jon-sessions-%d where %d is the current user id. If this directory already exists then it must be owned by the current user. req, secret, and kwargs are passed to the base class's __init__ method.

save(self)

The session's dictionary is written to the filesystem.

Public Static Methods

tidy(max_idle=0, max_age=0, basedir=None)

max_idle: integer
max_age: integer
basedir: string

Deletes session files that have expired. If max_idle is non-zero then it is the maximum number of seconds old a file's modification time may be before it is deleted. If max_age is non-zero then it is the maximum number of seconds old a session may be (since it was created) before it is deleted.

Protected Methods

_create(self, secret)

secret: string

Creates the session identifier and its associated file.

_load(self)

Updates the session's dictionary with the stored information from the session's file. Returns 0 if the file did not exist, otherwise 1.

class: GenericSQLSession(Session)

The GenericSQLSession class is a subclass of Session that uses an SQL database to store session data.

Public Methods

__init__(self, req, secret, dbc, table="sessions", **kwargs)

req: cgi.Request instance
secret: string
dbc: Python DB API Cursor instance
table: string

Creates a new GenericSQLSession instance. Session data will be stored using rows in an SQL table. The database is accessed via the Cursor instance dbc and the table name table. req, secret, and kwargs are passed to the base class's __init__ method.

The table must have at least the following fields:

CREATE TABLE sessions (
  ID          CHAR(8) NOT NULL,
  hash        CHAR(8) NOT NULL,
  data        BLOB NOT NULL,
  created     INT NOT NULL,
  updated     INT NOT NULL,
  PRIMARY KEY (ID)
);

This class has only been tested with MySQL, although the intention is that it should work with any DB API database.

save(self)

The session's dictionary is written to the database.

Public Static Methods

tidy(dbc, table="sessions", max_idle=0, max_age=0)

dbc: Python DB API Cursor instance
table: string
max_idle: integer
max_age: integer

Deletes session rows that have expired. If max_idle is non-zero then it is the maximum number of seconds old a session's updated time may be before it is deleted. If max_age is non-zero then it is the maximum number of seconds old a session's created time may be before it is deleted.

Protected Methods

_create(self, secret)

secret: string

Creates the session identifier and its associated table row.

_load(self)

Updates the session's dictionary with the stored information from the session's database row. Returns 0 if the row was not found, otherwise 1.

$Id: session.html,v 1.11 2008/08/15 15:44:11 jribbens Exp $