Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: MFA #162

Merged
merged 120 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from 108 commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
f99cd8f
changes storage layer to take json instead of config file path
rishabhpoddar Jan 19, 2023
e16d29b
adds new functions skeleton
rishabhpoddar Jan 19, 2023
841e84e
adds checks for conflicting configs for user pools
rishabhpoddar Jan 19, 2023
f322888
changes to tests to make them pass
rishabhpoddar Jan 19, 2023
dacfeef
adds skeleton for multi tenancy functions
rishabhpoddar Jan 21, 2023
426e2ed
fixes bug
rishabhpoddar Jan 23, 2023
4178085
adds connection pool ID function
rishabhpoddar Jan 23, 2023
89761fb
changes as per interface change
rishabhpoddar Jan 23, 2023
b7b8b5d
adds one test for multi tenany storage layer
rishabhpoddar Jan 24, 2023
787d49c
adds more tests
rishabhpoddar Jan 24, 2023
32680ee
fixes bugs
rishabhpoddar Jan 24, 2023
a700b72
adds more tests and changes config parsing to prioritise connection u…
rishabhpoddar Jan 25, 2023
91b3e33
fixes a few config parsing bugs
rishabhpoddar Jan 25, 2023
4ce4383
adds more tests
rishabhpoddar Jan 25, 2023
b68aebb
modifies testing to clear multiple user pools after each test
rishabhpoddar Jan 28, 2023
55e8075
makes initlogging idempotent
rishabhpoddar Jan 31, 2023
cbc005b
fixes all tests
rishabhpoddar Feb 3, 2023
ccb6f73
fixes tests
rishabhpoddar Feb 5, 2023
9cbc85f
adds more placeholder functions
rishabhpoddar Feb 7, 2023
ea05ab3
removes use of quiteprogramexception
rishabhpoddar Feb 7, 2023
18fd7ae
small change
rishabhpoddar Feb 8, 2023
b61ddc7
adds new function skeleton
rishabhpoddar Feb 8, 2023
06a0643
adds more skeleton functions
rishabhpoddar Feb 9, 2023
0c0931f
updates exception import
rishabhpoddar Feb 9, 2023
489ec41
adds skeleton for tenantIdentifier for emailpassword and useridmappin…
rishabhpoddar Feb 13, 2023
8a988ea
changes to incorporate tenantIndetifier for key value storage
rishabhpoddar Feb 14, 2023
5a9a47d
changes to session receipe to add tenantIdentifier
rishabhpoddar Feb 14, 2023
1c39f03
introduces the concept of appIdentifier vs tenantIdentifier
rishabhpoddar Feb 15, 2023
6746329
fixes test compilation issues
rishabhpoddar Feb 15, 2023
cb724ee
changes as per plugin change
rishabhpoddar Feb 15, 2023
72f7ec1
modifes user roles functions to add tenantidentifier and appidentifiers
rishabhpoddar Feb 15, 2023
39b5690
modifies emailpassword functions
rishabhpoddar Feb 16, 2023
145a4be
changes to a few functions
rishabhpoddar Feb 17, 2023
ebd1131
adds appidentifier to email verfication
rishabhpoddar Feb 17, 2023
437f39e
makes tests pass
rishabhpoddar Feb 17, 2023
805a9a7
adds tenant identifier to third party
rishabhpoddar Feb 17, 2023
38d10b1
adds tenantidentifier to passwordless
rishabhpoddar Feb 17, 2023
7e0c165
function name changes
rishabhpoddar Feb 20, 2023
9ae2f2d
fix: Multitenancy schema updates (#59)
sattvikc Mar 3, 2023
ef3a0a5
merges with latest
rishabhpoddar Mar 5, 2023
4525dec
fix: Multitenant emailpassword recipe changes (#60)
sattvikc Mar 14, 2023
639cb7c
fix: minor fix (#62)
sattvikc Mar 17, 2023
baf6a86
fix: Multitenant schema changes (#64)
sattvikc Mar 24, 2023
4c36155
fix: to support PR comments on core (#65)
sattvikc Mar 25, 2023
0c467d1
fix: Multitenant userroles (#69)
sattvikc Mar 28, 2023
d282b12
fix: Multitenant usermetadata (#70)
sattvikc Mar 29, 2023
7a9adbc
fix: ep storage (#71)
sattvikc Mar 29, 2023
09729e7
fix: thirdparty storage (#74)
sattvikc Mar 31, 2023
7eb9f2a
fix: Multitenant thirdparty changes for update email (#75)
sattvikc Apr 3, 2023
8dc347c
fix: Multitenant emailverification storage (#76)
sattvikc Apr 3, 2023
105b5f0
fix: tokens tenant specific (#77)
sattvikc Apr 3, 2023
154b9b3
fix: Multitenant session (#78)
sattvikc Apr 4, 2023
7800c54
comment modification
rishabhpoddar Apr 5, 2023
aaa94c2
fix: Multitenant session changes (#80)
sattvikc Apr 5, 2023
8e71b3e
Multi tenant merging with latest (#79)
rishabhpoddar Apr 5, 2023
ac16c99
many fixes
rishabhpoddar Apr 6, 2023
af8c931
fix: jwt changes (#82)
sattvikc Apr 6, 2023
6ac571a
fix: Multitenant General Queries (#84)
sattvikc Apr 10, 2023
16e970d
fix: Multitenant dashboard (#85)
sattvikc Apr 10, 2023
546de37
fix: Multitenant totp (#86)
sattvikc Apr 11, 2023
94855c9
merges (#87)
rishabhpoddar Apr 13, 2023
9d1a3a2
adds new config
rishabhpoddar Apr 18, 2023
528ee86
fix: multitenancy changes (#88)
sattvikc Apr 21, 2023
741a9b2
fix: Misc changes (#89)
sattvikc Apr 24, 2023
6662fb5
feat: Introduce MFA recipe in postgresql plugin
KShivendu Apr 27, 2023
45e6e09
chores: Mention MFA recipe support in CHANGELOG
KShivendu Apr 27, 2023
0e2b0e6
fix: Tenantid in userobjects (#90)
sattvikc Apr 27, 2023
1933454
fix: test fix (#92)
sattvikc Apr 28, 2023
6c3664e
fix: Startup log (#93)
sattvikc Apr 28, 2023
2e44c54
fix: Userpool test (#94)
sattvikc May 1, 2023
890192c
fix: delete non auth user (#95)
sattvikc May 2, 2023
71485b7
fix: Delete nonauth user (#96)
sattvikc May 4, 2023
1797df2
feat: Add active user stat queries for MFA
KShivendu May 4, 2023
77beacc
fix: Update user_id length in mfa_user_factors table
KShivendu May 4, 2023
0744c44
Set factor_id VARCHAR length to 16
KShivendu May 4, 2023
2d00098
fix: config validation (#97)
sattvikc May 4, 2023
8a7c696
fix: config per tenant, per app annotations (#98)
sattvikc May 5, 2023
57740f4
Merge branch 'multi-tenant-config' into feat/mfa
KShivendu May 9, 2023
4e1d22b
feat: Consider multitenancy when getting MFA stats
KShivendu May 10, 2023
2268cf2
test: Fix mistake in MFA table create query
KShivendu May 10, 2023
2b30ca9
feat: Add query to delete user from a tenant
KShivendu May 10, 2023
bfda93f
fix: config annotation (#102)
sattvikc May 12, 2023
a153063
fix: added setLogLevels (#103)
sattvikc May 15, 2023
275d4ad
Merge branch '3.0' into multi-tenant-config
sattvikc May 15, 2023
1b841e9
fix: merge issue
sattvikc May 15, 2023
1da59bc
Overload deleteMfaInfoForUser and set factor column size to 64
KShivendu May 15, 2023
f261688
fix: fkey names (#104)
sattvikc May 17, 2023
42eb27e
fix: Postgres migration (#105)
sattvikc May 23, 2023
e2b9ab3
fix: Fkey indexes (#109)
sattvikc May 25, 2023
8e1865d
Merge branch 'multi-tenant-config' into feat/mfa
KShivendu May 26, 2023
cdc6949
refactor: Replace totp not enabled error with unknown device error
KShivendu Jun 27, 2023
4d6a335
fix: Revert irrelevant changes
KShivendu Jun 27, 2023
453081b
Merge branch '5.0' into merge-5.0
sattvikc Sep 28, 2023
4917483
Merge pull request #161 from supertokens/merge-5.0
sattvikc Sep 28, 2023
4cf61bb
refactor: Replace TotpNotEnabledError with UnknownUserIdTotpError (#133)
KShivendu Sep 28, 2023
e547b94
fix: queries
sattvikc Sep 29, 2023
31578e2
fix: changes as per plugin interface (#163)
sattvikc Oct 3, 2023
d3ab41b
fix: mfa cleanup (#164)
sattvikc Oct 17, 2023
b6ae4e6
Merge branch '5.0' into merge-latest
sattvikc Oct 20, 2023
ed5eee8
Merge pull request #168 from supertokens/merge-latest
sattvikc Oct 20, 2023
b3f7a73
Mfa multitenancy (#167)
sattvikc Oct 27, 2023
6ebaa47
fix: created_at in totp devices (#169)
sattvikc Oct 31, 2023
dba89ba
fix: mfa stats (#170)
sattvikc Nov 1, 2023
72589b2
fix: index name
sattvikc Nov 6, 2023
c03a7f1
Merge branch '5.0' into feat/mfa
sattvikc Nov 6, 2023
d40538a
Merge branch '5.0' into feat/mfa
sattvikc Nov 28, 2023
d6e27cc
Merge branch '5.0' into feat/mfa
sattvikc Dec 21, 2023
08043dc
fix: mfa changes (#177)
sattvikc Dec 25, 2023
87e64f2
feat: make refresh update the signing key type of sessions (#180)
porcellus Jan 29, 2024
15a4351
fix: Merge latest (#199)
sattvikc Feb 27, 2024
85b4e52
merge latest (#204)
sattvikc Mar 7, 2024
f24e2eb
fix: One million users test (#196)
sattvikc Mar 11, 2024
451289b
fix: pass appId to getUserIdMappingForSuperTokensIds
sattvikc Mar 13, 2024
b6f9065
fix: one million users test
sattvikc Mar 13, 2024
8f4b1a9
fix: versions
sattvikc Mar 13, 2024
68cb492
fix: versions
sattvikc Mar 13, 2024
ae791e1
Remaining changes (#206)
sattvikc Mar 13, 2024
c91dea7
fix: one million users
sattvikc Mar 13, 2024
eb32bd3
Merge branch 'remaining-changes' into feat/mfa
sattvikc Mar 13, 2024
7a06b1f
Merge branch '6.0' into feat/mfa
sattvikc Mar 13, 2024
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

rishabhpoddar marked this conversation as resolved.
Show resolved Hide resolved
- Replace `TotpNotEnabledError` with `UnknownUserIdTotpError`.
- Support for MFA recipe

## [5.0.6] - 2023-12-05

- Validates db config types in `canBeUsed` function
Expand Down Expand Up @@ -130,7 +133,6 @@ CREATE INDEX IF NOT EXISTS app_id_to_user_id_primary_user_id_index ON app_id_to_
```
4. Run the new instance(s) of the core (version 7.0.0)


## [4.0.2]

- Fixes null pointer issue when user belongs to no tenant.
Expand Down
112 changes: 72 additions & 40 deletions src/main/java/io/supertokens/storage/postgresql/Start.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@
import io.supertokens.pluginInterface.jwt.JWTSigningKeyInfo;
import io.supertokens.pluginInterface.jwt.exceptions.DuplicateKeyIdException;
import io.supertokens.pluginInterface.jwt.sqlstorage.JWTRecipeSQLStorage;
import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
import io.supertokens.pluginInterface.multitenancy.MultitenancyStorage;
import io.supertokens.pluginInterface.multitenancy.TenantConfig;
import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;
import io.supertokens.pluginInterface.multitenancy.*;
import io.supertokens.pluginInterface.multitenancy.exceptions.DuplicateClientTypeException;
import io.supertokens.pluginInterface.multitenancy.exceptions.DuplicateTenantException;
import io.supertokens.pluginInterface.multitenancy.exceptions.DuplicateThirdPartyIdException;
Expand All @@ -71,8 +68,8 @@
import io.supertokens.pluginInterface.totp.TOTPStorage;
import io.supertokens.pluginInterface.totp.TOTPUsedCode;
import io.supertokens.pluginInterface.totp.exception.DeviceAlreadyExistsException;
import io.supertokens.pluginInterface.totp.exception.TotpNotEnabledException;
import io.supertokens.pluginInterface.totp.exception.UnknownDeviceException;
import io.supertokens.pluginInterface.totp.exception.UnknownTotpUserIdException;
import io.supertokens.pluginInterface.totp.exception.UsedCodeAlreadyExistsException;
import io.supertokens.pluginInterface.totp.sqlStorage.TOTPSQLStorage;
import io.supertokens.pluginInterface.useridmapping.UserIdMapping;
Expand Down Expand Up @@ -109,7 +106,8 @@
public class Start
implements SessionSQLStorage, EmailPasswordSQLStorage, EmailVerificationSQLStorage, ThirdPartySQLStorage,
JWTRecipeSQLStorage, PasswordlessSQLStorage, UserMetadataSQLStorage, UserRolesSQLStorage, UserIdMappingStorage,
UserIdMappingSQLStorage, MultitenancyStorage, MultitenancySQLStorage, DashboardSQLStorage, TOTPSQLStorage, ActiveUsersStorage, AuthRecipeSQLStorage {
UserIdMappingSQLStorage, MultitenancyStorage, MultitenancySQLStorage, DashboardSQLStorage, TOTPSQLStorage,
ActiveUsersStorage, ActiveUsersSQLStorage, AuthRecipeSQLStorage {

// 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.
Expand Down Expand Up @@ -831,13 +829,14 @@ public void addInfoToNonAuthRecipesBasedOnUserId(TenantIdentifier tenantIdentifi
}
} else if (className.equals(TOTPStorage.class.getName())) {
try {
TOTPDevice device = new TOTPDevice(userId, "testDevice", "secret", 0, 30, false);
TOTPQueries.createDevice(this, tenantIdentifier.toAppIdentifier(), device);
TOTPDevice device = new TOTPDevice(userId, "testDevice", "secret", 0, 30, false, System.currentTimeMillis());
this.startTransaction(con -> {
try {
long now = System.currentTimeMillis();
Connection sqlCon = (Connection) con.getConnection();
TOTPQueries.createDevice_Transaction(this, sqlCon, tenantIdentifier.toAppIdentifier(), device);
TOTPQueries.insertUsedCode_Transaction(this,
(Connection) con.getConnection(), tenantIdentifier,
sqlCon, tenantIdentifier,
new TOTPUsedCode(userId, "123456", true, 1000 + now, now));
} catch (SQLException e) {
throw new StorageTransactionLogicException(e);
Expand Down Expand Up @@ -1325,25 +1324,6 @@ public int countUsersActiveSince(AppIdentifier appIdentifier, long time) throws
}
}

@Override
public int countUsersEnabledTotp(AppIdentifier appIdentifier) throws StorageQueryException {
try {
return ActiveUsersQueries.countUsersEnabledTotp(this, appIdentifier);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

@Override
public int countUsersEnabledTotpAndActiveSince(AppIdentifier appIdentifier, long time)
throws StorageQueryException {
try {
return ActiveUsersQueries.countUsersEnabledTotpAndActiveSince(this, appIdentifier, time);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

@Override
public void deleteUserActive_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId)
throws StorageQueryException {
Expand Down Expand Up @@ -2618,26 +2598,60 @@ public void revokeExpiredSessions() throws StorageQueryException {
}

// TOTP recipe:
@TestOnly
@Override
public void createDevice(AppIdentifier appIdentifier, TOTPDevice device)
throws StorageQueryException, DeviceAlreadyExistsException, TenantOrAppNotFoundException {
throws DeviceAlreadyExistsException, TenantOrAppNotFoundException, StorageQueryException {
try {
TOTPQueries.createDevice(this, appIdentifier, device);
startTransaction(con -> {
try {
createDevice_Transaction(con, new AppIdentifier(null, null), device);
} catch (DeviceAlreadyExistsException | TenantOrAppNotFoundException e) {
throw new StorageTransactionLogicException(e);
}
return null;
});
} catch (StorageTransactionLogicException e) {
Exception actualException = e.actualException;
if (e.actualException instanceof DeviceAlreadyExistsException) {
throw (DeviceAlreadyExistsException) e.actualException;
} else if (e.actualException instanceof TenantOrAppNotFoundException) {
throw (TenantOrAppNotFoundException) e.actualException;
} else if (e.actualException instanceof StorageQueryException) {
throw (StorageQueryException) e.actualException;
}
}
}

@Override
public TOTPDevice createDevice_Transaction(TransactionConnection con, AppIdentifier appIdentifier, TOTPDevice device)
throws StorageQueryException, DeviceAlreadyExistsException, TenantOrAppNotFoundException {
Connection sqlCon = (Connection) con.getConnection();
try {
TOTPQueries.createDevice_Transaction(this, sqlCon, appIdentifier, device);
return device;
} catch (SQLException e) {
Exception actualException = e;

if (actualException instanceof PSQLException) {
ServerErrorMessage errMsg = ((PSQLException) actualException).getServerErrorMessage();

if (isPrimaryKeyError(errMsg, Config.getConfig(this).getTotpUserDevicesTable())) {
throw new DeviceAlreadyExistsException();
throw new DeviceAlreadyExistsException();
} else if (isForeignKeyConstraintError(errMsg, Config.getConfig(this).getTotpUsersTable(), "app_id")) {
throw new TenantOrAppNotFoundException(appIdentifier);
throw new TenantOrAppNotFoundException(appIdentifier);
}

}
throw new StorageQueryException(e);
}
}

throw new StorageQueryException(e.actualException);
@Override
public TOTPDevice getDeviceByName_Transaction(TransactionConnection con, AppIdentifier appIdentifier, String userId, String deviceName) throws StorageQueryException {
Connection sqlCon = (Connection) con.getConnection();
try {
return TOTPQueries.getDeviceByName_Transaction(this, sqlCon, appIdentifier, userId, deviceName);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

Expand Down Expand Up @@ -2691,8 +2705,8 @@ public boolean removeUser(TenantIdentifier tenantIdentifier, String userId)

@Override
public void updateDeviceName(AppIdentifier appIdentifier, String userId, String oldDeviceName, String newDeviceName)
throws StorageQueryException, DeviceAlreadyExistsException,
UnknownDeviceException {
throws StorageQueryException,
UnknownDeviceException, DeviceAlreadyExistsException {
try {
int updatedCount = TOTPQueries.updateDeviceName(this, appIdentifier, userId, oldDeviceName, newDeviceName);
if (updatedCount == 0) {
Expand All @@ -2702,7 +2716,7 @@ public void updateDeviceName(AppIdentifier appIdentifier, String userId, String
if (e instanceof PSQLException) {
ServerErrorMessage errMsg = ((PSQLException) e).getServerErrorMessage();
if (isPrimaryKeyError(errMsg, Config.getConfig(this).getTotpUserDevicesTable())) {
throw new DeviceAlreadyExistsException();
throw new DeviceAlreadyExistsException();
}
}
throw new StorageQueryException(e);
Expand Down Expand Up @@ -2733,7 +2747,7 @@ public TOTPDevice[] getDevices_Transaction(TransactionConnection con, AppIdentif
@Override
public void insertUsedCode_Transaction(TransactionConnection con, TenantIdentifier tenantIdentifier,
TOTPUsedCode usedCodeObj)
throws StorageQueryException, TotpNotEnabledException, UsedCodeAlreadyExistsException,
throws StorageQueryException, UnknownTotpUserIdException, UsedCodeAlreadyExistsException,
TenantOrAppNotFoundException {
Connection sqlCon = (Connection) con.getConnection();
try {
Expand All @@ -2745,7 +2759,7 @@ public void insertUsedCode_Transaction(TransactionConnection con, TenantIdentifi
throw new UsedCodeAlreadyExistsException();
} else if (isForeignKeyConstraintError(err, Config.getConfig(this).getTotpUsedCodesTable(),
"user_id")) {
throw new TotpNotEnabledException();
throw new UnknownTotpUserIdException();
} else if (isForeignKeyConstraintError(err, Config.getConfig(this).getTotpUsedCodesTable(), "tenant_id")) {
throw new TenantOrAppNotFoundException(tenantIdentifier);
}
Expand Down Expand Up @@ -2990,4 +3004,22 @@ public UserIdMapping[] getUserIdMapping_Transaction(TransactionConnection con, A
throw new StorageQueryException(e);
}
}

@Override
public int getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(AppIdentifier appIdentifier) throws StorageQueryException {
try {
return GeneralQueries.getUsersCountWithMoreThanOneLoginMethodOrTOTPEnabled(this, appIdentifier);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}

@Override
public int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(AppIdentifier appIdentifier, long sinceTime) throws StorageQueryException {
try {
return ActiveUsersQueries.countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(this, appIdentifier, sinceTime);
} catch (SQLException e) {
throw new StorageQueryException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ public String getTenantConfigsTable() {
return addSchemaAndPrefixToTableName("tenant_configs");
}

public String getTenantFirstFactorsTable() {
return addSchemaAndPrefixToTableName("tenant_first_factors");
}

public String getTenantRequiredSecondaryFactorsTable() {
return addSchemaAndPrefixToTableName("tenant_required_secondary_factors");
}

public String getTenantThirdPartyProvidersTable() {
return addSchemaAndPrefixToTableName("tenant_thirdparty_providers");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.update;
import static io.supertokens.storage.postgresql.config.Config.getConfig;

public class ActiveUsersQueries {
static String getQueryToCreateUserLastActiveTable(Start start) {
Expand Down Expand Up @@ -51,9 +52,10 @@ public static int countUsersActiveSince(Start start, AppIdentifier appIdentifier

public static int countUsersActiveSinceAndHasMoreThanOneLoginMethod(Start start, AppIdentifier appIdentifier, long sinceTime)
throws SQLException, StorageQueryException {
// TODO: Active users are present only on public tenant and MFA users may be present on different storages
String QUERY = "SELECT count(1) as c FROM ("
+ " SELECT count(user_id) as num_login_methods, app_id, primary_or_recipe_user_id"
+ " FROM " + Config.getConfig(start).getUsersTable()
+ " FROM " + Config.getConfig(start).getAppIdToUserIdTable()
+ " WHERE primary_or_recipe_user_id IN ("
+ " SELECT user_id FROM " + Config.getConfig(start).getUserLastActiveTable()
+ " WHERE app_id = ? AND last_active_time >= ?"
Expand All @@ -71,40 +73,6 @@ public static int countUsersActiveSinceAndHasMoreThanOneLoginMethod(Start start,
});
}

public static int countUsersEnabledTotp(Start start, AppIdentifier appIdentifier)
throws SQLException, StorageQueryException {
String QUERY = "SELECT COUNT(*) as total FROM " + Config.getConfig(start).getTotpUsersTable()
+ " WHERE app_id = ?";

return execute(start, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
}, result -> {
if (result.next()) {
return result.getInt("total");
}
return 0;
});
}

public static int countUsersEnabledTotpAndActiveSince(Start start, AppIdentifier appIdentifier, long sinceTime)
throws SQLException, StorageQueryException {
String QUERY =
"SELECT COUNT(*) as total FROM " + Config.getConfig(start).getTotpUsersTable() + " AS totp_users "
+ "INNER JOIN " + Config.getConfig(start).getUserLastActiveTable() + " AS user_last_active "
+ "ON totp_users.user_id = user_last_active.user_id "
+ "WHERE user_last_active.app_id = ? AND user_last_active.last_active_time >= ?";

return execute(start, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setLong(2, sinceTime);
}, result -> {
if (result.next()) {
return result.getInt("total");
}
return 0;
});
}

public static int updateUserLastActive(Start start, AppIdentifier appIdentifier, String userId)
throws SQLException, StorageQueryException {
String QUERY = "INSERT INTO " + Config.getConfig(start).getUserLastActiveTable()
Expand Down Expand Up @@ -152,4 +120,41 @@ public static void deleteUserActive_Transaction(Connection con, Start start, App
pst.setString(2, userId);
});
}

public static int countUsersThatHaveMoreThanOneLoginMethodOrTOTPEnabledAndActiveSince(Start start, AppIdentifier appIdentifier, long sinceTime)
throws SQLException, StorageQueryException {
// TODO: Active users are present only on public tenant and MFA users may be present on different storages
String QUERY =
"SELECT COUNT (DISTINCT user_id) as c FROM ("
+ " (" // users with more than one login method
+ " SELECT primary_or_recipe_user_id AS user_id FROM ("
+ " SELECT COUNT(user_id) as num_login_methods, app_id, primary_or_recipe_user_id"
+ " FROM " + getConfig(start).getAppIdToUserIdTable()
+ " WHERE app_id = ? AND primary_or_recipe_user_id IN ("
+ " SELECT user_id FROM " + getConfig(start).getUserLastActiveTable()
+ " WHERE app_id = ? AND last_active_time >= ?"
+ " )"
+ " GROUP BY (app_id, primary_or_recipe_user_id)"
+ " ) AS nloginmethods"
+ " WHERE num_login_methods > 1"
+ " ) UNION (" // TOTP users
+ " SELECT user_id FROM " + getConfig(start).getTotpUsersTable()
+ " WHERE app_id = ? AND user_id IN ("
+ " SELECT user_id FROM " + getConfig(start).getUserLastActiveTable()
+ " WHERE app_id = ? AND last_active_time >= ?"
+ " )"
+ " )"
+ ") AS all_users";

return execute(start, QUERY, pst -> {
pst.setString(1, appIdentifier.getAppId());
pst.setString(2, appIdentifier.getAppId());
pst.setLong(3, sinceTime);
pst.setString(4, appIdentifier.getAppId());
pst.setString(5, appIdentifier.getAppId());
pst.setLong(6, sinceTime);
}, result -> {
return result.next() ? result.getInt("c") : 0;
});
}
}
Loading
Loading