From afbf03b46b64a38e9e25099186d286454e28f27b Mon Sep 17 00:00:00 2001 From: Baghirov Feyruz Date: Mon, 14 Oct 2024 13:49:09 +0200 Subject: [PATCH] test of new table in database and check try --- .../codechecker_server/api/authentication.py | 109 ++++++------------ .../database/config_db_model.py | 12 ++ ..._create_a_state_table_for_verification_.py | 37 ++++++ web/server/vue-cli/package-lock.json | 12 +- .../functional/authentication/oauth_server.py | 3 +- .../authentication/test_authentication.py | 6 +- 6 files changed, 97 insertions(+), 82 deletions(-) create mode 100644 web/server/codechecker_server/migrations/config/versions/5bdea278c415_create_a_state_table_for_verification_.py diff --git a/web/server/codechecker_server/api/authentication.py b/web/server/codechecker_server/api/authentication.py index 4a462264da..82bf4e5261 100644 --- a/web/server/codechecker_server/api/authentication.py +++ b/web/server/codechecker_server/api/authentication.py @@ -11,7 +11,6 @@ import datetime import sqlite3 -import os from authlib.integrations.requests_client import OAuth2Session from authlib.common.security import generate_token @@ -30,7 +29,7 @@ from codechecker_server.profiler import timeit from ..database.config_db_model import Product, ProductPermission, Session, \ - SystemPermission + StateCodes, SystemPermission from ..database.database import DBSession from ..permissions import handler_from_scope_params as make_handler, \ require_manager, require_permission @@ -52,8 +51,6 @@ def __init__(self, manager, auth_session, config_database): self.__manager = manager self.__auth_session = auth_session self.__config_db = config_database - self.__db_path = os.path.expanduser( - '~/.codechecker/state_codes.sqlite') def __require_privilaged_access(self): """ @@ -152,33 +149,6 @@ def getAccessControl(self): globalPermissions=global_permissions, productPermissions=product_permissions) - @timeit - def createdatabase(self): - """ - Create the SQLite database for storing the state codes - """ - - # Check if the database file exists - if os.path.exists(self.__db_path): - LOG.debug(f"Database of states {self.__db_path} already exists.") - return - - # Create the database and the table - # Create the database and the table - try: - conn = sqlite3.connect(self.__db_path) - conn.execute( - "CREATE TABLE state_codes (" - "ID INTEGER PRIMARY KEY AUTOINCREMENT, " - "state TEXT, " - "expires_at DATETIME)" - ) - conn.close() - LOG.debug("successfully created" - f" Database of states {self.__db_path}") - except sqlite3.Error as e: - LOG.error(f"An error occurred: {e}") - @timeit def insertState(self, state): """ @@ -188,34 +158,43 @@ def insertState(self, state): # remove all the expired state codes from the database try: date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - conn = sqlite3.connect(self.__db_path) - conn.execute("DELETE FROM state_codes " - "WHERE expires_at < DATETIME(\"" + date + "\")") - conn.commit() - conn.close() + with DBSession(self.__config_db) as session: + + session.execute("DELETE FROM state_codes " + "WHERE expires_at " + "< DATETIME(\"" + date + "\")") + session.commit() + LOG.info("Expired state codes removed successfully.") except sqlite3.Error as e: - LOG.error(f"An error occurred: {e}") + LOG.error(f"An error occurred insertion: {e}") # Insert the state code into the database try: - date = (datetime.datetime.now() + datetime.timedelta(minutes=15)) \ - .strftime("%Y-%m-%d %H:%M:%S") - conn = sqlite3.connect(self.__db_path) - # Insert the state code into the database - conn.execute("INSERT INTO state_codes (state, expires_at) " - "VALUES (?, ?)", (state, date)) - conn.commit() - state_id = conn.execute("SELECT ID FROM state_codes " - "WHERE state = ? AND expires_at = ?", - (state, date)).fetchone()[0] - conn.close() - LOG.debug(f"State {state[0]} inserted successfully.") + with DBSession(self.__config_db) as session: + LOG.debug(f"State {state} insertion started.") + date = (datetime.datetime.now() + + datetime.timedelta(minutes=15)) + + new_state = StateCodes(state=state, expires_at=date) + session.add(new_state) + session.commit() + LOG.debug("State inserted into the database") + + state_id = session.query(StateCodes) \ + .filter(StateCodes.state == new_state.state + and + StateCodes.expires_at == new_state.expires_at) \ + .first().id + + LOG.debug("FETCHED STATE ID") + LOG.debug(f"State {state} inserted successfully") + LOG.debug(f"State {state[0]} inserted successfully.") return state_id except sqlite3.Error as e: - LOG.error(f"An error occurred: {e}") + LOG.error(f"An error occurred: {e}") # added here re1move raise codechecker_api_shared.ttypes.RequestFailed( codechecker_api_shared.ttypes.ErrorCode.AUTH_DENIED, - "STATE insertion failed.") + "STATE insertion failed. Please try again.") @timeit def getOauthProviders(self): @@ -226,13 +205,6 @@ def createLink(self, provider): """ For creating a autehntication link for OAuth for specified provider """ - try: - self.createdatabase() - except Exception as ex: - LOG.error("Database creation failed: %s", str(ex)) - raise codechecker_api_shared.ttypes.RequestFailed( - codechecker_api_shared.ttypes.ErrorCode.AUTH_DENIED, - "Database creation failed.") oauth_config = self.__manager.get_oauth_config(provider) if not oauth_config.get('enabled'): raise codechecker_api_shared.ttypes.RequestFailed( @@ -266,14 +238,12 @@ def createLink(self, provider): "State code insertion failed.") LOG.debug(f"State {state} inserted successfully with ID {state_id}") - print(url + "&state_id=" + str(state_id)) # added here re1move return url + "&state_id=" + str(state_id) @timeit def performLogin(self, auth_method, auth_string): - print("**********************") - print(auth_method, auth_string) - print("**********************") + print(f" ********** auth_method: {auth_method}") + print(f" ********** auth_string: {auth_string}") if not auth_string: raise codechecker_api_shared.ttypes.RequestFailed( @@ -308,16 +278,13 @@ def performLogin(self, auth_method, auth_string): code = parsed_query.get("code")[0] state = parsed_query.get("state")[0] state_id = parsed_query.get("state_id")[0] + state_db = None + with DBSession(self.__config_db) as session: - conn = sqlite3.connect(self.__db_path) - state_db = conn.execute("SELECT state " - "FROM state_codes " - "WHERE ID = " + state_id).fetchone()[0] - - # Delete the state from the database - conn.execute('DELETE FROM state_codes WHERE ID = ' + state_id) - conn.close() - + state_db = session.query(StateCodes) \ + .filter(StateCodes.id == state_id) \ + .first().state + # Delete the state from the database # THINK ABOUT ME if state_db != state: LOG.error("State code mismatch.") raise codechecker_api_shared.ttypes.RequestFailed( diff --git a/web/server/codechecker_server/database/config_db_model.py b/web/server/codechecker_server/database/config_db_model.py index 00f0c4948e..957e6dd247 100644 --- a/web/server/codechecker_server/database/config_db_model.py +++ b/web/server/codechecker_server/database/config_db_model.py @@ -158,6 +158,18 @@ def __init__(self, config_key, config_value): self.config_value = config_value +class StateCodes(Base): + __tablename__ = 'state_codes' + + id = Column(Integer, autoincrement=True, primary_key=True) + state = Column(String, nullable=False) + expires_at = Column(DateTime) + + def __init__(self, state, expires_at): + self.state = state + self.expires_at = expires_at + + IDENTIFIER = { 'identifier': "ConfigDatabase", 'orm_meta': CC_META diff --git a/web/server/codechecker_server/migrations/config/versions/5bdea278c415_create_a_state_table_for_verification_.py b/web/server/codechecker_server/migrations/config/versions/5bdea278c415_create_a_state_table_for_verification_.py new file mode 100644 index 0000000000..ed3f3c00c7 --- /dev/null +++ b/web/server/codechecker_server/migrations/config/versions/5bdea278c415_create_a_state_table_for_verification_.py @@ -0,0 +1,37 @@ +""" +Create a state table for verification for OAuth + +Revision ID: 5bdea278c415 +Revises: 00099e8bc212 +Create Date: 2024-10-09 16:14:33.235797 +""" + +from logging import getLogger + +from alembic import op +import sqlalchemy as sa + +# Revision identifiers, used by Alembic. +revision = '5bdea278c415' +down_revision = '00099e8bc212' +branch_labels = None +depends_on = None + + +def upgrade(): + LOG = getLogger("migration/config") + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('state_codes', + sa.Column('id', sa.Integer(), + autoincrement=True, nullable=False), + sa.Column('state', sa.String(), nullable=False), + sa.Column('expires_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id', name=op.f('pk_state_codes'))) + # ### end Alembic commands ### + + +def downgrade(): + LOG = getLogger("migration/config") + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('state_codes') + # ### end Alembic commands ### diff --git a/web/server/vue-cli/package-lock.json b/web/server/vue-cli/package-lock.json index 3a4aacb0d5..03ff378853 100644 --- a/web/server/vue-cli/package-lock.json +++ b/web/server/vue-cli/package-lock.json @@ -16397,9 +16397,9 @@ } }, "node_modules/webpack": { - "version": "5.94.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", - "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", "dev": true, "dependencies": { "@types/estree": "^1.0.5", @@ -29496,9 +29496,9 @@ } }, "webpack": { - "version": "5.94.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", - "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", "dev": true, "requires": { "@types/estree": "^1.0.5", diff --git a/web/tests/functional/authentication/oauth_server.py b/web/tests/functional/authentication/oauth_server.py index 49ef9f562b..e008256c78 100644 --- a/web/tests/functional/authentication/oauth_server.py +++ b/web/tests/functional/authentication/oauth_server.py @@ -87,8 +87,7 @@ def login_tester(self): if query_result: state = params['state'] code = query_result['code'] - state_id = params['state_id'] # added here re1move - return self.show_json({"code": code, "state": state, "state_id": state_id}) # added here re1move + return self.show_json({"code": code, "state": state}) return self.show_rejection("Invalid credentials") except IndexError: return self.show_rejection("Invalid query parameters") diff --git a/web/tests/functional/authentication/test_authentication.py b/web/tests/functional/authentication/test_authentication.py index 79e07a4817..60718d02a0 100644 --- a/web/tests/functional/authentication/test_authentication.py +++ b/web/tests/functional/authentication/test_authentication.py @@ -198,9 +198,9 @@ def try_login(self, provider, username, password): raise RequestFailed(data['error']) link = link.split('?')[0] - code, state, state_id = data['code'], data['state'], data['state_id'] # added here re1move - auth_string = f"{link}?code={code}&state={state}&state_id={state_id}" # added here re1move - #login?code=b297074a409d34818198&state=msuPS01qPAQrTsxYKMeVpDlG0hd3uc&state_id=4 + code, state = data['code'], data['state'] + auth_string = f"{link}?code={code}&state={state}" + self.session_token = auth_client.performLogin( "oauth", provider + "@" + auth_string)