Skip to content

Commit 72838e3

Browse files
authored
Merge pull request #231 from supertokens/feat/oauth/allow-list
feat: oauth allow list
2 parents cff42cb + ffa0196 commit 72838e3

5 files changed

Lines changed: 397 additions & 214 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,21 @@ CREATE TABLE IF NOT EXISTS oauth_clients (
2323
FOREIGN KEY(app_id) REFERENCES apps(app_id) ON DELETE CASCADE
2424
);
2525

26-
CREATE TABLE IF NOT EXISTS oauth_revoke (
26+
CREATE TABLE IF NOT EXISTS oauth_sessions (
27+
gid VARCHAR(255),
2728
app_id VARCHAR(64) DEFAULT 'public',
28-
target_type VARCHAR(16) NOT NULL,
29-
target_value VARCHAR(128) NOT NULL,
30-
timestamp BIGINT NOT NULL,
29+
client_id VARCHAR(255) NOT NULL,
30+
session_handle VARCHAR(128),
31+
external_refresh_token VARCHAR(255) UNIQUE,
32+
internal_refresh_token VARCHAR(255) UNIQUE,
33+
jti TEXT NOT NULL,
3134
exp BIGINT NOT NULL,
32-
PRIMARY KEY (app_id, target_type, target_value),
33-
FOREIGN KEY(app_id) REFERENCES apps(app_id) ON DELETE CASCADE
35+
PRIMARY KEY (gid),
36+
FOREIGN KEY(app_id, client_id) REFERENCES oauth_clients(app_id, client_id) ON DELETE CASCADE
3437
);
3538

36-
CREATE INDEX IF NOT EXISTS oauth_revoke_timestamp_index ON oauth_revoke(timestamp DESC, app_id DESC);
37-
CREATE INDEX IF NOT EXISTS oauth_revoke_exp_index ON oauth_revoke(exp DESC);
39+
CREATE INDEX IF NOT EXISTS oauth_session_exp_index ON oauth_sessions(exp DESC);
40+
CREATE INDEX IF NOT EXISTS oauth_session_external_refresh_token_index ON oauth_sessions(app_id, external_refresh_token DESC);
3841

3942
CREATE TABLE IF NOT EXISTS oauth_m2m_tokens (
4043
app_id VARCHAR(64) DEFAULT 'public',

src/main/java/io/supertokens/storage/postgresql/Start.java

Lines changed: 142 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,17 @@
4848
import io.supertokens.pluginInterface.jwt.JWTSigningKeyInfo;
4949
import io.supertokens.pluginInterface.jwt.exceptions.DuplicateKeyIdException;
5050
import io.supertokens.pluginInterface.jwt.sqlstorage.JWTRecipeSQLStorage;
51-
import io.supertokens.pluginInterface.multitenancy.*;
51+
import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
52+
import io.supertokens.pluginInterface.multitenancy.MultitenancyStorage;
53+
import io.supertokens.pluginInterface.multitenancy.TenantConfig;
54+
import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;
5255
import io.supertokens.pluginInterface.multitenancy.exceptions.DuplicateClientTypeException;
5356
import io.supertokens.pluginInterface.multitenancy.exceptions.DuplicateTenantException;
5457
import io.supertokens.pluginInterface.multitenancy.exceptions.DuplicateThirdPartyIdException;
5558
import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException;
5659
import io.supertokens.pluginInterface.multitenancy.sqlStorage.MultitenancySQLStorage;
60+
import io.supertokens.pluginInterface.oauth.OAuthClient;
5761
import io.supertokens.pluginInterface.oauth.OAuthLogoutChallenge;
58-
import io.supertokens.pluginInterface.oauth.OAuthRevokeTargetType;
5962
import io.supertokens.pluginInterface.oauth.OAuthStorage;
6063
import io.supertokens.pluginInterface.oauth.exception.DuplicateOAuthLogoutChallengeException;
6164
import io.supertokens.pluginInterface.oauth.exception.OAuthClientNotFoundException;
@@ -103,7 +106,10 @@
103106
import java.sql.Connection;
104107
import java.sql.SQLException;
105108
import java.sql.SQLTransactionRollbackException;
106-
import java.util.*;
109+
import java.util.ArrayList;
110+
import java.util.HashMap;
111+
import java.util.List;
112+
import java.util.Set;
107113

108114
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
109115

@@ -3095,76 +3101,107 @@ public int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(A
30953101
}
30963102
}
30973103

3104+
30983105
@Override
3099-
public boolean doesOAuthClientIdExist(AppIdentifier appIdentifier, String clientId)
3100-
throws StorageQueryException {
3106+
public boolean deleteOAuthClient(AppIdentifier appIdentifier, String clientId) throws StorageQueryException {
31013107
try {
3102-
return OAuthQueries.doesOAuthClientIdExist(this, clientId, appIdentifier);
3108+
return OAuthQueries.deleteOAuthClient(this, clientId, appIdentifier);
31033109
} catch (SQLException e) {
31043110
throw new StorageQueryException(e);
31053111
}
31063112
}
31073113

3114+
3115+
3116+
@TestOnly
3117+
public int getDbActivityCount(String dbname) throws SQLException, StorageQueryException {
3118+
String QUERY = "SELECT COUNT(*) as c FROM pg_stat_activity WHERE datname = ?;";
3119+
return execute(this, QUERY, pst -> {
3120+
pst.setString(1, dbname);
3121+
}, result -> {
3122+
if (result.next()) {
3123+
return result.getInt("c");
3124+
}
3125+
return -1;
3126+
});
3127+
}
3128+
31083129
@Override
3109-
public void addOrUpdateOauthClient(AppIdentifier appIdentifier, String clientId, boolean isClientCredentialsOnly)
3130+
public OAuthClient getOAuthClientById(AppIdentifier appIdentifier, String clientId)
3131+
throws StorageQueryException, OAuthClientNotFoundException {
3132+
try {
3133+
OAuthClient client = OAuthQueries.getOAuthClientById(this, clientId, appIdentifier);
3134+
if (client == null) {
3135+
throw new OAuthClientNotFoundException();
3136+
}
3137+
return client;
3138+
} catch (SQLException e) {
3139+
throw new StorageQueryException(e);
3140+
}
3141+
}
3142+
3143+
@Override
3144+
public void addOrUpdateOauthClient(AppIdentifier appIdentifier, String clientId, String clientSecret, boolean isClientCredentialsOnly, boolean enableRefreshTokenRotation)
31103145
throws StorageQueryException, TenantOrAppNotFoundException {
31113146
try {
3112-
OAuthQueries.addOrUpdateOauthClient(this, appIdentifier, clientId, isClientCredentialsOnly);
3147+
OAuthQueries.addOrUpdateOauthClient(this, appIdentifier, clientId, clientSecret, isClientCredentialsOnly, enableRefreshTokenRotation);
31133148
} catch (SQLException e) {
3149+
ServerErrorMessage errorMessage = ((PSQLException) e).getServerErrorMessage();
31143150
PostgreSQLConfig config = Config.getConfig(this);
3115-
if (e instanceof PSQLException) {
3116-
ServerErrorMessage serverMessage = ((PSQLException) e).getServerErrorMessage();
31173151

3118-
if (isForeignKeyConstraintError(serverMessage, config.getOAuthClientsTable(), "app_id")) {
3119-
throw new TenantOrAppNotFoundException(appIdentifier);
3120-
}
3152+
if (isForeignKeyConstraintError(
3153+
errorMessage,
3154+
config.getOAuthClientsTable(),
3155+
"app_id")) {
3156+
throw new TenantOrAppNotFoundException(appIdentifier);
31213157
}
31223158
throw new StorageQueryException(e);
31233159
}
31243160
}
31253161

31263162
@Override
3127-
public boolean deleteOAuthClient(AppIdentifier appIdentifier, String clientId) throws StorageQueryException {
3163+
public List<OAuthClient> getOAuthClients(AppIdentifier appIdentifier, List<String> clientIds) throws StorageQueryException {
31283164
try {
3129-
return OAuthQueries.deleteOAuthClient(this, clientId, appIdentifier);
3165+
return OAuthQueries.getOAuthClients(this, appIdentifier, clientIds);
31303166
} catch (SQLException e) {
31313167
throw new StorageQueryException(e);
31323168
}
31333169
}
31343170

31353171
@Override
3136-
public List<String> listOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException {
3172+
public boolean revokeOAuthTokenByGID(AppIdentifier appIdentifier, String gid) throws StorageQueryException {
31373173
try {
3138-
return OAuthQueries.listOAuthClients(this, appIdentifier);
3174+
return OAuthQueries.deleteOAuthSessionByGID(this, appIdentifier, gid);
31393175
} catch (SQLException e) {
31403176
throw new StorageQueryException(e);
31413177
}
31423178
}
31433179

31443180
@Override
3145-
public void revokeOAuthTokensBasedOnTargetFields(AppIdentifier appIdentifier, OAuthRevokeTargetType targetType, String targetValue, long exp)
3146-
throws StorageQueryException, TenantOrAppNotFoundException {
3181+
public boolean revokeOAuthTokenByClientId(AppIdentifier appIdentifier, String clientId)
3182+
throws StorageQueryException {
31473183
try {
3148-
OAuthQueries.revokeOAuthTokensBasedOnTargetFields(this, appIdentifier, targetType, targetValue, exp);
3184+
return OAuthQueries.deleteOAuthSessionByClientId(this, appIdentifier, clientId);
31493185
} catch (SQLException e) {
3150-
PostgreSQLConfig config = Config.getConfig(this);
3151-
if (e instanceof PSQLException) {
3152-
ServerErrorMessage serverMessage = ((PSQLException) e).getServerErrorMessage();
3186+
throw new StorageQueryException(e);
3187+
}
3188+
}
31533189

3154-
if (isForeignKeyConstraintError(serverMessage, config.getOAuthRevokeTable(), "app_id")) {
3155-
throw new TenantOrAppNotFoundException(appIdentifier);
3156-
}
3157-
}
3190+
@Override
3191+
public boolean revokeOAuthTokenByJTI(AppIdentifier appIdentifier, String gid, String jti)
3192+
throws StorageQueryException {
3193+
try {
3194+
return OAuthQueries.deleteJTIFromOAuthSession(this, appIdentifier, gid, jti);
3195+
} catch (SQLException e) {
31583196
throw new StorageQueryException(e);
31593197
}
3160-
31613198
}
31623199

31633200
@Override
3164-
public boolean isOAuthTokenRevokedBasedOnTargetFields(AppIdentifier appIdentifier, OAuthRevokeTargetType[] targetTypes, String[] targetValues, long issuedAt)
3201+
public boolean revokeOAuthTokenBySessionHandle(AppIdentifier appIdentifier, String sessionHandle)
31653202
throws StorageQueryException {
31663203
try {
3167-
return OAuthQueries.isOAuthTokenRevokedBasedOnTargetFields(this, appIdentifier, targetTypes, targetValues, issuedAt);
3204+
return OAuthQueries.deleteOAuthSessionBySessionHandle(this, appIdentifier, sessionHandle);
31683205
} catch (SQLException e) {
31693206
throw new StorageQueryException(e);
31703207
}
@@ -3176,43 +3213,45 @@ public void addOAuthM2MTokenForStats(AppIdentifier appIdentifier, String clientI
31763213
try {
31773214
OAuthQueries.addOAuthM2MTokenForStats(this, appIdentifier, clientId, iat, exp);
31783215
} catch (SQLException e) {
3216+
ServerErrorMessage errorMessage = ((PSQLException) e).getServerErrorMessage();
31793217
PostgreSQLConfig config = Config.getConfig(this);
3180-
if (e instanceof PSQLException) {
3181-
ServerErrorMessage serverMessage = ((PSQLException) e).getServerErrorMessage();
31823218

3183-
if (isForeignKeyConstraintError(serverMessage, config.getOAuthM2MTokensTable(), "client_id")) {
3184-
throw new OAuthClientNotFoundException();
3185-
}
3219+
if (isForeignKeyConstraintError(
3220+
errorMessage,
3221+
config.getOAuthM2MTokensTable(),
3222+
"client_id")) {
3223+
throw new OAuthClientNotFoundException();
31863224
}
31873225
throw new StorageQueryException(e);
31883226
}
31893227
}
31903228

31913229
@Override
3192-
public void cleanUpExpiredAndRevokedOAuthTokensList() throws StorageQueryException {
3230+
public void deleteExpiredOAuthM2MTokens(long exp) throws StorageQueryException {
31933231
try {
3194-
OAuthQueries.cleanUpExpiredAndRevokedOAuthTokensList(this);
3232+
OAuthQueries.deleteExpiredOAuthM2MTokens(this, exp);
31953233
} catch (SQLException e) {
31963234
throw new StorageQueryException(e);
31973235
}
31983236
}
31993237

32003238
@Override
32013239
public void addOAuthLogoutChallenge(AppIdentifier appIdentifier, String challenge, String clientId,
3202-
String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated)
3240+
String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated)
32033241
throws StorageQueryException, DuplicateOAuthLogoutChallengeException, OAuthClientNotFoundException {
32043242
try {
32053243
OAuthQueries.addOAuthLogoutChallenge(this, appIdentifier, challenge, clientId, postLogoutRedirectionUri, sessionHandle, state, timeCreated);
32063244
} catch (SQLException e) {
3245+
ServerErrorMessage errorMessage = ((PSQLException) e).getServerErrorMessage();
32073246
PostgreSQLConfig config = Config.getConfig(this);
3208-
if (e instanceof PSQLException) {
3209-
ServerErrorMessage serverMessage = ((PSQLException) e).getServerErrorMessage();
32103247

3211-
if (isPrimaryKeyError(serverMessage, config.getOAuthLogoutChallengesTable())) {
3212-
throw new DuplicateOAuthLogoutChallengeException();
3213-
} else if (isForeignKeyConstraintError(serverMessage, config.getOAuthLogoutChallengesTable(), "client_id")) {
3214-
throw new OAuthClientNotFoundException();
3215-
}
3248+
if (isPrimaryKeyError(errorMessage, config.getOAuthLogoutChallengesTable())) {
3249+
throw new DuplicateOAuthLogoutChallengeException();
3250+
} else if (isForeignKeyConstraintError(
3251+
errorMessage,
3252+
config.getOAuthLogoutChallengesTable(),
3253+
"client_id")) {
3254+
throw new OAuthClientNotFoundException();
32163255
}
32173256
throw new StorageQueryException(e);
32183257
}
@@ -3245,6 +3284,47 @@ public void deleteOAuthLogoutChallengesBefore(long time) throws StorageQueryExce
32453284
}
32463285
}
32473286

3287+
@Override
3288+
public void createOrUpdateOAuthSession(AppIdentifier appIdentifier, String gid, String clientId,
3289+
String externalRefreshToken, String internalRefreshToken,
3290+
String sessionHandle, List<String> jtis, long exp)
3291+
throws StorageQueryException, OAuthClientNotFoundException {
3292+
try {
3293+
OAuthQueries.createOrUpdateOAuthSession(this, appIdentifier, gid, clientId, externalRefreshToken,
3294+
internalRefreshToken, sessionHandle, jtis, exp);
3295+
} catch (SQLException e) {
3296+
ServerErrorMessage errorMessage = ((PSQLException) e).getServerErrorMessage();
3297+
PostgreSQLConfig config = Config.getConfig(this);
3298+
3299+
if (isForeignKeyConstraintError(
3300+
errorMessage,
3301+
config.getOAuthSessionsTable(),
3302+
"client_id")) {
3303+
throw new OAuthClientNotFoundException();
3304+
}
3305+
throw new StorageQueryException(e);
3306+
}
3307+
}
3308+
3309+
@Override
3310+
public String getRefreshTokenMapping(AppIdentifier appIdentifier, String externalRefreshToken)
3311+
throws StorageQueryException {
3312+
try {
3313+
return OAuthQueries.getRefreshTokenMapping(this, appIdentifier, externalRefreshToken);
3314+
} catch (SQLException e) {
3315+
throw new StorageQueryException(e);
3316+
}
3317+
}
3318+
3319+
@Override
3320+
public void deleteExpiredOAuthSessions(long exp) throws StorageQueryException {
3321+
try {
3322+
OAuthQueries.deleteExpiredOAuthSessions(this, exp);
3323+
} catch (SQLException e) {
3324+
throw new StorageQueryException(e);
3325+
}
3326+
}
3327+
32483328
@Override
32493329
public int countTotalNumberOfOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException {
32503330
try {
@@ -3283,16 +3363,22 @@ public int countTotalNumberOfOAuthM2MTokensAlive(AppIdentifier appIdentifier) th
32833363
}
32843364
}
32853365

3286-
@TestOnly
3287-
public int getDbActivityCount(String dbname) throws SQLException, StorageQueryException {
3288-
String QUERY = "SELECT COUNT(*) as c FROM pg_stat_activity WHERE datname = ?;";
3289-
return execute(this, QUERY, pst -> {
3290-
pst.setString(1, dbname);
3291-
}, result -> {
3292-
if (result.next()) {
3293-
return result.getInt("c");
3294-
}
3295-
return -1;
3296-
});
3366+
@Override
3367+
public boolean isOAuthTokenRevokedByGID(AppIdentifier appIdentifier, String gid) throws StorageQueryException {
3368+
try {
3369+
return !OAuthQueries.isOAuthSessionExistsByGID(this, appIdentifier, gid);
3370+
} catch (SQLException e) {
3371+
throw new StorageQueryException(e);
3372+
}
3373+
}
3374+
3375+
@Override
3376+
public boolean isOAuthTokenRevokedByJTI(AppIdentifier appIdentifier, String gid, String jti)
3377+
throws StorageQueryException {
3378+
try {
3379+
return !OAuthQueries.isOAuthSessionExistsByJTI(this, appIdentifier, gid, jti);
3380+
} catch (SQLException e) {
3381+
throw new StorageQueryException(e);
3382+
}
32973383
}
32983384
}

0 commit comments

Comments
 (0)