From 611b01fd0e3a10baaadbd99dfbf7430a27faa01a Mon Sep 17 00:00:00 2001 From: Yann Date: Thu, 25 Aug 2016 10:17:08 +0200 Subject: [PATCH] Bugfixes on ram_session on sessions and on cookies - webui fix in cookies handling - ram_session fix in token generation (return an str : hex representation of os.urandom(n)) - more fixes in Client session handling --- lodel/auth/client.py | 31 +++++++++++++++++++++++-------- plugins/ram_sessions/__init__.py | 2 +- plugins/ram_sessions/main.py | 22 ++++++++++------------ plugins/webui/run.py | 26 ++++++++++++++------------ 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/lodel/auth/client.py b/lodel/auth/client.py index 80ca85d..1aa02b2 100644 --- a/lodel/auth/client.py +++ b/lodel/auth/client.py @@ -8,6 +8,7 @@ from lodel.settings import Settings from lodel import logger from lodel.plugin.hooks import LodelHook from lodel.plugin import SessionHandlerPlugin as SessionHandler +from .exceptions import * ##@brief Class designed to handle sessions and its datas class LodelSession(object): @@ -61,6 +62,7 @@ exists ! (exactly %d)" % refcount) raise ClientAuthenticationError("Trying to restore a session, but \ a session is allready started !!!") self.__datas = SessionHandler.restore(token) + self.__token = token return self.datas ##@brief Save the current session state @@ -68,7 +70,7 @@ a session is allready started !!!") if not self.started: raise ClientAuthenticationError( "Trying to save a non started session") - SessionHandler.save(self.__token) + SessionHandler.save(self.__token, self.__datas) ##@brief Destroy a session def destroy(self): @@ -185,6 +187,9 @@ class Client(object, metaclass = ClientMetaclass): self.__session = LodelSession(session_token) logger.debug("New client : %s" % self) + def __del__(self): + del(self.__session) + ##@brief Try to authenticate a user with a login and a password #@param login str : provided login #@param password str : provided password (hash) @@ -227,27 +232,37 @@ class Client(object, metaclass = ClientMetaclass): #@throw ClientAuthenticationFailure if token is not valid or not #existing @classmethod - def restore_session(self, token): + def restore_session(cls, token): cls._assert_instance() - return self.__session.restore(token) + return Client._instance.__session.restore(token) ##@brief Return the current session token or None #@return A session token or None @classmethod def session_token(cls): cls._assert_instance() - return cls._instance.__session.retrieve_token() + return Client._instance.__session.retrieve_token() @classmethod def session(cls): cls._assert_instance() - return cls._instance.__session - + return Client._instance.__session + + ##@brief Delete current session @classmethod def destroy(cls): cls._assert_instance() - cls._instance.__session.destroy() - + Client._instance.__session.destroy() + + ##@brief Delete current client and save its session + @classmethod + def clean(cls): + if Client._instance.__session.started: + Client._instance.__session.save() + if Client._instance is not None: + del(Client._instance) + Client._instance = None + ##@brief Test wether a client is anonymous or logged in #@return True if client is anonymous @classmethod diff --git a/plugins/ram_sessions/__init__.py b/plugins/ram_sessions/__init__.py index 5882c29..c7c34d7 100644 --- a/plugins/ram_sessions/__init__.py +++ b/plugins/ram_sessions/__init__.py @@ -10,6 +10,6 @@ __fullname__ = "RAM Session Store Plugin" CONFSPEC = { 'lodel2.sessions':{ 'expiration': (900, SettingValidator('int')), - 'token_size': (512, SettingValidator('int')), + 'tokensize': (512, SettingValidator('int')), } } diff --git a/plugins/ram_sessions/main.py b/plugins/ram_sessions/main.py index eec0ad2..84735e7 100644 --- a/plugins/ram_sessions/main.py +++ b/plugins/ram_sessions/main.py @@ -1,6 +1,7 @@ #-*- coding: utf-8 -*- import os import copy +import binascii from lodel import logger from lodel.settings import Settings @@ -8,20 +9,26 @@ from lodel.auth.exceptions import * __sessions = dict() +def __generate_token(): + return binascii.hexlify(os.urandom(Settings.sessions.tokensize//2)) + def _check_token(token): - if len(token) != Settings.sessions.token_size: + if len(token) != Settings.sessions.tokensize: raise ClientAuthenticationFailure("Malformed session token") if token not in __sessions: raise ClientAuthenticationFailure("No session with this token") def start_session(): - token = os.urandom(Settings.sessions.token_size) + token = __generate_token() __sessions[token] = dict() + _check_token(token) + logger.debug("New session created") return token def destroy_session(token): _check_token(token) del(__sessions[token]) + logger.debug("Session %s destroyed" % token) def restore_session(token): _check_token(token) @@ -31,14 +38,5 @@ def restore_session(token): def save_session(token, datas): _check_token(token) __sessions[token] = copy.copy(datas) - - -def get_value(token, name): - _check_token(token) - return __sessions[token][name] - -def del_value(token, name): - _check_token(token) - if name in __sessions[token]: - del(__sessions[token][name]) + logger.debug("Session saved") diff --git a/plugins/webui/run.py b/plugins/webui/run.py index d649065..de5fc08 100644 --- a/plugins/webui/run.py +++ b/plugins/webui/run.py @@ -26,13 +26,16 @@ session_store = FilesystemSessionStore(path=SESSION_FILES_BASE_DIR, filename_tem COOKIE_SESSION_ID = 'toktoken' COOKIE_SESSION_HASH = 'nekotkot' -COOKIE_SESSION_HASH_SALT = [ os.urandom(32) for _ in range(2) ] #Before and after salt (maybe useless) +#COOKIE_SESSION_HASH_SALT = [ os.urandom(32) for _ in range(2) ] #Before and after salt (maybe useless) +COOKIE_SESSION_HASH_SALT = ['salt1', 'salt2'] COOKIE_SESSION_HASH_ALGO = hashlib.sha512 ##@brief Return a salted hash of a cookie def cookie_hash(token): + token = str(token) + return COOKIE_SESSION_HASH_ALGO(token.encode()).hexdigest() return COOKIE_SESSION_HASH_ALGO( - COOKIE_SESSION_HASH_SALT[0]+token+COOKIE_SESSION_HASH_SALT[1]).hexdigest() + (COOKIE_SESSION_HASH_SALT[0]+token+COOKIE_SESSION_HASH_SALT[1]).encode()).hexdigest() ##@brief Load cookie from request @@ -41,9 +44,9 @@ def cookie_hash(token): #@return None or a session token def load_cookie(request): token = request.cookies.get(COOKIE_SESSION_ID) - if token is None and token != '': + token=token.encode() + if token is None or len(token) == 0: return None - token = bytes(token, 'utf-8') hashtok = request.cookies.get(COOKIE_SESSION_HASH) if hashtok is None: raise ClientAuthenticationFailure( @@ -103,11 +106,12 @@ def application(env, start_response): #to log messages with client infos client = WebUiClient(env['REMOTE_ADDR'], env['HTTP_USER_AGENT'], None) session_token = load_cookie(request) - if session_token is not None: - WebClient.restore_session(token) + WebUiClient.restore_session(session_token) + #next line is for testing purpose + print("ACCESS DATAS : ", WebUiClient['last_request']) session_token = None - #test + #next line is for testing purpose WebUiClient['last_request'] = time.time() try: controller = get_controller(request) @@ -124,18 +128,16 @@ def application(env, start_response): if session_token is not None: save_cookie(response,session_token) session_token = None - - except (ClientError, ClientAuthenticationError): - response = HttpException(400).render(request) + response = HttpException(200).render(request) empty_cookie(response) except ClientAuthenticationFailure: - response = HttpException(401).render(request) + response = HttpException(200).render(request) empty_cookie(response) except Exception as e: raise e res = response(env, start_response) - WebUiClient.destroy() + WebUiClient.clean() return res