Cleanup session files periodically. Fixes #3674

This commit is contained in:
Akshay Joshi 2018-10-09 11:34:13 +01:00 committed by Dave Page
parent c66840bc8e
commit 7144db7f5a
5 changed files with 62 additions and 10 deletions

View File

@ -15,4 +15,5 @@ Features
Bug fixes Bug fixes
********* *********
| `Bug #3674 <https://redmine.postgresql.org/issues/3674>`_ - Cleanup session files periodically.
| `Bug #3660 <https://redmine.postgresql.org/issues/3660>`_ - Rename the 'SQL Editor' section of the Preferences to 'Query Tool' as it applies to the whole tool, not just the editor. | `Bug #3660 <https://redmine.postgresql.org/issues/3660>`_ - Rename the 'SQL Editor' section of the Preferences to 'Query Tool' as it applies to the whole tool, not just the editor.

View File

@ -387,6 +387,17 @@ SESSION_SKIP_PATHS = [
'/misc/ping' '/misc/ping'
] ]
##########################################################################
# Session expiration support
##########################################################################
# SESSION_EXPIRATION_TIME is the interval in Days. Session will be
# expire after the specified number of *days*.
SESSION_EXPIRATION_TIME = 1
# CHECK_SESSION_FILES_INTERVAL is interval in Hours. Application will check
# the session files for cleanup after specified number of *hours*.
CHECK_SESSION_FILES_INTERVAL = 24
########################################################################## ##########################################################################
# SSH Tunneling supports only for Python 2.7 and 3.4+ # SSH Tunneling supports only for Python 2.7 and 3.4+
########################################################################## ##########################################################################

View File

@ -32,6 +32,7 @@ from pgadmin.utils import PgAdminModule, driver
from pgadmin.utils.preferences import Preferences from pgadmin.utils.preferences import Preferences
from pgadmin.utils.session import create_session_interface, pga_unauthorised from pgadmin.utils.session import create_session_interface, pga_unauthorised
from pgadmin.utils.versioned_template_loader import VersionedTemplateLoader from pgadmin.utils.versioned_template_loader import VersionedTemplateLoader
from datetime import timedelta
# If script is running under python3, it will not have the xrange function # If script is running under python3, it will not have the xrange function
# defined # defined
@ -354,6 +355,10 @@ def create_app(app_name=None):
# register custom unauthorised handler. # register custom unauthorised handler.
app.login_manager.unauthorized_handler(pga_unauthorised) app.login_manager.unauthorized_handler(pga_unauthorised)
# Set the permanent session lifetime to the specified value in config file.
app.permanent_session_lifetime = timedelta(
days=config.SESSION_EXPIRATION_TIME)
app.session_interface = create_session_interface( app.session_interface = create_session_interface(
app, config.SESSION_SKIP_PATHS app, config.SESSION_SKIP_PATHS
) )

View File

@ -14,6 +14,7 @@ from flask import url_for, render_template, Response, request
from flask_babelex import gettext from flask_babelex import gettext
from pgadmin.utils import PgAdminModule from pgadmin.utils import PgAdminModule
from pgadmin.utils.preferences import Preferences from pgadmin.utils.preferences import Preferences
from pgadmin.utils.session import cleanup_session_files
import config import config
@ -99,6 +100,8 @@ def ping():
@blueprint.route("/cleanup", methods=['POST']) @blueprint.route("/cleanup", methods=['POST'])
def cleanup(): def cleanup():
driver.ping() driver.ping()
# Cleanup session files.
cleanup_session_files()
return "" return ""

View File

@ -23,6 +23,7 @@ import os
import random import random
import string import string
import time import time
import config
from uuid import uuid4 from uuid import uuid4
from threading import Lock from threading import Lock
from flask import current_app, request, flash, redirect from flask import current_app, request, flash, redirect
@ -52,6 +53,7 @@ def _calc_hmac(body, secret):
sess_lock = Lock() sess_lock = Lock()
LAST_CHECK_SESSION_FILES = None
class ManagedSession(CallbackDict, SessionMixin): class ManagedSession(CallbackDict, SessionMixin):
@ -68,6 +70,7 @@ class ManagedSession(CallbackDict, SessionMixin):
self.last_write = None self.last_write = None
self.force_write = False self.force_write = False
self.hmac_digest = hmac_digest self.hmac_digest = hmac_digest
self.permanent = True
def sign(self, secret): def sign(self, secret):
if not self.hmac_digest: if not self.hmac_digest:
@ -283,14 +286,8 @@ class FileBackedSessionManager(SessionManager):
class ManagedSessionInterface(SessionInterface): class ManagedSessionInterface(SessionInterface):
def __init__(self, manager, cookie_timedelta): def __init__(self, manager):
self.manager = manager self.manager = manager
self.cookie_timedelta = cookie_timedelta
def get_expiration_time(self, app, session):
if session.permanent:
return app.permanent_session_lifetime
return datetime.datetime.now() + self.cookie_timedelta
def open_session(self, app, request): def open_session(self, app, request):
cookie_val = request.cookies.get(app.session_cookie_name) cookie_val = request.cookies.get(app.session_cookie_name)
@ -341,8 +338,7 @@ def create_session_interface(app, skip_paths=[]):
), ),
1000, 1000,
skip_paths skip_paths
), ))
datetime.timedelta(days=1))
def pga_unauthorised(): def pga_unauthorised():
@ -372,3 +368,39 @@ def pga_unauthorised():
flash(login_message, category=lm.login_message_category) flash(login_message, category=lm.login_message_category)
return redirect(login_url(lm.login_view, request.url)) return redirect(login_url(lm.login_view, request.url))
def cleanup_session_files():
"""
This function will iterate through session directory and check the last
modified time, if it older than (session expiration time + 1) days then
delete that file.
"""
global LAST_CHECK_SESSION_FILES
if LAST_CHECK_SESSION_FILES is None:
LAST_CHECK_SESSION_FILES = datetime.datetime.now()
else:
if datetime.datetime.now() >= LAST_CHECK_SESSION_FILES + \
datetime.timedelta(hours=config.CHECK_SESSION_FILES_INTERVAL):
for root, dirs, files in os.walk(
current_app.config['SESSION_DB_PATH']):
for file_name in files:
absolute_file_name = os.path.join(root, file_name)
st = os.stat(absolute_file_name)
# Get the last modified time of the session file
last_modified_time = \
datetime.datetime.fromtimestamp(st.st_mtime)
# Calculate session file expiry time.
file_expiration_time = \
last_modified_time + \
current_app.permanent_session_lifetime + \
datetime.timedelta(days=1)
if file_expiration_time <= datetime.datetime.now():
if os.path.exists(absolute_file_name):
os.unlink(absolute_file_name)
LAST_CHECK_SESSION_FILES = datetime.datetime.now()