Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fbbe4a1
feat: improving indexes
porcellus Jan 25, 2026
ba125de
feat: implement LockedUser wrapper for PostgreSQL (ISO-001)
porcellus Jan 25, 2026
d20d144
test: add race-condition tests
porcellus Jan 25, 2026
70a202a
feat(ISO-002): implement LockedUser enforcement for reserveAccountInf…
porcellus Jan 25, 2026
1c41d86
feat(ISO-003): implement LockedUser enforcement for updateAccountInfo…
porcellus Jan 25, 2026
73a2176
feat(ISO-004): implement LockedUser enforcement for addPrimaryUserAcc…
porcellus Jan 25, 2026
5b5d87f
feat(ISO-005): implement LockedUser-based removeAccountInfoReservatio…
porcellus Jan 25, 2026
248d5f5
feat(ISO-006): add LockedUser validation to addTenantIdToRecipeUser_T…
porcellus Jan 25, 2026
b3948ee
fix: correct LockedUser state determination and linking validation
porcellus Jan 26, 2026
427f43c
feat(ISO-007): implement LockedUser enforcement for addTenantIdToPrim…
porcellus Jan 26, 2026
486a86d
feat: add recipeId to LockedUserImpl and fetch during lock acquisition
porcellus Jan 26, 2026
38aee3e
feat(ISO-008): use LockedUser for getRecipeIdForUser_Transaction
porcellus Jan 26, 2026
89bb6d2
feat(ISO-022): remove String-based duplicate methods, migrate plugin-…
porcellus Jan 27, 2026
cf24aa8
fix: remove FOR UPDATE from _Transaction methods per ISO-022
porcellus Jan 29, 2026
de9d021
feat: convert string-based helpers to use LockedUser (ISO-024)
porcellus Jan 30, 2026
ee274e9
fix: self-review and test fixes
porcellus Feb 1, 2026
05a3c36
test: add a way to check on query performance of tests
porcellus Feb 2, 2026
b1e88ee
Merge remote-tracking branch 'origin/master' into feat/isolation-rese…
porcellus Feb 2, 2026
47ff687
Merge remote-tracking branch 'origin/feat/isolation-reservation-table…
porcellus Feb 19, 2026
0bb7492
fix: address PR review comments
porcellus Feb 19, 2026
a462918
fix: restore correct jar from origin/master
porcellus Feb 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [9.3.1]

- Bump version

## [9.3.0]

- Adds SAML support
Expand Down Expand Up @@ -44,6 +48,7 @@ CREATE TABLE IF NOT EXISTS saml_relay_state (
state TEXT NOT NULL,
redirect_uri TEXT NOT NULL,
created_at BIGINT NOT NULL,
expires_at BIGINT NOT NULL,
CONSTRAINT saml_relay_state_pkey PRIMARY KEY(app_id, tenant_id, relay_state),
CONSTRAINT saml_relay_state_app_id_fkey FOREIGN KEY(app_id) REFERENCES apps (app_id) ON DELETE CASCADE,
CONSTRAINT saml_relay_state_tenant_id_fkey FOREIGN KEY(app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE
Expand All @@ -59,6 +64,7 @@ CREATE TABLE IF NOT EXISTS saml_claims (
code VARCHAR(256) NOT NULL,
claims TEXT NOT NULL,
created_at BIGINT NOT NULL,
expires_at BIGINT NOT NULL,
CONSTRAINT saml_claims_pkey PRIMARY KEY(app_id, tenant_id, code),
CONSTRAINT saml_claims_app_id_fkey FOREIGN KEY(app_id) REFERENCES apps (app_id) ON DELETE CASCADE,
CONSTRAINT saml_claims_tenant_id_fkey FOREIGN KEY(app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,4 @@ tasks.withType(Test).configureEach {
}
}
}
}
}
20 changes: 15 additions & 5 deletions implementationDependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,26 @@
"name":"jackson-dataformat-yaml 2.18.2",
"src":"https://repo.maven.apache.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.18.2/jackson-dataformat-yaml-2.18.2-sources.jar"
},
{
"jar":"https://repo.maven.apache.org/maven2/org/yaml/snakeyaml/2.3/snakeyaml-2.3.jar",
"name":"snakeyaml 2.3",
"src":"https://repo.maven.apache.org/maven2/org/yaml/snakeyaml/2.3/snakeyaml-2.3-sources.jar"
},
{
"jar":"https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.18.2/jackson-databind-2.18.2.jar",
"name":"jackson-databind 2.18.2",
"src":"https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.18.2/jackson-databind-2.18.2-sources.jar"
},
{
"jar":"https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-core/2.18.2/jackson-core-2.18.2.jar",
"name":"jackson-core 2.18.2",
"src":"https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-core/2.18.2/jackson-core-2.18.2-sources.jar"
},
{
"jar":"https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.18.2/jackson-annotations-2.18.2.jar",
"name":"jackson-annotations 2.18.2",
"src":"https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.18.2/jackson-annotations-2.18.2-sources.jar"
},
{
"jar":"https://repo.maven.apache.org/maven2/org/yaml/snakeyaml/2.3/snakeyaml-2.3.jar",
"name":"snakeyaml 2.3",
"src":"https://repo.maven.apache.org/maven2/org/yaml/snakeyaml/2.3/snakeyaml-2.3-sources.jar"
},
{
"jar":"https://repo.maven.apache.org/maven2/ch/qos/logback/logback-classic/1.5.13/logback-classic-1.5.13.jar",
"name":"logback-classic 1.5.13",
Expand Down
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually don't commit these jars. It's done by release process.

Binary file not shown.
Binary file added jar/postgresql-plugin-9.4.0.jar
Binary file not shown.
104 changes: 104 additions & 0 deletions src/main/java/io/supertokens/storage/postgresql/LockedUserImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* 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.storage.postgresql;

import io.supertokens.pluginInterface.useridmapping.LockedUser;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.sql.Connection;
import java.lang.ref.WeakReference;

/**
* PostgreSQL implementation of LockedUser.
* Tracks the connection to validate the lock is still active.
*/
public class LockedUserImpl implements LockedUser {

@Nonnull
private final String recipeUserId;

@Nonnull
private final String recipeId;

@Nullable
private final String primaryUserId;

// WeakReference so we don't prevent connection from being garbage collected
private final WeakReference<Connection> connectionRef;

public LockedUserImpl(@Nonnull String recipeUserId, @Nonnull String recipeId,
@Nullable String primaryUserId, @Nonnull Connection connection) {
this.recipeUserId = recipeUserId;
this.recipeId = recipeId;
this.primaryUserId = primaryUserId;
this.connectionRef = new WeakReference<>(connection);
}

@Override
@Nonnull
public String getRecipeUserId() {
return recipeUserId;
}

@Override
@Nonnull
public String getRecipeId() {
return recipeId;
}

@Override
@Nullable
public String getPrimaryUserId() {
return primaryUserId;
}

@Override
public boolean isValidForConnection(Object connection) {
Connection originalCon = connectionRef.get();
if (originalCon == null) {
return false;
}
// Check that the provided connection is the same instance as the one used to acquire the lock
if (originalCon != connection) {
return false;
}
try {
return !originalCon.isClosed();
} catch (Exception e) {
return false;
}
}

@Override
public String toString() {
Connection con = connectionRef.get();
boolean connectionAlive = false;
try {
connectionAlive = con != null && !con.isClosed();
} catch (Exception ignored) {
}
return "LockedUser{" +
"recipeUserId='" + recipeUserId + '\'' +
", recipeId='" + recipeId + '\'' +
", primaryUserId='" + primaryUserId + '\'' +
", isLinked=" + isLinked() +
", isPrimary=" + isPrimary() +
", connectionAlive=" + connectionAlive +
'}';
}
}
Loading
Loading