From a22c1320d078786320f1c688685e05453f7ca91b Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Fri, 4 Oct 2024 10:54:20 +0530 Subject: [PATCH] feat: OAuth provider support (#164) * fix: tenant config * fix: thirdparty providers * fix: cleanup * fix: providers non null * fix: changelog * fix: pr comments * reformats code * adds function to check if client exists for the app * feat: oauth - WIP (#158) * feat: oauth recipe id, sqlstoreage and response type * fix: review fixes * fix: review fixes * fix: review fix - renamed exception * feat: OAuthStorage isClientAlreadyExists * feat: delete from oauth table * fix: removing unused/unnecessary method, change return type of other * fix: merge with latest (#159) * adding dev-v6.2.0 tag to this commit to ensure building * adding dev-v6.2.0 tag to this commit to ensure building * fix: listClientsForApp * fix: oauth plugin interface updates (#160) * fix: revoke * fix: pr comments * fix: oauth storage * fix: update * fix: add m2m token * fix: revoke and cleanup * fix: logout (#161) * fix: logout * fix: session revoke in logout * fix: version and cleanup * fix: rename / refactor * fix: changelog * fix: changelog * fix: constraints --------- Co-authored-by: rishabhpoddar Co-authored-by: Tamas Soltesz --- CHANGELOG.md | 4 ++ build.gradle | 2 +- .../pluginInterface/RECIPE_ID.java | 2 +- .../pluginInterface/StorageUtils.java | 9 +++ .../oauth/OAuthLogoutChallenge.java | 19 ++++++ .../oauth/OAuthRevokeTargetType.java | 18 ++++++ .../pluginInterface/oauth/OAuthStorage.java | 63 +++++++++++++++++++ ...uplicateOAuthLogoutChallengeException.java | 21 +++++++ .../OAuthClientNotFoundException.java | 24 +++++++ 9 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/supertokens/pluginInterface/oauth/OAuthLogoutChallenge.java create mode 100644 src/main/java/io/supertokens/pluginInterface/oauth/OAuthRevokeTargetType.java create mode 100644 src/main/java/io/supertokens/pluginInterface/oauth/OAuthStorage.java create mode 100644 src/main/java/io/supertokens/pluginInterface/oauth/exception/DuplicateOAuthLogoutChallengeException.java create mode 100644 src/main/java/io/supertokens/pluginInterface/oauth/exception/OAuthClientNotFoundException.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d6f79581..423fea79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [6.3.0] - 2024-10-02 + +- Adds `OAuthStorage` interface for OAuth Provider support + ## [6.2.0] - 2024-05-24 - Adds new class `ConfigFieldInfo` that represents a core config field diff --git a/build.gradle b/build.gradle index 48fc30d8..b945eddd 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java-library' } -version = "6.2.0" +version = "6.3.0" repositories { mavenCentral() diff --git a/src/main/java/io/supertokens/pluginInterface/RECIPE_ID.java b/src/main/java/io/supertokens/pluginInterface/RECIPE_ID.java index 6aee253f..d9d0848f 100644 --- a/src/main/java/io/supertokens/pluginInterface/RECIPE_ID.java +++ b/src/main/java/io/supertokens/pluginInterface/RECIPE_ID.java @@ -22,7 +22,7 @@ public enum RECIPE_ID { EMAIL_PASSWORD("emailpassword"), THIRD_PARTY("thirdparty"), SESSION("session"), EMAIL_VERIFICATION("emailverification"), JWT("jwt"), PASSWORDLESS("passwordless"), USER_METADATA("usermetadata"), USER_ROLES("userroles"), USER_ID_MAPPING("useridmapping"), DASHBOARD("dashboard"), TOTP("totp"), - MULTITENANCY("multitenancy"), ACCOUNT_LINKING("accountlinking"), MFA("mfa"); + MULTITENANCY("multitenancy"), ACCOUNT_LINKING("accountlinking"), MFA("mfa"), OAUTH("oauth"); private final String name; diff --git a/src/main/java/io/supertokens/pluginInterface/StorageUtils.java b/src/main/java/io/supertokens/pluginInterface/StorageUtils.java index 19bfb89a..9a18dbae 100644 --- a/src/main/java/io/supertokens/pluginInterface/StorageUtils.java +++ b/src/main/java/io/supertokens/pluginInterface/StorageUtils.java @@ -21,6 +21,7 @@ import io.supertokens.pluginInterface.emailpassword.sqlStorage.EmailPasswordSQLStorage; import io.supertokens.pluginInterface.emailverification.sqlStorage.EmailVerificationSQLStorage; import io.supertokens.pluginInterface.multitenancy.MultitenancyStorage; +import io.supertokens.pluginInterface.oauth.OAuthStorage; import io.supertokens.pluginInterface.passwordless.sqlStorage.PasswordlessSQLStorage; import io.supertokens.pluginInterface.session.SessionStorage; import io.supertokens.pluginInterface.thirdparty.sqlStorage.ThirdPartySQLStorage; @@ -132,4 +133,12 @@ public static MultitenancyStorage getMultitenancyStorage(Storage storage) { } return (MultitenancyStorage) storage; } + + public static OAuthStorage getOAuthStorage(Storage storage) { + if (storage.getType() != STORAGE_TYPE.SQL) { + // we only support SQL for now + throw new UnsupportedOperationException(""); + } + return (OAuthStorage) storage; + } } diff --git a/src/main/java/io/supertokens/pluginInterface/oauth/OAuthLogoutChallenge.java b/src/main/java/io/supertokens/pluginInterface/oauth/OAuthLogoutChallenge.java new file mode 100644 index 00000000..ca453367 --- /dev/null +++ b/src/main/java/io/supertokens/pluginInterface/oauth/OAuthLogoutChallenge.java @@ -0,0 +1,19 @@ +package io.supertokens.pluginInterface.oauth; + +public class OAuthLogoutChallenge { + public final String challenge; + public final String clientId; + public final String postLogoutRedirectionUri; + public final String sessionHandle; + public final String state; + public final long timeCreated; + + public OAuthLogoutChallenge(String challenge, String clientId, String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated) { + this.challenge = challenge; + this.clientId = clientId; + this.postLogoutRedirectionUri = postLogoutRedirectionUri; + this.sessionHandle = sessionHandle; + this.state = state; + this.timeCreated = timeCreated; + } +} diff --git a/src/main/java/io/supertokens/pluginInterface/oauth/OAuthRevokeTargetType.java b/src/main/java/io/supertokens/pluginInterface/oauth/OAuthRevokeTargetType.java new file mode 100644 index 00000000..8ccdf975 --- /dev/null +++ b/src/main/java/io/supertokens/pluginInterface/oauth/OAuthRevokeTargetType.java @@ -0,0 +1,18 @@ +package io.supertokens.pluginInterface.oauth; + +public enum OAuthRevokeTargetType { + CLIENT_ID("client_id"), + GID("gid"), + JTI("jti"), + SESSION_HANDLE("session_handle"); + + private final String value; + + OAuthRevokeTargetType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/io/supertokens/pluginInterface/oauth/OAuthStorage.java b/src/main/java/io/supertokens/pluginInterface/oauth/OAuthStorage.java new file mode 100644 index 00000000..e0e5916a --- /dev/null +++ b/src/main/java/io/supertokens/pluginInterface/oauth/OAuthStorage.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.supertokens.pluginInterface.oauth; + +import io.supertokens.pluginInterface.exceptions.StorageQueryException; +import io.supertokens.pluginInterface.multitenancy.AppIdentifier; +import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException; +import io.supertokens.pluginInterface.nonAuthRecipe.NonAuthRecipeStorage; +import io.supertokens.pluginInterface.oauth.exception.DuplicateOAuthLogoutChallengeException; +import io.supertokens.pluginInterface.oauth.exception.OAuthClientNotFoundException; + +import java.util.List; + +public interface OAuthStorage extends NonAuthRecipeStorage { + + public boolean doesOAuthClientIdExist(AppIdentifier appIdentifier, String clientId) throws + StorageQueryException; + + public void addOrUpdateOauthClient(AppIdentifier appIdentifier, String clientId, boolean isClientCredentialsOnly) throws TenantOrAppNotFoundException, StorageQueryException; + + public boolean deleteOAuthClient(AppIdentifier appIdentifier, String clientId) throws StorageQueryException; + + public List listOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException; + + public void revokeOAuthTokensBasedOnTargetFields(AppIdentifier appIdentifier, OAuthRevokeTargetType targetType, String targetValue, long exp) throws TenantOrAppNotFoundException, StorageQueryException; + + public boolean isOAuthTokenRevokedBasedOnTargetFields(AppIdentifier appIdentifier, OAuthRevokeTargetType[] targetTypes, String[] targetValues, long issuedAt) throws StorageQueryException; + + public void addOAuthM2MTokenForStats(AppIdentifier appIdentifier, String clientId, long iat, long exp) throws OAuthClientNotFoundException, StorageQueryException; + + public void cleanUpExpiredAndRevokedOAuthTokensList() throws StorageQueryException; + + public void addOAuthLogoutChallenge(AppIdentifier appIdentifier, String challenge, String clientId, String postLogoutRedirectionUri, String sessionHandle, String state, long timeCreated) throws + DuplicateOAuthLogoutChallengeException, OAuthClientNotFoundException, StorageQueryException; + + public OAuthLogoutChallenge getOAuthLogoutChallenge(AppIdentifier appIdentifier, String challenge) throws StorageQueryException; + + public void deleteOAuthLogoutChallenge(AppIdentifier appIdentifier, String challenge) throws StorageQueryException; + + public void deleteOAuthLogoutChallengesBefore(long time) throws StorageQueryException; + + public int countTotalNumberOfOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException; + + public int countTotalNumberOfClientCredentialsOnlyOAuthClients(AppIdentifier appIdentifier) throws StorageQueryException; + + public int countTotalNumberOfOAuthM2MTokensCreatedSince(AppIdentifier appIdentifier, long since) throws StorageQueryException; + + public int countTotalNumberOfOAuthM2MTokensAlive(AppIdentifier appIdentifier) throws StorageQueryException; +} diff --git a/src/main/java/io/supertokens/pluginInterface/oauth/exception/DuplicateOAuthLogoutChallengeException.java b/src/main/java/io/supertokens/pluginInterface/oauth/exception/DuplicateOAuthLogoutChallengeException.java new file mode 100644 index 00000000..0f1692ce --- /dev/null +++ b/src/main/java/io/supertokens/pluginInterface/oauth/exception/DuplicateOAuthLogoutChallengeException.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.supertokens.pluginInterface.oauth.exception; + +public class DuplicateOAuthLogoutChallengeException extends Exception { + private static final long serialVersionUID = -7183235655606906540L; +} diff --git a/src/main/java/io/supertokens/pluginInterface/oauth/exception/OAuthClientNotFoundException.java b/src/main/java/io/supertokens/pluginInterface/oauth/exception/OAuthClientNotFoundException.java new file mode 100644 index 00000000..f14d7bf2 --- /dev/null +++ b/src/main/java/io/supertokens/pluginInterface/oauth/exception/OAuthClientNotFoundException.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.supertokens.pluginInterface.oauth.exception; + +import java.io.Serial; + +public class OAuthClientNotFoundException extends Exception { + @Serial + private static final long serialVersionUID = 1412853176388698991L; +}