diff --git a/src/main/java/io/supertokens/inmemorydb/Start.java b/src/main/java/io/supertokens/inmemorydb/Start.java index cfc402645..59be39b1e 100644 --- a/src/main/java/io/supertokens/inmemorydb/Start.java +++ b/src/main/java/io/supertokens/inmemorydb/Start.java @@ -3363,9 +3363,55 @@ public WebAuthNStoredCredential loadCredentialById_Transaction(TenantIdentifier } } + @Override + public AuthRecipeUserInfo signUpWithCredentialsRegister_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, + String userId, String email, String relyingPartyId, WebAuthNStoredCredential credential) + throws StorageQueryException, DuplicateUserIdException, TenantOrAppNotFoundException, + DuplicateEmailException { + Connection sqlCon = (Connection) con.getConnection(); + try { + return WebAuthNQueries.signUpWithCredentialRegister_Transaction(this, sqlCon, tenantIdentifier, userId, email, relyingPartyId, credential); + } catch (StorageTransactionLogicException stle) { + if (stle.actualException instanceof SQLiteException) { + SQLiteConfig config = Config.getConfig(this); + String serverMessage = stle.actualException.getMessage(); + + if (isUniqueConstraintError(serverMessage, config.getWebAuthNUserToTenantTable(), + new String[]{"app_id", "tenant_id", "email"})) { + throw new DuplicateEmailException(); + } else if (isPrimaryKeyError(serverMessage, config.getWebAuthNUsersTable(), + new String[]{"app_id", "user_id"}) + || isPrimaryKeyError(serverMessage, config.getUsersTable(), + new String[]{"app_id", "tenant_id", "user_id"}) + || isPrimaryKeyError(serverMessage, config.getWebAuthNUserToTenantTable(), + new String[]{"app_id", "tenant_id", "user_id"}) + || isPrimaryKeyError(serverMessage, config.getAppIdToUserIdTable(), + new String[]{"app_id", "user_id"})) { + throw new DuplicateUserIdException(); + } else if (isForeignKeyConstraintError( + serverMessage, + config.getAppsTable(), + new String[]{"app_id"}, + new Object[]{tenantIdentifier.getAppId()})) { + throw new TenantOrAppNotFoundException(tenantIdentifier); + } else if (isForeignKeyConstraintError( + serverMessage, + config.getTenantsTable(), + new String[]{"app_id", "tenant_id"}, + new Object[]{tenantIdentifier.getAppId(), tenantIdentifier.getTenantId()})) { + throw new TenantOrAppNotFoundException(tenantIdentifier); + } + } + + throw new StorageQueryException(stle.actualException); + } catch (SQLException e) { + throw new StorageQueryException(e); + } + } + @Override public AuthRecipeUserInfo signUp_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, - String userId, String email, String relyingPartyId) + String userId, String email, String relyingPartyId) throws StorageQueryException, DuplicateUserIdException, TenantOrAppNotFoundException, DuplicateEmailException { Connection sqlCon = (Connection) con.getConnection(); @@ -3404,6 +3450,8 @@ public AuthRecipeUserInfo signUp_Transaction(TenantIdentifier tenantIdentifier, } throw new StorageQueryException(stle.actualException); + } catch (SQLException e) { + throw new StorageQueryException(e); } } diff --git a/src/main/java/io/supertokens/inmemorydb/queries/WebAuthNQueries.java b/src/main/java/io/supertokens/inmemorydb/queries/WebAuthNQueries.java index 54833b0ab..216b342c2 100644 --- a/src/main/java/io/supertokens/inmemorydb/queries/WebAuthNQueries.java +++ b/src/main/java/io/supertokens/inmemorydb/queries/WebAuthNQueries.java @@ -28,6 +28,7 @@ import io.supertokens.pluginInterface.multitenancy.TenantIdentifier; import io.supertokens.pluginInterface.webauthn.WebAuthNOptions; import io.supertokens.pluginInterface.webauthn.WebAuthNStoredCredential; +import org.jetbrains.annotations.Nullable; import java.sql.Connection; import java.sql.ResultSet; @@ -216,8 +217,8 @@ public static WebAuthNStoredCredential saveCredential_Transaction(Start start, C return credential; } - public static AuthRecipeUserInfo signUp_Transaction(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String userId, String email, - String relyingPartyId) + public static void createUser_Transaction(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String userId, String email, + String relyingPartyId) throws StorageTransactionLogicException, StorageQueryException { long timeJoined = System.currentTimeMillis(); @@ -274,20 +275,46 @@ public static AuthRecipeUserInfo signUp_Transaction(Start start, Connection sqlC pst.setLong(5, timeJoined); }); - //sqlCon.commit(); - Collection loginMethods = getUsersInfoUsingIdList_Transaction(start, sqlCon, Collections.singleton(userId), tenantIdentifier.toAppIdentifier()); - if(!loginMethods.isEmpty()) { //expecting it to be size 1 - for(LoginMethod loginMethod: loginMethods){ - return AuthRecipeUserInfo.create(userId, false, loginMethod); - } - } - - return null; } catch (SQLException throwables) { throw new StorageTransactionLogicException(throwables); } } + public static AuthRecipeUserInfo signUp_Transaction(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String userId, String email, + String relyingPartyId) + throws StorageTransactionLogicException, StorageQueryException, SQLException { + + createUser_Transaction(start, sqlCon, tenantIdentifier, userId, email, relyingPartyId); + + return getAuthRecipeUserInfo(start, sqlCon, + tenantIdentifier, userId); + } + + public static AuthRecipeUserInfo signUpWithCredentialRegister_Transaction(Start start, Connection sqlCon, TenantIdentifier tenantIdentifier, String userId, String email, + String relyingPartyId, WebAuthNStoredCredential credential) + throws StorageQueryException, StorageTransactionLogicException, SQLException { + + createUser_Transaction(start, sqlCon, tenantIdentifier, userId, email, relyingPartyId); + saveCredential_Transaction(start, sqlCon, tenantIdentifier, credential); + + return getAuthRecipeUserInfo(start, sqlCon, + tenantIdentifier, userId); + } + + @Nullable + private static AuthRecipeUserInfo getAuthRecipeUserInfo(Start start, Connection sqlCon, + TenantIdentifier tenantIdentifier, String userId) + throws SQLException, StorageQueryException { + Collection loginMethods = getUsersInfoUsingIdList_Transaction(start, sqlCon, + Collections.singleton(userId), tenantIdentifier.toAppIdentifier()); + if (!loginMethods.isEmpty()) { //expecting it to be size 1 + for (LoginMethod loginMethod : loginMethods) { + return AuthRecipeUserInfo.create(userId, false, loginMethod); + } + } + return null; + } + public static String getPrimaryUserIdUsingEmail(Start start, TenantIdentifier tenantIdentifier, String email) throws SQLException, StorageQueryException { String QUERY = "SELECT DISTINCT all_users.primary_or_recipe_user_id AS user_id " diff --git a/src/main/java/io/supertokens/webauthn/WebAuthN.java b/src/main/java/io/supertokens/webauthn/WebAuthN.java index 69c6c1d28..9f43edbdd 100644 --- a/src/main/java/io/supertokens/webauthn/WebAuthN.java +++ b/src/main/java/io/supertokens/webauthn/WebAuthN.java @@ -186,26 +186,22 @@ public static WebAuthNSignInUpResult signUp(Storage storage, TenantIdentifier te while (true) { try { String recipeUserId = Utils.getUUID(); + WebAuthNOptions generatedOptions = webAuthNStorage.loadOptionsById_Transaction(tenantIdentifier, con, optionsId); - AuthRecipeUserInfo userInfo = webAuthNStorage.signUp_Transaction(tenantIdentifier, con, recipeUserId, generatedOptions.userEmail, - generatedOptions.relyingPartyId); - userInfo.setExternalUserId(null); - - RegistrationData verifiedRegistrationData = getRegistrationData(registrationResponseJson, generatedOptions); WebAuthNStoredCredential credentialToSave = WebauthMapper.mapRegistrationDataToStoredCredential( verifiedRegistrationData, recipeUserId, credentialId, generatedOptions.userEmail, generatedOptions.relyingPartyId, tenantIdentifier); - WebAuthNStoredCredential savedCredential = webAuthNStorage.saveCredentials_Transaction( - tenantIdentifier, - con, credentialToSave); + AuthRecipeUserInfo userInfo = webAuthNStorage.signUpWithCredentialsRegister_Transaction(tenantIdentifier, con, recipeUserId, generatedOptions.userEmail, + generatedOptions.relyingPartyId, credentialToSave); + userInfo.setExternalUserId(null); - return new WebAuthNSignInUpResult(savedCredential, userInfo, generatedOptions); + return new WebAuthNSignInUpResult(credentialToSave, userInfo, generatedOptions); } catch (DuplicateUserIdException duplicateUserIdException) { //ignore and retry } catch (Exception e) { diff --git a/src/main/java/io/supertokens/webserver/api/webauthn/SignInAPI.java b/src/main/java/io/supertokens/webserver/api/webauthn/SignInAPI.java index 727a4b17a..eb0673347 100644 --- a/src/main/java/io/supertokens/webserver/api/webauthn/SignInAPI.java +++ b/src/main/java/io/supertokens/webserver/api/webauthn/SignInAPI.java @@ -18,6 +18,7 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; +import io.supertokens.ActiveUsers; import io.supertokens.Main; import io.supertokens.pluginInterface.Storage; import io.supertokens.pluginInterface.multitenancy.TenantIdentifier; @@ -51,7 +52,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I TenantIdentifier tenantIdentifier = getTenantIdentifier(req); Storage storage = getTenantStorage(req); - String webauthGeneratedOptionsId = InputParser.parseStringOrThrowError(input, "webauthGeneratedOptionsId", + String webauthGeneratedOptionsId = InputParser.parseStringOrThrowError(input, "webauthnGeneratedOptionsId", false); JsonObject credentialsData = InputParser.parseJsonObjectOrThrowError(input, "credential", false); String credentialsDataString = new Gson().toJson(credentialsData); @@ -64,6 +65,9 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I throw new ServletException("WebAuthN sign in failed"); } + ActiveUsers.updateLastActive(tenantIdentifier.toAppIdentifier(), main, + signInResult.userInfo.getSupertokensUserId()); + JsonObject result = new JsonObject(); result.addProperty("status", "OK"); result.add("user", new Gson().fromJson(new Gson().toJson(signInResult.userInfo), JsonObject.class)); diff --git a/src/main/java/io/supertokens/webserver/api/webauthn/SignUpWithCredentialRegisterAPI.java b/src/main/java/io/supertokens/webserver/api/webauthn/SignUpWithCredentialRegisterAPI.java index f74e6663e..33b25c6e8 100644 --- a/src/main/java/io/supertokens/webserver/api/webauthn/SignUpWithCredentialRegisterAPI.java +++ b/src/main/java/io/supertokens/webserver/api/webauthn/SignUpWithCredentialRegisterAPI.java @@ -78,6 +78,9 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I result.addProperty("relyingPartyName", signUpResult.options.relyingPartyName); result.addProperty("recipeUserId", signUpResult.credential.userId); + Logging.info(this.main, tenantIdentifier, "SIGNUP_WITH_CREDENTIAL RESPONSE " , true); + Logging.info(this.main, tenantIdentifier, result.toString(), true); + super.sendJsonResponse(200, result, resp); } catch ( TenantOrAppNotFoundException e) {