diff -r bdc3dc94d744 -r 470d8e828fda goa/appobjects/sessions.py --- a/goa/appobjects/sessions.py Fri Sep 24 18:20:57 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,291 +0,0 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of CubicWeb. -# -# CubicWeb is free software: you can redistribute it and/or modify it under the -# terms of the GNU Lesser General Public License as published by the Free -# Software Foundation, either version 2.1 of the License, or (at your option) -# any later version. -# -# CubicWeb is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -# details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with CubicWeb. If not, see . -"""persistent sessions stored in big table - - -XXX TODO: -* cleanup persistent session -* use user as ancestor? -""" -__docformat__ = "restructuredtext en" - -from pickle import loads, dumps -from time import localtime, strftime - -from logilab.common.decorators import cached, clear_cache - -from cubicweb import BadConnectionId -from cubicweb.dbapi import Connection, ConnectionProperties, repo_connect -from cubicweb.selectors import none_rset, match_user_groups -from cubicweb.server.session import Session -from cubicweb.web import InvalidSession -from cubicweb.web.application import AbstractSessionManager -from cubicweb.web.application import AbstractAuthenticationManager - -from google.appengine.api.datastore import Key, Entity, Get, Put, Delete, Query -from google.appengine.api.datastore_errors import EntityNotFoundError -from google.appengine.api.datastore_types import Blob - -try: - del Connection.__del__ -except AttributeError: - pass # already deleted - - -class GAEAuthenticationManager(AbstractAuthenticationManager): - """authenticate user associated to a request and check session validity, - using google authentication service - """ - - def __init__(self, *args, **kwargs): - super(GAEAuthenticationManager, self).__init__(*args, **kwargs) - self._repo = self.config.repository(vreg=self.vreg) - - def authenticate(self, req, _login=None, _password=None): - """authenticate user and return an established connection for this user - - :raise ExplicitLogin: if authentication is required (no authentication - info found or wrong user/password) - """ - if _login is not None: - login, password = _login, _password - else: - login, password = req.get_authorization() - # remove possibly cached cursor coming from closed connection - clear_cache(req, 'cursor') - cnxprops = ConnectionProperties(self.vreg.config.repo_method, - close=False, log=False) - cnx = repo_connect(self._repo, login, password=password, cnxprops=cnxprops) - self._init_cnx(cnx, login, password) - # associate the connection to the current request - req.set_connection(cnx) - return cnx - - def _init_cnx(self, cnx, login, password): - cnx.anonymous_connection = self.config.is_anonymous_user(login) - cnx.vreg = self.vreg - cnx.login = login - cnx.password = password - - -class GAEPersistentSessionManager(AbstractSessionManager): - """manage session data associated to a session identifier""" - - def __init__(self, vreg, *args, **kwargs): - super(GAEPersistentSessionManager, self).__init__(vreg, *args, **kwargs) - self._repo = self.config.repository(vreg=vreg) - - def get_session(self, req, sessionid): - """return existing session for the given session identifier""" - # search a record for the given session - key = Key.from_path('CubicWebSession', 'key_' + sessionid, parent=None) - try: - record = Get(key) - except EntityNotFoundError: - raise InvalidSession() - repo = self._repo - if self.has_expired(record): - repo._sessions.pop(sessionid, None) - Delete(record) - raise InvalidSession() - # associate it with a repository session - try: - reposession = repo._get_session(sessionid) - user = reposession.user - # touch session to avoid closing our own session when sessions are - # cleaned (touch is done on commit/rollback on the server side, too - # late in that case) - reposession._touch() - except BadConnectionId: - # can't found session in the repository, this probably mean the - # session is not yet initialized on this server, hijack the repo - # to create it - # use an internal connection - ssession = repo.internal_session() - # try to get a user object - try: - user = repo.authenticate_user(ssession, record['login'], - record['password']) - finally: - ssession.close() - reposession = Session(user, self._repo, _id=sessionid) - self._repo._sessions[sessionid] = reposession - cnx = Connection(self._repo, sessionid) - return self._get_proxy(req, record, cnx, user) - - def open_session(self, req): - """open and return a new session for the given request""" - cnx = self.authmanager.authenticate(req) - # avoid rebuilding a user - user = self._repo._get_session(cnx.sessionid).user - # build persistent record for session data - record = Entity('CubicWebSession', name='key_' + cnx.sessionid) - record['login'] = cnx.login - record['password'] = cnx.password - record['anonymous_connection'] = cnx.anonymous_connection - Put(record) - return self._get_proxy(req, record, cnx, user) - - def close_session(self, proxy): - """close session on logout or on invalid session detected (expired out, - corrupted...) - """ - proxy.close() - - def current_sessions(self): - for record in Query('CubicWebSession').Run(): - yield ConnectionProxy(record) - - def _get_proxy(self, req, record, cnx, user): - proxy = ConnectionProxy(record, cnx, user) - user.req = req - req.set_connection(proxy, user) - return proxy - - -class ConnectionProxy(object): - - def __init__(self, record, cnx=None, user=None): - self.__record = record - self.__cnx = cnx - self.__user = user - self.__data = None - self.__is_dirty = False - self.sessionid = record.key().name()[4:] # remove 'key_' prefix - - def __repr__(self): - sstr = '') - self.w(u'%s web sessions closed
\n' % nbclosed) - # clean repository sessions - repo = self.config.repository(vreg=self.vreg) - nbclosed = repo.clean_sessions() - self.w(u'%s repository sessions closed
\n' % nbclosed) - self.w(u'%s remaining sessions
\n' % remaining) - self.w(u'') - - -def registration_callback(vreg): - vreg.register(SessionsCleaner) - vreg.register(GAEAuthenticationManager, clear=True) - vreg.register(GAEPersistentSessionManager, clear=True)