Skip to content

Commit 91350fd

Browse files
authored
Merge pull request #5039 from barnabasdomozi/db_sessions
[fix] Cleanup expired sessions from the database
2 parents 7e6a4c0 + 14fe5f8 commit 91350fd

5 files changed

Lines changed: 69 additions & 3 deletions

File tree

web/server/codechecker_server/api/authentication.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import string
2424

2525
from collections import defaultdict
26+
from typing import Optional
2627

2728
from codechecker_api.Authentication_v6.ttypes import AccessControl, \
2829
AuthorisationList, HandshakeInformation, Permissions, \
2930
PersonalAccessToken, SessionTokenData
31+
from sqlalchemy.orm import sessionmaker
3032

3133
from codechecker_common.logger import get_logger
3234

@@ -39,7 +41,8 @@
3941
from ..permissions import handler_from_scope_params as make_handler, \
4042
require_manager, require_permission
4143
from ..server import permissions
42-
from ..session_manager import generate_session_token
44+
from ..session_manager import (SessionManager, generate_session_token,
45+
_Session)
4346

4447

4548
LOG = get_logger('server')
@@ -51,6 +54,9 @@ class ThriftAuthHandler:
5154
"""
5255
Handle Thrift authentication requests.
5356
"""
57+
__manager: SessionManager
58+
__auth_session: Optional[_Session]
59+
__config_db: sessionmaker
5460

5561
def __init__(self, manager, auth_session, config_database):
5662
self.__manager = manager

web/server/codechecker_server/database/config_db_model.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ class OAuthToken(Base):
223223
ForeignKey('auth_sessions.id',
224224
deferrable=False,
225225
ondelete='CASCADE'),
226-
nullable=False)
226+
nullable=False,
227+
index=True)
227228

228229
def __init__(self, access_token, expires_at, refresh_token,
229230
auth_session_id):
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
Add index oauth_tokens(auth_session_id)
3+
4+
Revision ID: 635389f535cd
5+
Revises: 511b1b37de2e
6+
Create Date: 2026-08-17 15:28:04.316623
7+
"""
8+
9+
from alembic import op
10+
11+
12+
# Revision identifiers, used by Alembic.
13+
revision = '635389f535cd'
14+
down_revision = '511b1b37de2e'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
op.create_index(op.f('ix_oauth_tokens_auth_session_id'),
21+
'oauth_tokens', ['auth_session_id'], unique=False)
22+
23+
24+
def downgrade():
25+
op.drop_index(op.f('ix_oauth_tokens_auth_session_id'),
26+
table_name='oauth_tokens')

web/server/codechecker_server/server.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,14 @@ def start_server(config_directory: str, workspace_directory: str,
10511051
server_secrets_file = os.path.join(config_directory, 'server_secrets.json')
10521052

10531053
if not skip_db_cleanup:
1054+
# TODO:
1055+
# Perform a cleanup on the config database as well.
1056+
# - Do a garbage collection on table auth_sessions and
1057+
# remove expired sessions. Currently, this cleanup is only
1058+
# performed when a user logs in. Therefore, expired sessions
1059+
# can accumulate for users who no longer interact with the
1060+
# server.
1061+
10541062
all_success, fails = _do_db_cleanups(config_sql_server,
10551063
context,
10561064
check_env)

web/server/codechecker_server/session_manager.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import re
1515
import uuid
1616

17-
from datetime import datetime
17+
from datetime import datetime, timedelta
1818
import hashlib
1919
from typing import Optional
2020

@@ -32,6 +32,7 @@
3232
from .database.config_db_model import OAuthToken
3333
from .database.config_db_model import PersonalAccessToken
3434
from .database.config_db_model import SystemPermission
35+
from .database.database import DBSession
3536
from .permissions import SUPERUSER
3637

3738
import codechecker_api_shared
@@ -858,6 +859,25 @@ def __create_local_session(self, token, user_name, groups, is_root,
858859
self.__refresh_time, is_root, self.__config_db_sessionmaker,
859860
last_access)
860861

862+
def __cleanup_expired_auth_sessions(self, user_name: str):
863+
"""
864+
Cleanup expired auth_sessions of a user from the database.
865+
"""
866+
with DBSession(self.__config_db_sessionmaker) as session:
867+
try:
868+
cutoff_date = (datetime.now() - timedelta(
869+
seconds=self.__auth_config['session_lifetime']))
870+
session.query(SessionRecord) \
871+
.filter(SessionRecord.user_name == user_name) \
872+
.filter(SessionRecord.last_access < cutoff_date) \
873+
.delete(synchronize_session=False)
874+
875+
session.commit()
876+
except Exception as e:
877+
LOG.error("Failed to cleanup expired auth sessions "
878+
"from the database:")
879+
LOG.error(str(e))
880+
861881
def create_session(self, auth_string):
862882
""" Creates a new session for the given auth-string. """
863883
if not self.__auth_config['enabled']:
@@ -889,6 +909,9 @@ def create_session(self, auth_string):
889909
groups = validation.get('groups', [])
890910
is_root = validation.get('root', False)
891911

912+
if user_name:
913+
self.__cleanup_expired_auth_sessions(user_name)
914+
892915
local_session = self.__create_local_session(token, user_name,
893916
groups, is_root)
894917
self.__sessions.append(local_session)
@@ -953,6 +976,8 @@ def create_session_oauth(self, provider: str,
953976
'groups': groups,
954977
'is_root': False}
955978

979+
self.__cleanup_expired_auth_sessions(username)
980+
956981
local_session = self.__create_local_session(
957982
codechecker_session_token,
958983
user_data.get('username'),

0 commit comments

Comments
 (0)