view MoinMoin/web/ @ 4628:3c6980b5e938

fix new session code. remove old session code. details below. Removed the old 1.8 session code (MoinMoin.session): * cfg.session_handler and session_id_handler are gone (use cfg.session_service) * cfg.anonymous_session_lifetime is gone (use cfg.cookie_lifetime) Fixed new 1.9 session code (MoinMoin.web.session): * cfg.cookie_lifetime is now a tuple (anon, loggedin), giving the lifetime of the cookie in hours, accepting floats, for anon sessions and logged in sessions. Default is (0, 12). 0 means not to use a session cookie (== not to establish a session) and makes only sense for anon users. * cfg.cookie_httponly is new and defaults to True. * when logging out, the session cookie is deleted. * more debug logging
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 07 Mar 2009 19:10:05 +0100
parents d8e5e9cfadf1
children 554e1d780e3b
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
    MoinMoin - WSGI session handling

    To provide sessions, the MoinMoin WSGI application interacts with an
    object implementing the `SessionService` API. The interface is quite
    straight forward. For documentation of the expected methods, refer
    to the documentation of `SessionService` in this module.

    @copyright: 2008 MoinMoin:FlorianKrupicka,
                2009 MoinMoin:ThomasWaldmann
    @license: GNU GPL, see COPYING for details.
import time

from werkzeug.contrib.sessions import FilesystemSessionStore, Session

from MoinMoin.util import filesys

from MoinMoin import log
logging = log.getLogger(__name__)

class MoinSession(Session):
    """ Compatibility interface to Werkzeug-sessions for old Moin-code. """
    is_new = property(lambda s:
    is_stored = property(lambda s: True)

class SessionService(object):
    A session service returns a session object given a request object and
    provides services like persisting sessions and cleaning up occasionally.
    def get_session(self, request, sid=None):
        """ Return a session object pertaining to the particular request."""
        raise NotImplementedError

    def destroy_session(self, request, session):
        """ Destroy an existing session (make it unusable). """
        raise NotImplementedError

    def finalize(self, request, session):
        If the service needs to do anything to the session and/or request,
        before it is sent back to the client, he can chose to do so here.
        Typical examples would be setting cookies for the client.
        raise NotImplementedError

class FileSessionService(SessionService):
    This sample session service stores session information in a temporary
    directory and identifies the session via a cookie in the request/response
    cycle. It is based on werkzeug's FilesystemSessionStore, that implements
    the whole logic for creating the actual session objects (which are
    inherited from the builtin `dict`)
    def __init__(self, cookie_name='MOIN_SESSION'):
        self.cookie_name = cookie_name = None

    def _store_get(self, request):
        if is None:
            path = request.cfg.session_dir
            except OSError:
   = FilesystemSessionStore(path=path, filename_template='%s', session_class=MoinSession)

    def get_session(self, request, sid=None):
        if sid is None:
            sid = request.cookies.get(self.cookie_name, None)
        store = self._store_get(request)
        if sid is None:
            session =
            session = store.get(sid)
        return session

    def destroy_session(self, request, session):
        store = self._store_get(request)

    def finalize(self, request, session):
        if request.user.auth_method == 'setuid':
            userobj = request._setuid_real_user
            setuid =
            userobj = request.user
            setuid = None
        logging.debug("finalize userobj = %r, setuid = %r" % (userobj, setuid))
        cfg = request.cfg
        cookie_path = cfg.cookie_path or request.script_root or '/'
        if userobj and userobj.valid:
            session[''] =
            session['user.auth_method'] = userobj.auth_method
            session['user.auth_attribs'] = userobj.auth_attribs
            if setuid:
                session['setuid'] = setuid
            elif 'setuid' in session:
                del session['setuid']
            logging.debug("after auth: storing valid user into session: %r" %
            logging.debug("after auth: user is invalid")
            if '' in session:
                logging.debug("after auth: destroying session: %r" % session)
                self.destroy_session(request, session)
                logging.debug("after auth: deleting session cookie!")
                request.delete_cookie(self.cookie_name, path=cookie_path, domain=cfg.cookie_domain)

            lifetime_h = cfg.cookie_lifetime[userobj and userobj.valid]
            cookie_lifetime = int(float(lifetime_h) * 3600)
            if cookie_lifetime:
                cookie_expires = time.time() + cookie_lifetime
                # a secure cookie is not transmitted over unsecure connections:
                cookie_secure = (cfg.cookie_secure or  # True means: force secure cookies
                    cfg.cookie_secure is None and request.is_secure)  # None means: https -> secure cookie
                logging.debug("user: %r, setting session cookie: %r" % (userobj, session.sid))
                request.set_cookie(self.cookie_name, session.sid,
                                   max_age=cookie_lifetime, expires=cookie_expires,
                                   path=cookie_path, domain=cfg.cookie_domain,
                                   secure=cookie_secure, httponly=cfg.cookie_httponly)

        if session.should_save:
            store = self._store_get(request)
            logging.debug("saving session: %r" % session)