From 815158852c8c103ef8f945349b9018227b0a90ba Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Thu, 26 Sep 2024 18:30:23 +0530 Subject: [PATCH 1/3] fix: oauth updates --- .../io/supertokens/storage/mysql/Start.java | 159 +++++++- .../storage/mysql/config/MySQLConfig.java | 16 + .../storage/mysql/queries/GeneralQueries.java | 30 ++ .../storage/mysql/queries/OAuthQueries.java | 356 ++++++++++++++++++ 4 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java diff --git a/src/main/java/io/supertokens/storage/mysql/Start.java b/src/main/java/io/supertokens/storage/mysql/Start.java index 1470bcc..4b9fe42 100644 --- a/src/main/java/io/supertokens/storage/mysql/Start.java +++ b/src/main/java/io/supertokens/storage/mysql/Start.java @@ -57,6 +57,8 @@ import io.supertokens.pluginInterface.multitenancy.exceptions.DuplicateThirdPartyIdException; import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException; import io.supertokens.pluginInterface.multitenancy.sqlStorage.MultitenancySQLStorage; +import io.supertokens.pluginInterface.oauth.OAuthLogoutChallenge; +import io.supertokens.pluginInterface.oauth.OAuthStorage; import io.supertokens.pluginInterface.passwordless.PasswordlessCode; import io.supertokens.pluginInterface.passwordless.PasswordlessDevice; import io.supertokens.pluginInterface.passwordless.exception.*; @@ -112,7 +114,7 @@ public class Start implements SessionSQLStorage, EmailPasswordSQLStorage, EmailVerificationSQLStorage, ThirdPartySQLStorage, JWTRecipeSQLStorage, PasswordlessSQLStorage, UserMetadataSQLStorage, UserRolesSQLStorage, UserIdMappingStorage, UserIdMappingSQLStorage, MultitenancyStorage, MultitenancySQLStorage, DashboardSQLStorage, TOTPSQLStorage, - ActiveUsersStorage, ActiveUsersSQLStorage, AuthRecipeSQLStorage { + ActiveUsersStorage, ActiveUsersSQLStorage, AuthRecipeSQLStorage, OAuthStorage { // these configs are protected from being modified / viewed by the dev using the SuperTokens // SaaS. If the core is not running in SuperTokens SaaS, this array has no effect. @@ -3034,6 +3036,161 @@ public int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(A } } + @Override + public boolean doesClientIdExistForApp(AppIdentifier appIdentifier, String clientId) + throws StorageQueryException { + try { + return OAuthQueries.isClientIdForAppId(this, clientId, appIdentifier); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public void addOrUpdateClientForApp(AppIdentifier appIdentifier, String clientId, boolean isClientCredentialsOnly) + throws StorageQueryException { + try { + OAuthQueries.insertClientIdForAppId(this, appIdentifier, clientId, isClientCredentialsOnly); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public boolean removeAppClientAssociation(AppIdentifier appIdentifier, String clientId) + throws StorageQueryException { + try { + return OAuthQueries.deleteClientIdForAppId(this, clientId, appIdentifier); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public List listClientsForApp(AppIdentifier appIdentifier) throws StorageQueryException { + try { + return OAuthQueries.listClientsForApp(this, appIdentifier); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public void revoke(AppIdentifier appIdentifier, String targetType, String targetValue, long exp) + throws StorageQueryException { + try { + OAuthQueries.revoke(this, appIdentifier, targetType, targetValue, exp); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public boolean isRevoked(AppIdentifier appIdentifier, String[] targetTypes, String[] targetValues, long issuedAt) + throws StorageQueryException { + try { + return OAuthQueries.isRevoked(this, appIdentifier, targetTypes, targetValues, issuedAt); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public void addM2MToken(AppIdentifier appIdentifier, String clientId, long iat, long exp) + throws StorageQueryException { + try { + OAuthQueries.addM2MToken(this, appIdentifier, clientId, iat, exp); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public void addLogoutChallenge(AppIdentifier appIdentifier, String challenge, String clientId, + String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated) throws StorageQueryException { + try { + OAuthQueries.addLogoutChallenge(this, appIdentifier, challenge, clientId, postLogoutRedirectionUri, sessionHandle, state, timeCreated); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public OAuthLogoutChallenge getLogoutChallenge(AppIdentifier appIdentifier, String challenge) + throws StorageQueryException { + try { + return OAuthQueries.getLogoutChallenge(this, appIdentifier, challenge); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public void deleteLogoutChallenge(AppIdentifier appIdentifier, String challenge) throws StorageQueryException { + try { + OAuthQueries.deleteLogoutChallenge(this, appIdentifier, challenge); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public void deleteLogoutChallengesBefore(AppIdentifier appIdentifier, long time) throws StorageQueryException { + try { + OAuthQueries.deleteLogoutChallengesBefore(this, appIdentifier, time); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public void cleanUpExpiredAndRevokedTokens(AppIdentifier appIdentifier) throws StorageQueryException { + try { + OAuthQueries.cleanUpExpiredAndRevokedTokens(this, appIdentifier); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public int countTotalNumberOfM2MTokensAlive(AppIdentifier appIdentifier) throws StorageQueryException { + try { + return OAuthQueries.countTotalNumberOfM2MTokensAlive(this, appIdentifier); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public int countTotalNumberOfM2MTokensCreatedSince(AppIdentifier appIdentifier, long since) + throws StorageQueryException { + try { + return OAuthQueries.countTotalNumberOfM2MTokensCreatedSince(this, appIdentifier, since); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public int countTotalNumberOfClientCredentialsOnlyClientsForApp(AppIdentifier appIdentifier) + throws StorageQueryException { + try { + return OAuthQueries.countTotalNumberOfClientsForApp(this, appIdentifier, true); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + @Override + public int countTotalNumberOfClientsForApp(AppIdentifier appIdentifier) throws StorageQueryException { + try { + return OAuthQueries.countTotalNumberOfClientsForApp(this, appIdentifier, false); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + + public static boolean isEnabledForDeadlockTesting() { return enableForDeadlockTesting; } diff --git a/src/main/java/io/supertokens/storage/mysql/config/MySQLConfig.java b/src/main/java/io/supertokens/storage/mysql/config/MySQLConfig.java index ea2f359..e514beb 100644 --- a/src/main/java/io/supertokens/storage/mysql/config/MySQLConfig.java +++ b/src/main/java/io/supertokens/storage/mysql/config/MySQLConfig.java @@ -373,6 +373,22 @@ public String getTotpUsedCodesTable() { return addPrefixToTableName("totp_used_codes"); } + public String getOAuthClientsTable() { + return addPrefixToTableName("oauth_clients"); + } + + public String getOAuthRevokeTable() { + return addPrefixToTableName("oauth_revoke"); + } + + public String getOAuthM2MTokensTable() { + return addPrefixToTableName("oauth_m2m_tokens"); + } + + public String getOAuthLogoutChallengesTable() { + return addPrefixToTableName("oauth_logout_challenges"); + } + private String addPrefixToTableName(String tableName) { return mysql_table_names_prefix + tableName; } diff --git a/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java index dfa0439..015334a 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java @@ -416,6 +416,36 @@ public static void createTablesIfNotExists(Start start, Connection con) throws S // index: update(con, TOTPQueries.getQueryToCreateUsedCodesExpiryTimeIndex(start), NO_OP_SETTER); } + + if (!doesTableExists(start, con, Config.getConfig(start).getOAuthClientsTable())) { + getInstance(start).addState(CREATING_NEW_TABLE, null); + update(con, OAuthQueries.getQueryToCreateOAuthClientTable(start), NO_OP_SETTER); + } + + if (!doesTableExists(start, con, Config.getConfig(start).getOAuthRevokeTable())) { + getInstance(start).addState(CREATING_NEW_TABLE, null); + update(con, OAuthQueries.getQueryToCreateOAuthRevokeTable(start), NO_OP_SETTER); + + // index + update(con, OAuthQueries.getQueryToCreateOAuthRevokeTimestampIndex(start), NO_OP_SETTER); + } + + if (!doesTableExists(start, con, Config.getConfig(start).getOAuthM2MTokensTable())) { + getInstance(start).addState(CREATING_NEW_TABLE, null); + update(con, OAuthQueries.getQueryToCreateOAuthM2MTokensTable(start), NO_OP_SETTER); + + // index + update(con, OAuthQueries.getQueryToCreateOAuthM2MTokenIatIndex(start), NO_OP_SETTER); + update(con, OAuthQueries.getQueryToCreateOAuthM2MTokenExpIndex(start), NO_OP_SETTER); + } + + if (!doesTableExists(start, con, Config.getConfig(start).getOAuthLogoutChallengesTable())) { + getInstance(start).addState(CREATING_NEW_TABLE, null); + update(con, OAuthQueries.getQueryToCreateOAuthLogoutChallengesTable(start), NO_OP_SETTER); + + // index + update(con, OAuthQueries.getQueryToCreateOAuthLogoutChallengesTimeCreatedIndex(start), NO_OP_SETTER); + } } @TestOnly diff --git a/src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java new file mode 100644 index 0000000..98d16f8 --- /dev/null +++ b/src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java @@ -0,0 +1,356 @@ +package io.supertokens.storage.mysql.queries; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import io.supertokens.pluginInterface.exceptions.StorageQueryException; +import io.supertokens.pluginInterface.multitenancy.AppIdentifier; +import io.supertokens.pluginInterface.oauth.OAuthLogoutChallenge; +import io.supertokens.storage.mysql.Start; +import io.supertokens.storage.mysql.config.Config; +import io.supertokens.storage.mysql.utils.Utils; + +import static io.supertokens.storage.mysql.QueryExecutorTemplate.execute; +import static io.supertokens.storage.mysql.QueryExecutorTemplate.update; + +public class OAuthQueries { + + public static String getQueryToCreateOAuthClientTable(Start start) { + String oAuth2ClientTable = Config.getConfig(start).getOAuthClientsTable(); + // @formatter:off + return "CREATE TABLE IF NOT EXISTS " + oAuth2ClientTable + " (" + + "app_id VARCHAR(64)," + + "client_id VARCHAR(128) NOT NULL," + + "is_client_credentials_only BOOLEAN NOT NULL," + + " PRIMARY KEY (app_id, client_id)," + + " FOREIGN KEY(app_id) REFERENCES " + Config.getConfig(start).getAppsTable() + "(app_id) ON DELETE CASCADE);"; + // @formatter:on + } + + public static String getQueryToCreateOAuthRevokeTable(Start start) { + String oAuth2RevokeTable = Config.getConfig(start).getOAuthRevokeTable(); + // @formatter:off + return "CREATE TABLE IF NOT EXISTS " + oAuth2RevokeTable + " (" + + "app_id VARCHAR(64) DEFAULT 'public'," + + "target_type VARCHAR(16) NOT NULL," + + "target_value VARCHAR(128) NOT NULL," + + "timestamp BIGINT UNSIGNED NOT NULL, " + + "exp BIGINT UNSIGNED NOT NULL," + + "PRIMARY KEY (app_id, target_type, target_value)," + + "FOREIGN KEY(app_id) " + + " REFERENCES " + Config.getConfig(start).getAppsTable() + "(app_id) ON DELETE CASCADE" + + ");"; + // @formatter:on + } + + public static String getQueryToCreateOAuthRevokeTimestampIndex(Start start) { + String oAuth2RevokeTable = Config.getConfig(start).getOAuthRevokeTable(); + return "CREATE INDEX oauth_revoke_timestamp_index ON " + + oAuth2RevokeTable + "(timestamp DESC, app_id DESC);"; + } + + public static String getQueryToCreateOAuthM2MTokensTable(Start start) { + String oAuth2M2MTokensTable = Config.getConfig(start).getOAuthM2MTokensTable(); + // @formatter:off + return "CREATE TABLE " + oAuth2M2MTokensTable + " (" + + "app_id VARCHAR(64) DEFAULT 'public'," + + "client_id VARCHAR(128) NOT NULL," + + "iat BIGINT UNSIGNED NOT NULL," + + "exp BIGINT UNSIGNED NOT NULL," + + "PRIMARY KEY (app_id, client_id, iat)," + + "FOREIGN KEY(app_id)" + + " REFERENCES " + Config.getConfig(start).getAppsTable() + "(app_id) ON DELETE CASCADE" + + ");"; + // @formatter:on + } + + public static String getQueryToCreateOAuthM2MTokenIatIndex(Start start) { + String oAuth2M2MTokensTable = Config.getConfig(start).getOAuthM2MTokensTable(); + return "CREATE INDEX oauth_m2m_token_iat_index ON " + + oAuth2M2MTokensTable + "(iat DESC, app_id DESC);"; + } + + public static String getQueryToCreateOAuthM2MTokenExpIndex(Start start) { + String oAuth2M2MTokensTable = Config.getConfig(start).getOAuthM2MTokensTable(); + return "CREATE INDEX oauth_m2m_token_exp_index ON " + + oAuth2M2MTokensTable + "(exp DESC, app_id DESC);"; + } + + public static String getQueryToCreateOAuthLogoutChallengesTable(Start start) { + String oAuth2LogoutChallengesTable = Config.getConfig(start).getOAuthLogoutChallengesTable(); + // @formatter:off + return "CREATE TABLE IF NOT EXISTS " + oAuth2LogoutChallengesTable + " (" + + "app_id VARCHAR(64) DEFAULT 'public'," + + "challenge VARCHAR(128) NOT NULL," + + "client_id VARCHAR(128) NOT NULL," + + "post_logout_redirect_uri VARCHAR(1024)," + + "session_handle VARCHAR(128)," + + "state VARCHAR(128)," + + "time_created BIGINT UNSIGNED NOT NULL," + + "PRIMARY KEY (app_id, challenge)," + + "FOREIGN KEY(app_id, client_id)" + + " REFERENCES " + Config.getConfig(start).getOAuthClientsTable() + "(app_id, client_id) ON DELETE CASCADE," + + "FOREIGN KEY(app_id)" + + " REFERENCES " + Config.getConfig(start).getAppsTable() + "(app_id) ON DELETE CASCADE" + + ");"; + // @formatter:on + } + + public static String getQueryToCreateOAuthLogoutChallengesTimeCreatedIndex(Start start) { + String oAuth2LogoutChallengesTable = Config.getConfig(start).getOAuthLogoutChallengesTable(); + return "CREATE INDEX oauth_logout_challenges_time_created_index ON " + + oAuth2LogoutChallengesTable + "(time_created ASC, app_id ASC);"; + } + + public static boolean isClientIdForAppId(Start start, String clientId, AppIdentifier appIdentifier) + throws SQLException, StorageQueryException { + String QUERY = "SELECT app_id FROM " + Config.getConfig(start).getOAuthClientsTable() + + " WHERE client_id = ? AND app_id = ?"; + + return execute(start, QUERY, pst -> { + pst.setString(1, clientId); + pst.setString(2, appIdentifier.getAppId()); + }, ResultSet::next); + } + + public static List listClientsForApp(Start start, AppIdentifier appIdentifier) + throws SQLException, StorageQueryException { + String QUERY = "SELECT client_id FROM " + Config.getConfig(start).getOAuthClientsTable() + + " WHERE app_id = ?"; + return execute(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + }, (result) -> { + List res = new ArrayList<>(); + while (result.next()) { + res.add(result.getString("client_id")); + } + return res; + }); + } + + public static void insertClientIdForAppId(Start start, AppIdentifier appIdentifier, String clientId, + boolean isClientCredentialsOnly) + throws SQLException, StorageQueryException { + String INSERT = "INSERT INTO " + Config.getConfig(start).getOAuthClientsTable() + + "(app_id, client_id, is_client_credentials_only) VALUES(?, ?, ?) " + + "ON DUPLICATE KEY UPDATE is_client_credentials_only = ?"; + update(start, INSERT, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, clientId); + pst.setBoolean(3, isClientCredentialsOnly); + pst.setBoolean(4, isClientCredentialsOnly); + }); + } + + public static boolean deleteClientIdForAppId(Start start, String clientId, AppIdentifier appIdentifier) + throws SQLException, StorageQueryException { + String DELETE = "DELETE FROM " + Config.getConfig(start).getOAuthClientsTable() + + " WHERE app_id = ? AND client_id = ?"; + int numberOfRow = update(start, DELETE, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, clientId); + }); + return numberOfRow > 0; + } + + public static void revoke(Start start, AppIdentifier appIdentifier, String targetType, String targetValue, long exp) + throws SQLException, StorageQueryException { + String INSERT = "INSERT INTO " + Config.getConfig(start).getOAuthRevokeTable() + + "(app_id, target_type, target_value, timestamp, exp) VALUES (?, ?, ?, ?, ?) " + + "ON DUPLICATE KEY UPDATE timestamp = ?, exp = ?"; + + long currentTime = System.currentTimeMillis() / 1000; + update(start, INSERT, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, targetType); + pst.setString(3, targetValue); + pst.setLong(4, currentTime); + pst.setLong(5, exp); + pst.setLong(6, currentTime); + pst.setLong(7, exp); + }); + } + + public static boolean isRevoked(Start start, AppIdentifier appIdentifier, String[] targetTypes, String[] targetValues, long issuedAt) + throws SQLException, StorageQueryException { + String QUERY = "SELECT app_id FROM " + Config.getConfig(start).getOAuthRevokeTable() + + " WHERE app_id = ? AND timestamp > ? AND ("; + + for (int i = 0; i < targetTypes.length; i++) { + QUERY += "(target_type = ? AND target_value = ?)"; + + if (i < targetTypes.length - 1) { + QUERY += " OR "; + } + } + + QUERY += ")"; + + return execute(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setLong(2, issuedAt); + + int index = 3; + for (int i = 0; i < targetTypes.length; i++) { + pst.setString(index, targetTypes[i]); + index++; + pst.setString(index, targetValues[i]); + index++; + } + }, ResultSet::next); + } + + public static int countTotalNumberOfClientsForApp(Start start, AppIdentifier appIdentifier, + boolean filterByClientCredentialsOnly) throws SQLException, StorageQueryException { + if (filterByClientCredentialsOnly) { + String QUERY = "SELECT COUNT(*) as c FROM " + Config.getConfig(start).getOAuthClientsTable() + + " WHERE app_id = ? AND is_client_credentials_only = ?"; + return execute(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setBoolean(2, true); + }, result -> { + if (result.next()) { + return result.getInt("c"); + } + return 0; + }); + } else { + String QUERY = "SELECT COUNT(*) as c FROM " + Config.getConfig(start).getOAuthClientsTable() + + " WHERE app_id = ?"; + return execute(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + }, result -> { + if (result.next()) { + return result.getInt("c"); + } + return 0; + }); + } + } + + public static int countTotalNumberOfM2MTokensAlive(Start start, AppIdentifier appIdentifier) + throws SQLException, StorageQueryException { + String QUERY = "SELECT COUNT(*) as c FROM " + Config.getConfig(start).getOAuthM2MTokensTable() + + " WHERE app_id = ? AND exp > ?"; + return execute(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setLong(2, System.currentTimeMillis()/1000); + }, result -> { + if (result.next()) { + return result.getInt("c"); + } + return 0; + }); + } + + public static int countTotalNumberOfM2MTokensCreatedSince(Start start, AppIdentifier appIdentifier, long since) + throws SQLException, StorageQueryException { + String QUERY = "SELECT COUNT(*) as c FROM " + Config.getConfig(start).getOAuthM2MTokensTable() + + " WHERE app_id = ? AND iat >= ?"; + return execute(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setLong(2, since / 1000); + }, result -> { + if (result.next()) { + return result.getInt("c"); + } + return 0; + }); + } + + public static void addM2MToken(Start start, AppIdentifier appIdentifier, String clientId, long iat, long exp) + throws SQLException, StorageQueryException { + String QUERY = "INSERT INTO " + Config.getConfig(start).getOAuthM2MTokensTable() + + " (app_id, client_id, iat, exp) VALUES (?, ?, ?, ?)"; + update(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, clientId); + pst.setLong(3, iat); + pst.setLong(4, exp); + }); + } + + public static void cleanUpExpiredAndRevokedTokens(Start start, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { + { + // delete expired M2M tokens + String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthM2MTokensTable() + + " WHERE app_id = ? AND exp < ?"; + + long timestamp = System.currentTimeMillis() / 1000 - 3600 * 24 * 31; // expired 31 days ago + update(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setLong(2, timestamp); + }); + } + + { + // delete expired revoked tokens + String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthRevokeTable() + + " WHERE app_id = ? AND exp < ?"; + + long timestamp = System.currentTimeMillis() / 1000 - 3600 * 24 * 31; // expired 31 days ago + update(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setLong(2, timestamp); + }); + } + } + + public static void addLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge, String clientId, + String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated) throws SQLException, StorageQueryException { + String QUERY = "INSERT INTO " + Config.getConfig(start).getOAuthLogoutChallengesTable() + + " (app_id, challenge, client_id, post_logout_redirect_uri, session_handle, state, time_created) VALUES (?, ?, ?, ?, ?, ?, ?)"; + update(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, challenge); + pst.setString(3, clientId); + pst.setString(4, postLogoutRedirectionUri); + pst.setString(5, sessionHandle); + pst.setString(6, state); + pst.setLong(7, timeCreated); + }); + } + + public static OAuthLogoutChallenge getLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge) throws SQLException, StorageQueryException { + String QUERY = "SELECT challenge, client_id, post_logout_redirect_uri, session_handle, state, time_created FROM " + + Config.getConfig(start).getOAuthLogoutChallengesTable() + + " WHERE app_id = ? AND challenge = ?"; + + return execute(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, challenge); + }, result -> { + if (result.next()) { + return new OAuthLogoutChallenge( + result.getString("challenge"), + result.getString("client_id"), + result.getString("post_logout_redirect_uri"), + result.getString("session_handle"), + result.getString("state"), + result.getLong("time_created") + ); + } + return null; + }); + } + + public static void deleteLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge) throws SQLException, StorageQueryException { + String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthLogoutChallengesTable() + + " WHERE app_id = ? AND challenge = ?"; + update(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setString(2, challenge); + }); + } + + public static void deleteLogoutChallengesBefore(Start start, AppIdentifier appIdentifier, long time) throws SQLException, StorageQueryException { + String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthLogoutChallengesTable() + + " WHERE app_id = ? AND time_created < ?"; + update(start, QUERY, pst -> { + pst.setString(1, appIdentifier.getAppId()); + pst.setLong(2, time); + }); + } +} From c8ce3df253d9c7e2bdce24c1471ea0b9fb6647fa Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Fri, 4 Oct 2024 10:22:33 +0530 Subject: [PATCH 2/3] fix: as per other plugins --- CHANGELOG.md | 5 + build.gradle | 2 +- pluginInterfaceSupported.json | 2 +- .../io/supertokens/storage/mysql/Start.java | 116 ++++++++++++------ .../storage/mysql/queries/GeneralQueries.java | 1 + .../storage/mysql/queries/OAuthQueries.java | 68 +++++----- 6 files changed, 119 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2e0b81..fd0db5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [7.2.0] - 2024-10-03 + +- Compatible with plugin interface version 6.3 +- Adds support for OAuthStorage + ## [7.1.3] - 2024-09-04 - Adds index on `last_active_time` for `user_last_active` table to improve the performance of MAU computation. diff --git a/build.gradle b/build.gradle index 4d9af05..9248813 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java-library' } -version = "7.1.3" +version = "7.2.0" repositories { mavenCentral() diff --git a/pluginInterfaceSupported.json b/pluginInterfaceSupported.json index 0dedee8..25f8238 100644 --- a/pluginInterfaceSupported.json +++ b/pluginInterfaceSupported.json @@ -1,6 +1,6 @@ { "_comment": "contains a list of plugin interfaces branch names that this core supports", "versions": [ - "6.2" + "6.3" ] } \ No newline at end of file diff --git a/src/main/java/io/supertokens/storage/mysql/Start.java b/src/main/java/io/supertokens/storage/mysql/Start.java index 4b9fe42..bf3e505 100644 --- a/src/main/java/io/supertokens/storage/mysql/Start.java +++ b/src/main/java/io/supertokens/storage/mysql/Start.java @@ -58,7 +58,10 @@ import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException; import io.supertokens.pluginInterface.multitenancy.sqlStorage.MultitenancySQLStorage; import io.supertokens.pluginInterface.oauth.OAuthLogoutChallenge; +import io.supertokens.pluginInterface.oauth.OAuthRevokeTargetType; import io.supertokens.pluginInterface.oauth.OAuthStorage; +import io.supertokens.pluginInterface.oauth.exception.DuplicateOAuthLogoutChallengeException; +import io.supertokens.pluginInterface.oauth.exception.OAuthClientNotFoundException; import io.supertokens.pluginInterface.passwordless.PasswordlessCode; import io.supertokens.pluginInterface.passwordless.PasswordlessDevice; import io.supertokens.pluginInterface.passwordless.exception.*; @@ -3037,159 +3040,192 @@ public int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(A } @Override - public boolean doesClientIdExistForApp(AppIdentifier appIdentifier, String clientId) + public boolean doesOAuthClientIdExist(AppIdentifier appIdentifier, String clientId) throws StorageQueryException { try { - return OAuthQueries.isClientIdForAppId(this, clientId, appIdentifier); + return OAuthQueries.doesOAuthClientIdExist(this, clientId, appIdentifier); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public void addOrUpdateClientForApp(AppIdentifier appIdentifier, String clientId, boolean isClientCredentialsOnly) - throws StorageQueryException { + public void addOrUpdateOauthClient(AppIdentifier appIdentifier, String clientId, boolean isClientCredentialsOnly) + throws StorageQueryException, TenantOrAppNotFoundException { try { - OAuthQueries.insertClientIdForAppId(this, appIdentifier, clientId, isClientCredentialsOnly); + OAuthQueries.addOrUpdateOauthClient(this, appIdentifier, clientId, isClientCredentialsOnly); } catch (SQLException e) { + if (e instanceof SQLIntegrityConstraintViolationException) { + MySQLConfig config = Config.getConfig(this); + String serverMessage = e.getMessage(); + + if (isForeignKeyConstraintError(serverMessage, config.getAppsTable(), "app_id")) { + throw new TenantOrAppNotFoundException(appIdentifier); + } + } throw new StorageQueryException(e); } } @Override - public boolean removeAppClientAssociation(AppIdentifier appIdentifier, String clientId) - throws StorageQueryException { + public boolean deleteOAuthClient(AppIdentifier appIdentifier, String clientId) throws StorageQueryException { try { - return OAuthQueries.deleteClientIdForAppId(this, clientId, appIdentifier); + return OAuthQueries.deleteOAuthClient(this, clientId, appIdentifier); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public List listClientsForApp(AppIdentifier appIdentifier) throws StorageQueryException { + public List listOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException { try { - return OAuthQueries.listClientsForApp(this, appIdentifier); + return OAuthQueries.listOAuthClients(this, appIdentifier); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public void revoke(AppIdentifier appIdentifier, String targetType, String targetValue, long exp) - throws StorageQueryException { + public void revokeOAuthTokensBasedOnTargetFields(AppIdentifier appIdentifier, OAuthRevokeTargetType targetType, String targetValue, long exp) + throws StorageQueryException, TenantOrAppNotFoundException { try { - OAuthQueries.revoke(this, appIdentifier, targetType, targetValue, exp); + OAuthQueries.revokeOAuthTokensBasedOnTargetFields(this, appIdentifier, targetType, targetValue, exp); } catch (SQLException e) { + if (e instanceof SQLIntegrityConstraintViolationException) { + MySQLConfig config = Config.getConfig(this); + String serverMessage = e.getMessage(); + + if (isForeignKeyConstraintError(serverMessage, config.getAppsTable(), "app_id")) { + throw new TenantOrAppNotFoundException(appIdentifier); + } + } throw new StorageQueryException(e); } + } @Override - public boolean isRevoked(AppIdentifier appIdentifier, String[] targetTypes, String[] targetValues, long issuedAt) + public boolean isOAuthTokenRevokedBasedOnTargetFields(AppIdentifier appIdentifier, OAuthRevokeTargetType[] targetTypes, String[] targetValues, long issuedAt) throws StorageQueryException { try { - return OAuthQueries.isRevoked(this, appIdentifier, targetTypes, targetValues, issuedAt); + return OAuthQueries.isOAuthTokenRevokedBasedOnTargetFields(this, appIdentifier, targetTypes, targetValues, issuedAt); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public void addM2MToken(AppIdentifier appIdentifier, String clientId, long iat, long exp) - throws StorageQueryException { + public void addOAuthM2MTokenForStats(AppIdentifier appIdentifier, String clientId, long iat, long exp) + throws StorageQueryException, OAuthClientNotFoundException { try { - OAuthQueries.addM2MToken(this, appIdentifier, clientId, iat, exp); + OAuthQueries.addOAuthM2MTokenForStats(this, appIdentifier, clientId, iat, exp); } catch (SQLException e) { + if (e instanceof SQLIntegrityConstraintViolationException) { + MySQLConfig config = Config.getConfig(this); + String serverMessage = e.getMessage(); + + if (isForeignKeyConstraintError(serverMessage, config.getOAuthClientsTable(), "client_id")) { + throw new OAuthClientNotFoundException(); + } + } throw new StorageQueryException(e); } } @Override - public void addLogoutChallenge(AppIdentifier appIdentifier, String challenge, String clientId, - String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated) throws StorageQueryException { + public void cleanUpExpiredAndRevokedOAuthTokensList() throws StorageQueryException { try { - OAuthQueries.addLogoutChallenge(this, appIdentifier, challenge, clientId, postLogoutRedirectionUri, sessionHandle, state, timeCreated); + OAuthQueries.cleanUpExpiredAndRevokedOAuthTokensList(this); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public OAuthLogoutChallenge getLogoutChallenge(AppIdentifier appIdentifier, String challenge) - throws StorageQueryException { + public void addOAuthLogoutChallenge(AppIdentifier appIdentifier, String challenge, String clientId, + String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated) + throws StorageQueryException, DuplicateOAuthLogoutChallengeException, OAuthClientNotFoundException { try { - return OAuthQueries.getLogoutChallenge(this, appIdentifier, challenge); + OAuthQueries.addOAuthLogoutChallenge(this, appIdentifier, challenge, clientId, postLogoutRedirectionUri, sessionHandle, state, timeCreated); } catch (SQLException e) { + if (e instanceof SQLIntegrityConstraintViolationException) { + MySQLConfig config = Config.getConfig(this); + String serverMessage = e.getMessage(); + if (isPrimaryKeyError(serverMessage, config.getOAuthLogoutChallengesTable())) { + throw new DuplicateOAuthLogoutChallengeException(); + } + else if (isForeignKeyConstraintError(serverMessage, config.getOAuthClientsTable(), "client_id")) { + throw new OAuthClientNotFoundException(); + } + } throw new StorageQueryException(e); } } @Override - public void deleteLogoutChallenge(AppIdentifier appIdentifier, String challenge) throws StorageQueryException { + public OAuthLogoutChallenge getOAuthLogoutChallenge(AppIdentifier appIdentifier, String challenge) throws StorageQueryException { try { - OAuthQueries.deleteLogoutChallenge(this, appIdentifier, challenge); + return OAuthQueries.getOAuthLogoutChallenge(this, appIdentifier, challenge); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public void deleteLogoutChallengesBefore(AppIdentifier appIdentifier, long time) throws StorageQueryException { + public void deleteOAuthLogoutChallenge(AppIdentifier appIdentifier, String challenge) throws StorageQueryException { try { - OAuthQueries.deleteLogoutChallengesBefore(this, appIdentifier, time); + OAuthQueries.deleteOAuthLogoutChallenge(this, appIdentifier, challenge); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public void cleanUpExpiredAndRevokedTokens(AppIdentifier appIdentifier) throws StorageQueryException { + public void deleteOAuthLogoutChallengesBefore(long time) throws StorageQueryException { try { - OAuthQueries.cleanUpExpiredAndRevokedTokens(this, appIdentifier); + OAuthQueries.deleteOAuthLogoutChallengesBefore(this, time); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public int countTotalNumberOfM2MTokensAlive(AppIdentifier appIdentifier) throws StorageQueryException { + public int countTotalNumberOfOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException { try { - return OAuthQueries.countTotalNumberOfM2MTokensAlive(this, appIdentifier); + return OAuthQueries.countTotalNumberOfClients(this, appIdentifier, false); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public int countTotalNumberOfM2MTokensCreatedSince(AppIdentifier appIdentifier, long since) + public int countTotalNumberOfClientCredentialsOnlyOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException { try { - return OAuthQueries.countTotalNumberOfM2MTokensCreatedSince(this, appIdentifier, since); + return OAuthQueries.countTotalNumberOfClients(this, appIdentifier, true); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public int countTotalNumberOfClientCredentialsOnlyClientsForApp(AppIdentifier appIdentifier) + public int countTotalNumberOfOAuthM2MTokensCreatedSince(AppIdentifier appIdentifier, long since) throws StorageQueryException { try { - return OAuthQueries.countTotalNumberOfClientsForApp(this, appIdentifier, true); + return OAuthQueries.countTotalNumberOfOAuthM2MTokensCreatedSince(this, appIdentifier, since); } catch (SQLException e) { throw new StorageQueryException(e); } } @Override - public int countTotalNumberOfClientsForApp(AppIdentifier appIdentifier) throws StorageQueryException { + public int countTotalNumberOfOAuthM2MTokensAlive(AppIdentifier appIdentifier) throws StorageQueryException { try { - return OAuthQueries.countTotalNumberOfClientsForApp(this, appIdentifier, false); + return OAuthQueries.countTotalNumberOfOAuthM2MTokensAlive(this, appIdentifier); } catch (SQLException e) { throw new StorageQueryException(e); - } } - + } public static boolean isEnabledForDeadlockTesting() { return enableForDeadlockTesting; diff --git a/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java index 015334a..e9f2059 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/GeneralQueries.java @@ -428,6 +428,7 @@ public static void createTablesIfNotExists(Start start, Connection con) throws S // index update(con, OAuthQueries.getQueryToCreateOAuthRevokeTimestampIndex(start), NO_OP_SETTER); + update(con, OAuthQueries.getQueryToCreateOAuthRevokeExpIndex(start), NO_OP_SETTER); } if (!doesTableExists(start, con, Config.getConfig(start).getOAuthM2MTokensTable())) { diff --git a/src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java index 98d16f8..bd72880 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/OAuthQueries.java @@ -8,6 +8,7 @@ import io.supertokens.pluginInterface.exceptions.StorageQueryException; import io.supertokens.pluginInterface.multitenancy.AppIdentifier; import io.supertokens.pluginInterface.oauth.OAuthLogoutChallenge; +import io.supertokens.pluginInterface.oauth.OAuthRevokeTargetType; import io.supertokens.storage.mysql.Start; import io.supertokens.storage.mysql.config.Config; import io.supertokens.storage.mysql.utils.Utils; @@ -51,6 +52,12 @@ public static String getQueryToCreateOAuthRevokeTimestampIndex(Start start) { + oAuth2RevokeTable + "(timestamp DESC, app_id DESC);"; } + public static String getQueryToCreateOAuthRevokeExpIndex(Start start) { + String oAuth2RevokeTable = Config.getConfig(start).getOAuthRevokeTable(); + return "CREATE INDEX oauth_revoke_exp_index ON " + + oAuth2RevokeTable + "(exp DESC);"; + } + public static String getQueryToCreateOAuthM2MTokensTable(Start start) { String oAuth2M2MTokensTable = Config.getConfig(start).getOAuthM2MTokensTable(); // @formatter:off @@ -60,8 +67,8 @@ public static String getQueryToCreateOAuthM2MTokensTable(Start start) { + "iat BIGINT UNSIGNED NOT NULL," + "exp BIGINT UNSIGNED NOT NULL," + "PRIMARY KEY (app_id, client_id, iat)," - + "FOREIGN KEY(app_id)" - + " REFERENCES " + Config.getConfig(start).getAppsTable() + "(app_id) ON DELETE CASCADE" + + "FOREIGN KEY(app_id, client_id)" + + " REFERENCES " + Config.getConfig(start).getOAuthClientsTable() + "(app_id, client_id) ON DELETE CASCADE" + ");"; // @formatter:on } @@ -75,7 +82,7 @@ public static String getQueryToCreateOAuthM2MTokenIatIndex(Start start) { public static String getQueryToCreateOAuthM2MTokenExpIndex(Start start) { String oAuth2M2MTokensTable = Config.getConfig(start).getOAuthM2MTokensTable(); return "CREATE INDEX oauth_m2m_token_exp_index ON " - + oAuth2M2MTokensTable + "(exp DESC, app_id DESC);"; + + oAuth2M2MTokensTable + "(exp DESC);"; } public static String getQueryToCreateOAuthLogoutChallengesTable(Start start) { @@ -91,9 +98,7 @@ public static String getQueryToCreateOAuthLogoutChallengesTable(Start start) { + "time_created BIGINT UNSIGNED NOT NULL," + "PRIMARY KEY (app_id, challenge)," + "FOREIGN KEY(app_id, client_id)" - + " REFERENCES " + Config.getConfig(start).getOAuthClientsTable() + "(app_id, client_id) ON DELETE CASCADE," - + "FOREIGN KEY(app_id)" - + " REFERENCES " + Config.getConfig(start).getAppsTable() + "(app_id) ON DELETE CASCADE" + + " REFERENCES " + Config.getConfig(start).getOAuthClientsTable() + "(app_id, client_id) ON DELETE CASCADE" + ");"; // @formatter:on } @@ -104,7 +109,7 @@ public static String getQueryToCreateOAuthLogoutChallengesTimeCreatedIndex(Start + oAuth2LogoutChallengesTable + "(time_created ASC, app_id ASC);"; } - public static boolean isClientIdForAppId(Start start, String clientId, AppIdentifier appIdentifier) + public static boolean doesOAuthClientIdExist(Start start, String clientId, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { String QUERY = "SELECT app_id FROM " + Config.getConfig(start).getOAuthClientsTable() + " WHERE client_id = ? AND app_id = ?"; @@ -115,7 +120,7 @@ public static boolean isClientIdForAppId(Start start, String clientId, AppIdenti }, ResultSet::next); } - public static List listClientsForApp(Start start, AppIdentifier appIdentifier) + public static List listOAuthClients(Start start, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { String QUERY = "SELECT client_id FROM " + Config.getConfig(start).getOAuthClientsTable() + " WHERE app_id = ?"; @@ -130,7 +135,7 @@ public static List listClientsForApp(Start start, AppIdentifier appIdent }); } - public static void insertClientIdForAppId(Start start, AppIdentifier appIdentifier, String clientId, + public static void addOrUpdateOauthClient(Start start, AppIdentifier appIdentifier, String clientId, boolean isClientCredentialsOnly) throws SQLException, StorageQueryException { String INSERT = "INSERT INTO " + Config.getConfig(start).getOAuthClientsTable() @@ -144,7 +149,7 @@ public static void insertClientIdForAppId(Start start, AppIdentifier appIdentifi }); } - public static boolean deleteClientIdForAppId(Start start, String clientId, AppIdentifier appIdentifier) + public static boolean deleteOAuthClient(Start start, String clientId, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { String DELETE = "DELETE FROM " + Config.getConfig(start).getOAuthClientsTable() + " WHERE app_id = ? AND client_id = ?"; @@ -155,7 +160,7 @@ public static boolean deleteClientIdForAppId(Start start, String clientId, AppId return numberOfRow > 0; } - public static void revoke(Start start, AppIdentifier appIdentifier, String targetType, String targetValue, long exp) + public static void revokeOAuthTokensBasedOnTargetFields(Start start, AppIdentifier appIdentifier, OAuthRevokeTargetType targetType, String targetValue, long exp) throws SQLException, StorageQueryException { String INSERT = "INSERT INTO " + Config.getConfig(start).getOAuthRevokeTable() + "(app_id, target_type, target_value, timestamp, exp) VALUES (?, ?, ?, ?, ?) " @@ -164,7 +169,7 @@ public static void revoke(Start start, AppIdentifier appIdentifier, String targe long currentTime = System.currentTimeMillis() / 1000; update(start, INSERT, pst -> { pst.setString(1, appIdentifier.getAppId()); - pst.setString(2, targetType); + pst.setString(2, targetType.getValue()); pst.setString(3, targetValue); pst.setLong(4, currentTime); pst.setLong(5, exp); @@ -173,7 +178,7 @@ public static void revoke(Start start, AppIdentifier appIdentifier, String targe }); } - public static boolean isRevoked(Start start, AppIdentifier appIdentifier, String[] targetTypes, String[] targetValues, long issuedAt) + public static boolean isOAuthTokenRevokedBasedOnTargetFields(Start start, AppIdentifier appIdentifier, OAuthRevokeTargetType[] targetTypes, String[] targetValues, long issuedAt) throws SQLException, StorageQueryException { String QUERY = "SELECT app_id FROM " + Config.getConfig(start).getOAuthRevokeTable() + " WHERE app_id = ? AND timestamp > ? AND ("; @@ -194,7 +199,7 @@ public static boolean isRevoked(Start start, AppIdentifier appIdentifier, String int index = 3; for (int i = 0; i < targetTypes.length; i++) { - pst.setString(index, targetTypes[i]); + pst.setString(index, targetTypes[i].getValue()); index++; pst.setString(index, targetValues[i]); index++; @@ -202,7 +207,7 @@ public static boolean isRevoked(Start start, AppIdentifier appIdentifier, String }, ResultSet::next); } - public static int countTotalNumberOfClientsForApp(Start start, AppIdentifier appIdentifier, + public static int countTotalNumberOfClients(Start start, AppIdentifier appIdentifier, boolean filterByClientCredentialsOnly) throws SQLException, StorageQueryException { if (filterByClientCredentialsOnly) { String QUERY = "SELECT COUNT(*) as c FROM " + Config.getConfig(start).getOAuthClientsTable() + @@ -230,7 +235,7 @@ public static int countTotalNumberOfClientsForApp(Start start, AppIdentifier app } } - public static int countTotalNumberOfM2MTokensAlive(Start start, AppIdentifier appIdentifier) + public static int countTotalNumberOfOAuthM2MTokensAlive(Start start, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { String QUERY = "SELECT COUNT(*) as c FROM " + Config.getConfig(start).getOAuthM2MTokensTable() + " WHERE app_id = ? AND exp > ?"; @@ -245,7 +250,7 @@ public static int countTotalNumberOfM2MTokensAlive(Start start, AppIdentifier ap }); } - public static int countTotalNumberOfM2MTokensCreatedSince(Start start, AppIdentifier appIdentifier, long since) + public static int countTotalNumberOfOAuthM2MTokensCreatedSince(Start start, AppIdentifier appIdentifier, long since) throws SQLException, StorageQueryException { String QUERY = "SELECT COUNT(*) as c FROM " + Config.getConfig(start).getOAuthM2MTokensTable() + " WHERE app_id = ? AND iat >= ?"; @@ -260,10 +265,10 @@ public static int countTotalNumberOfM2MTokensCreatedSince(Start start, AppIdenti }); } - public static void addM2MToken(Start start, AppIdentifier appIdentifier, String clientId, long iat, long exp) + public static void addOAuthM2MTokenForStats(Start start, AppIdentifier appIdentifier, String clientId, long iat, long exp) throws SQLException, StorageQueryException { String QUERY = "INSERT INTO " + Config.getConfig(start).getOAuthM2MTokensTable() + - " (app_id, client_id, iat, exp) VALUES (?, ?, ?, ?)"; + " (app_id, client_id, iat, exp) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE exp=exp"; update(start, QUERY, pst -> { pst.setString(1, appIdentifier.getAppId()); pst.setString(2, clientId); @@ -272,33 +277,31 @@ public static void addM2MToken(Start start, AppIdentifier appIdentifier, String }); } - public static void cleanUpExpiredAndRevokedTokens(Start start, AppIdentifier appIdentifier) throws SQLException, StorageQueryException { + public static void cleanUpExpiredAndRevokedOAuthTokensList(Start start) throws SQLException, StorageQueryException { { // delete expired M2M tokens String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthM2MTokensTable() + - " WHERE app_id = ? AND exp < ?"; + " WHERE exp < ?"; long timestamp = System.currentTimeMillis() / 1000 - 3600 * 24 * 31; // expired 31 days ago update(start, QUERY, pst -> { - pst.setString(1, appIdentifier.getAppId()); - pst.setLong(2, timestamp); + pst.setLong(1, timestamp); }); } { // delete expired revoked tokens String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthRevokeTable() + - " WHERE app_id = ? AND exp < ?"; + " WHERE exp < ?"; long timestamp = System.currentTimeMillis() / 1000 - 3600 * 24 * 31; // expired 31 days ago update(start, QUERY, pst -> { - pst.setString(1, appIdentifier.getAppId()); - pst.setLong(2, timestamp); + pst.setLong(1, timestamp); }); } } - public static void addLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge, String clientId, + public static void addOAuthLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge, String clientId, String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated) throws SQLException, StorageQueryException { String QUERY = "INSERT INTO " + Config.getConfig(start).getOAuthLogoutChallengesTable() + " (app_id, challenge, client_id, post_logout_redirect_uri, session_handle, state, time_created) VALUES (?, ?, ?, ?, ?, ?, ?)"; @@ -313,7 +316,7 @@ public static void addLogoutChallenge(Start start, AppIdentifier appIdentifier, }); } - public static OAuthLogoutChallenge getLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge) throws SQLException, StorageQueryException { + public static OAuthLogoutChallenge getOAuthLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge) throws SQLException, StorageQueryException { String QUERY = "SELECT challenge, client_id, post_logout_redirect_uri, session_handle, state, time_created FROM " + Config.getConfig(start).getOAuthLogoutChallengesTable() + " WHERE app_id = ? AND challenge = ?"; @@ -336,7 +339,7 @@ public static OAuthLogoutChallenge getLogoutChallenge(Start start, AppIdentifier }); } - public static void deleteLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge) throws SQLException, StorageQueryException { + public static void deleteOAuthLogoutChallenge(Start start, AppIdentifier appIdentifier, String challenge) throws SQLException, StorageQueryException { String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthLogoutChallengesTable() + " WHERE app_id = ? AND challenge = ?"; update(start, QUERY, pst -> { @@ -345,12 +348,11 @@ public static void deleteLogoutChallenge(Start start, AppIdentifier appIdentifie }); } - public static void deleteLogoutChallengesBefore(Start start, AppIdentifier appIdentifier, long time) throws SQLException, StorageQueryException { + public static void deleteOAuthLogoutChallengesBefore(Start start, long time) throws SQLException, StorageQueryException { String QUERY = "DELETE FROM " + Config.getConfig(start).getOAuthLogoutChallengesTable() + - " WHERE app_id = ? AND time_created < ?"; + " WHERE time_created < ?"; update(start, QUERY, pst -> { - pst.setString(1, appIdentifier.getAppId()); - pst.setLong(2, time); + pst.setLong(1, time); }); } } From 7f5a397195efb532e2cafa489a14916346ff9078 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Fri, 4 Oct 2024 10:25:15 +0530 Subject: [PATCH 3/3] fix: as per other plugins --- src/main/java/io/supertokens/storage/mysql/Start.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/supertokens/storage/mysql/Start.java b/src/main/java/io/supertokens/storage/mysql/Start.java index bf3e505..c0b4ddd 100644 --- a/src/main/java/io/supertokens/storage/mysql/Start.java +++ b/src/main/java/io/supertokens/storage/mysql/Start.java @@ -842,6 +842,8 @@ public void addInfoToNonAuthRecipesBasedOnUserId(TenantIdentifier tenantIdentifi } } else if (className.equals(JWTRecipeStorage.class.getName())) { /* Since JWT recipe tables do not store userId we do not add any data to them */ + } else if (className.equals(OAuthStorage.class.getName())) { + /* Since OAuth recipe tables do not store userId we do not add any data to them */ } else if (className.equals(ActiveUsersStorage.class.getName())) { try { ActiveUsersQueries.updateUserLastActive(this, tenantIdentifier.toAppIdentifier(), userId);