Back to index

moin  1.9.0~rc2
session.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003     MoinMoin - WSGI session handling
00004 
00005     To provide sessions, the MoinMoin WSGI application interacts with an
00006     object implementing the `SessionService` API. The interface is quite
00007     straight forward. For documentation of the expected methods, refer
00008     to the documentation of `SessionService` in this module.
00009 
00010     @copyright: 2008 MoinMoin:FlorianKrupicka,
00011                 2009 MoinMoin:ThomasWaldmann
00012     @license: GNU GPL, see COPYING for details.
00013 """
00014 import time
00015 
00016 from werkzeug.contrib.sessions import FilesystemSessionStore, Session
00017 
00018 from MoinMoin.util import filesys
00019 
00020 from MoinMoin import log
00021 logging = log.getLogger(__name__)
00022 
00023 class MoinSession(Session):
00024     """ Compatibility interface to Werkzeug-sessions for old Moin-code. """
00025     is_new = property(lambda s: s.new)
00026 
00027 class SessionService(object):
00028     """
00029     A session service returns a session object given a request object and
00030     provides services like persisting sessions and cleaning up occasionally.
00031     """
00032     def get_session(self, request, sid=None):
00033         """ Return a session object pertaining to the particular request."""
00034         raise NotImplementedError
00035 
00036     def destroy_session(self, request, session):
00037         """ Destroy an existing session (make it unusable). """
00038         raise NotImplementedError
00039 
00040     def finalize(self, request, session):
00041         """
00042         If the service needs to do anything to the session and/or request,
00043         before it is sent back to the client, he can chose to do so here.
00044         Typical examples would be setting cookies for the client.
00045         """
00046         raise NotImplementedError
00047 
00048 def _get_session_lifetime(request, userobj):
00049     """ Get session lifetime for the user object userobj
00050     Cookie lifetime in hours, can be fractional. First tuple element is for anonymous sessions,
00051     second tuple element is for logged-in sessions. For anonymous sessions,
00052     t=0 means that they are disabled, t>0 means that many hours.
00053     For logged-in sessions, t>0 means that many hours,
00054     or forever if user checked 'remember_me', t<0 means -t hours and
00055     ignore user 'remember_me' setting - you usually don't want to use t=0, it disables logged-in sessions."""
00056     lifetime = int(float(request.cfg.cookie_lifetime[userobj and userobj.valid]) * 3600)
00057     forever = 10 * 365 * 24 * 3600 # 10 years
00058 
00059     if userobj and userobj.valid and userobj.remember_me and lifetime > 0:
00060         return forever
00061     return abs(lifetime)
00062 
00063 class FileSessionService(SessionService):
00064     """
00065     This sample session service stores session information in a temporary
00066     directory and identifies the session via a cookie in the request/response
00067     cycle. It is based on werkzeug's FilesystemSessionStore, that implements
00068     the whole logic for creating the actual session objects (which are
00069     inherited from the builtin `dict`)
00070     """
00071     def __init__(self, cookie_name='MOIN_SESSION'):
00072         self.cookie_name = cookie_name
00073         self.store = None
00074 
00075     def _store_get(self, request):
00076         if self.store is None:
00077             path = request.cfg.session_dir
00078             try:
00079                 filesys.mkdir(path)
00080             except OSError:
00081                 pass
00082             self.store = FilesystemSessionStore(path=path, filename_template='%s', session_class=MoinSession)
00083         return self.store
00084 
00085     def get_session(self, request, sid=None):
00086         if sid is None:
00087             sid = request.cookies.get(self.cookie_name, None)
00088         store = self._store_get(request)
00089         if sid is None:
00090             session = store.new()
00091         else:
00092             session = store.get(sid)
00093         return session
00094 
00095     def destroy_session(self, request, session):
00096         session.clear()
00097         store = self._store_get(request)
00098         store.delete(session)
00099 
00100     def finalize(self, request, session):
00101         if request.user.auth_method == 'setuid':
00102             userobj = request._setuid_real_user
00103             setuid = request.user.id
00104         else:
00105             userobj = request.user
00106             setuid = None
00107         logging.debug("finalize userobj = %r, setuid = %r" % (userobj, setuid))
00108         cfg = request.cfg
00109         cookie_path = cfg.cookie_path or request.script_root or '/'
00110         if userobj and userobj.valid:
00111             session['user.id'] = userobj.id
00112             session['user.auth_method'] = userobj.auth_method
00113             session['user.auth_attribs'] = userobj.auth_attribs
00114             if setuid:
00115                 session['setuid'] = setuid
00116             elif 'setuid' in session:
00117                 del session['setuid']
00118             logging.debug("after auth: storing valid user into session: %r" % userobj.name)
00119         else:
00120             logging.debug("after auth: user is invalid")
00121             if 'user.id' in session:
00122                 logging.debug("after auth: destroying session: %r" % session)
00123                 self.destroy_session(request, session)
00124                 logging.debug("after auth: deleting session cookie!")
00125                 request.delete_cookie(self.cookie_name, path=cookie_path, domain=cfg.cookie_domain)
00126 
00127         cookie_lifetime = _get_session_lifetime(request, userobj)
00128         if cookie_lifetime:
00129             cookie_expires = time.time() + cookie_lifetime
00130             # a secure cookie is not transmitted over unsecure connections:
00131             cookie_secure = (cfg.cookie_secure or  # True means: force secure cookies
00132                              cfg.cookie_secure is None and request.is_secure)  # None means: https -> secure cookie
00133             logging.debug("user: %r, setting session cookie: %r" % (userobj, session.sid))
00134             request.set_cookie(self.cookie_name, session.sid,
00135                                max_age=cookie_lifetime, expires=cookie_expires,
00136                                 path=cookie_path, domain=cfg.cookie_domain,
00137                                secure=cookie_secure, httponly=cfg.cookie_httponly)
00138 
00139             if session.should_save:
00140                 store = self._store_get(request)
00141                 logging.debug("saving session: %r" % session)
00142                 store.save(session)
00143