Skip to content

Commit f1b2f46

Browse files
authored
Merge pull request #236 from supertokens/feat/webauthn-1
feat: creating webauthn related tables
2 parents e76a262 + 550ce1b commit f1b2f46

File tree

5 files changed

+1221
-2
lines changed

5 files changed

+1221
-2
lines changed

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

Lines changed: 351 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@
9999
import io.supertokens.pluginInterface.userroles.exception.DuplicateUserRoleMappingException;
100100
import io.supertokens.pluginInterface.userroles.exception.UnknownRoleException;
101101
import io.supertokens.pluginInterface.userroles.sqlStorage.UserRolesSQLStorage;
102+
import io.supertokens.pluginInterface.webauthn.AccountRecoveryTokenInfo;
103+
import io.supertokens.pluginInterface.webauthn.WebAuthNOptions;
104+
import io.supertokens.pluginInterface.webauthn.WebAuthNStoredCredential;
105+
import io.supertokens.pluginInterface.webauthn.exceptions.DuplicateRecoverAccountTokenException;
106+
import io.supertokens.pluginInterface.webauthn.exceptions.DuplicateUserEmailException;
107+
import io.supertokens.pluginInterface.webauthn.exceptions.WebauthNCredentialNotExistsException;
108+
import io.supertokens.pluginInterface.webauthn.exceptions.WebauthNOptionsNotExistsException;
109+
import io.supertokens.pluginInterface.webauthn.slqStorage.WebAuthNSQLStorage;
102110
import io.supertokens.storage.postgresql.config.Config;
103111
import io.supertokens.storage.postgresql.config.PostgreSQLConfig;
104112
import io.supertokens.storage.postgresql.output.Logging;
@@ -123,7 +131,8 @@ public class Start
123131
implements SessionSQLStorage, EmailPasswordSQLStorage, EmailVerificationSQLStorage, ThirdPartySQLStorage,
124132
JWTRecipeSQLStorage, PasswordlessSQLStorage, UserMetadataSQLStorage, UserRolesSQLStorage, UserIdMappingStorage,
125133
UserIdMappingSQLStorage, MultitenancyStorage, MultitenancySQLStorage, DashboardSQLStorage, TOTPSQLStorage,
126-
ActiveUsersStorage, ActiveUsersSQLStorage, AuthRecipeSQLStorage, OAuthStorage, BulkImportSQLStorage {
134+
ActiveUsersStorage, ActiveUsersSQLStorage, AuthRecipeSQLStorage, OAuthStorage, BulkImportSQLStorage,
135+
WebAuthNSQLStorage {
127136

128137
// these configs are protected from being modified / viewed by the dev using the SuperTokens
129138
// SaaS. If the core is not running in SuperTokens SaaS, this array has no effect.
@@ -1672,6 +1681,30 @@ public AuthRecipeUserInfo[] listPrimaryUsersByPhoneNumber(TenantIdentifier tenan
16721681
}
16731682
}
16741683

1684+
@Override
1685+
public AuthRecipeUserInfo getPrimaryUserByWebauthNCredentialId(TenantIdentifier tenantIdentifier,
1686+
String webauthNCredentialId)
1687+
throws StorageQueryException {
1688+
try {
1689+
return GeneralQueries.getPrimaryUserByWebauthNCredentialId(this, tenantIdentifier, webauthNCredentialId);
1690+
} catch (SQLException | StorageTransactionLogicException e) {
1691+
throw new StorageQueryException(e);
1692+
}
1693+
}
1694+
1695+
@Override
1696+
public AuthRecipeUserInfo getPrimaryUserByWebauthNCredentialId_Transaction(TenantIdentifier tenantIdentifier,
1697+
TransactionConnection con,
1698+
String credentialId)
1699+
throws StorageQueryException {
1700+
try {
1701+
Connection sqlCon = (Connection) con.getConnection();
1702+
return GeneralQueries.getPrimaryUserByWebauthNCredentialId_Transaction(this, sqlCon, tenantIdentifier, credentialId);
1703+
} catch (SQLException | StorageTransactionLogicException e) {
1704+
throw new StorageQueryException(e);
1705+
}
1706+
}
1707+
16751708
@Override
16761709
public AuthRecipeUserInfo getPrimaryUserByThirdPartyInfo(TenantIdentifier tenantIdentifier, String thirdPartyId,
16771710
String thirdPartyUserId) throws StorageQueryException {
@@ -3950,4 +3983,321 @@ public boolean isOAuthTokenRevokedByJTI(AppIdentifier appIdentifier, String gid,
39503983
throw new StorageQueryException(e);
39513984
}
39523985
}
3986+
3987+
@Override
3988+
public WebAuthNStoredCredential saveCredentials(TenantIdentifier tenantIdentifier, WebAuthNStoredCredential credential)
3989+
throws StorageQueryException {
3990+
try {
3991+
return WebAuthNQueries.saveCredential(this, tenantIdentifier, credential);
3992+
} catch (SQLException e) {
3993+
throw new StorageQueryException(e);
3994+
}
3995+
}
3996+
3997+
@Override
3998+
public WebAuthNOptions saveGeneratedOptions(TenantIdentifier tenantIdentifier, WebAuthNOptions optionsToSave) throws StorageQueryException {
3999+
try {
4000+
return WebAuthNQueries.saveOptions(this, tenantIdentifier, optionsToSave);
4001+
} catch (SQLException e) {
4002+
throw new StorageQueryException(e);
4003+
}
4004+
}
4005+
4006+
@Override
4007+
public WebAuthNOptions loadOptionsById(TenantIdentifier tenantIdentifier, String optionsId)
4008+
throws StorageQueryException {
4009+
try {
4010+
return WebAuthNQueries.loadOptionsById(this, tenantIdentifier, optionsId);
4011+
} catch (SQLException e){
4012+
throw new StorageQueryException(e);
4013+
}
4014+
}
4015+
4016+
@Override
4017+
public WebAuthNStoredCredential loadCredentialByIdForUser(TenantIdentifier tenantIdentifier, String credentialId, String recipeUserId)
4018+
throws StorageQueryException {
4019+
try {
4020+
return WebAuthNQueries.loadCredentialByIdForUser(this, tenantIdentifier, credentialId, recipeUserId);
4021+
} catch (SQLException e) {
4022+
throw new StorageQueryException(e);
4023+
}
4024+
}
4025+
4026+
4027+
@Override
4028+
public WebAuthNStoredCredential saveCredentials_Transaction(TenantIdentifier tenantIdentifier,
4029+
TransactionConnection con,
4030+
WebAuthNStoredCredential credential)
4031+
throws StorageQueryException {
4032+
4033+
Connection sqlCon = (Connection) con.getConnection();
4034+
try {
4035+
return WebAuthNQueries.saveCredential_Transaction(this, sqlCon, tenantIdentifier, credential);
4036+
} catch (SQLException e) {
4037+
throw new StorageQueryException(e);
4038+
}
4039+
}
4040+
4041+
@Override
4042+
public WebAuthNOptions loadOptionsById_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con,
4043+
String optionsId) throws StorageQueryException {
4044+
try {
4045+
Connection sqlCon = (Connection) con.getConnection();
4046+
return WebAuthNQueries.loadOptionsById_Transaction(this, sqlCon, tenantIdentifier, optionsId);
4047+
} catch (SQLException e) {
4048+
throw new StorageQueryException(e);
4049+
}
4050+
}
4051+
4052+
@Override
4053+
public WebAuthNStoredCredential loadCredentialById_Transaction(TenantIdentifier tenantIdentifier,
4054+
TransactionConnection con, String credentialId)
4055+
throws StorageQueryException {
4056+
try {
4057+
Connection sqlCon = (Connection) con.getConnection();
4058+
return WebAuthNQueries.loadCredentialById_Transaction(this, sqlCon, tenantIdentifier, credentialId);
4059+
} catch (SQLException e) {
4060+
throw new StorageQueryException(e);
4061+
}
4062+
}
4063+
4064+
@Override
4065+
public AuthRecipeUserInfo signUpWithCredentialsRegister_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con,
4066+
String userId, String email, String relyingPartyId, WebAuthNStoredCredential credential)
4067+
throws StorageQueryException, io.supertokens.pluginInterface.webauthn.exceptions.DuplicateUserIdException, TenantOrAppNotFoundException,
4068+
DuplicateUserEmailException {
4069+
Connection sqlCon = (Connection) con.getConnection();
4070+
try {
4071+
return WebAuthNQueries.signUpWithCredentialRegister_Transaction(this, sqlCon, tenantIdentifier, userId, email, relyingPartyId, credential);
4072+
} catch (StorageTransactionLogicException stle) {
4073+
if (stle.actualException instanceof SQLException) {
4074+
ServerErrorMessage errorMessage = ((PSQLException) stle.actualException).getServerErrorMessage();
4075+
PostgreSQLConfig config = Config.getConfig(this);
4076+
4077+
if (isUniqueConstraintError(errorMessage, config.getWebAuthNUserToTenantTable(),"email")) {
4078+
Logging.error(this, errorMessage.getMessage(), true);
4079+
Logging.error(this, email, true);
4080+
throw new DuplicateUserEmailException();
4081+
} else if (isPrimaryKeyError(errorMessage, config.getWebAuthNUsersTable())
4082+
|| isPrimaryKeyError(errorMessage, config.getUsersTable())
4083+
|| isPrimaryKeyError(errorMessage, config.getWebAuthNUserToTenantTable())
4084+
|| isPrimaryKeyError(errorMessage, config.getAppIdToUserIdTable())) {
4085+
throw new io.supertokens.pluginInterface.webauthn.exceptions.DuplicateUserIdException();
4086+
} else if (isForeignKeyConstraintError(
4087+
errorMessage,
4088+
config.getAppsTable(),
4089+
"app_id")) {
4090+
throw new TenantOrAppNotFoundException(tenantIdentifier.toAppIdentifier());
4091+
} else if (isForeignKeyConstraintError(
4092+
errorMessage,
4093+
config.getTenantsTable(),
4094+
"tenant_id")) {
4095+
throw new TenantOrAppNotFoundException(tenantIdentifier);
4096+
}
4097+
}
4098+
4099+
throw new StorageQueryException(stle.actualException);
4100+
} catch (SQLException e) {
4101+
throw new StorageQueryException(e);
4102+
}
4103+
}
4104+
4105+
@Override
4106+
public AuthRecipeUserInfo signUp_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con,
4107+
String userId, String email, String relyingPartyId)
4108+
throws StorageQueryException, TenantOrAppNotFoundException, DuplicateUserEmailException,
4109+
io.supertokens.pluginInterface.webauthn.exceptions.DuplicateUserIdException {
4110+
Connection sqlCon = (Connection) con.getConnection();
4111+
try {
4112+
return WebAuthNQueries.signUp_Transaction(this, sqlCon, tenantIdentifier, userId, email, relyingPartyId);
4113+
} catch (StorageTransactionLogicException stle) {
4114+
if (stle.actualException instanceof SQLException) {
4115+
ServerErrorMessage errorMessage = ((PSQLException) stle.actualException).getServerErrorMessage();
4116+
PostgreSQLConfig config = Config.getConfig(this);
4117+
4118+
if (isUniqueConstraintError(errorMessage, config.getWebAuthNUserToTenantTable(),"email")) {
4119+
throw new DuplicateUserEmailException();
4120+
} else if (isPrimaryKeyError(errorMessage, config.getWebAuthNUsersTable())
4121+
|| isPrimaryKeyError(errorMessage, config.getUsersTable())
4122+
|| isPrimaryKeyError(errorMessage, config.getWebAuthNUserToTenantTable())
4123+
|| isPrimaryKeyError(errorMessage, config.getAppIdToUserIdTable())) {
4124+
throw new io.supertokens.pluginInterface.webauthn.exceptions.DuplicateUserIdException();
4125+
} else if (isForeignKeyConstraintError(
4126+
errorMessage,
4127+
config.getAppsTable(),
4128+
"app_id")) {
4129+
throw new TenantOrAppNotFoundException(tenantIdentifier.toAppIdentifier());
4130+
} else if (isForeignKeyConstraintError(
4131+
errorMessage,
4132+
config.getTenantsTable(),
4133+
"tenant_id")) {
4134+
throw new TenantOrAppNotFoundException(tenantIdentifier);
4135+
}
4136+
}
4137+
4138+
throw new StorageQueryException(stle.actualException);
4139+
} catch (SQLException e) {
4140+
throw new StorageQueryException(e);
4141+
}
4142+
}
4143+
4144+
@Override
4145+
public AuthRecipeUserInfo getUserInfoByCredentialId_Transaction(TenantIdentifier tenantIdentifier,
4146+
TransactionConnection con, String credentialId)
4147+
throws StorageQueryException {
4148+
try {
4149+
Connection sqlCon = (Connection) con.getConnection();
4150+
return WebAuthNQueries.getUserInfoByCredentialId_Transaction(this, sqlCon, tenantIdentifier, credentialId);
4151+
} catch (SQLException e) {
4152+
throw new StorageQueryException(e);
4153+
}
4154+
}
4155+
4156+
@Override
4157+
public void updateCounter_Transaction(TenantIdentifier tenantIdentifier,
4158+
TransactionConnection con, String credentialId,
4159+
long counter) throws StorageQueryException {
4160+
try {
4161+
Connection sqlCon = (Connection) con.getConnection();
4162+
WebAuthNQueries.updateCounter_Transaction(this, sqlCon, tenantIdentifier, credentialId, counter);
4163+
} catch (SQLException e) {
4164+
throw new StorageQueryException(e);
4165+
}
4166+
}
4167+
4168+
@Override
4169+
public void addRecoverAccountToken(TenantIdentifier tenantIdentifier, AccountRecoveryTokenInfo accountRecoveryTokenInfo)
4170+
throws DuplicateRecoverAccountTokenException, StorageQueryException {
4171+
try {
4172+
WebAuthNQueries.addRecoverAccountToken(this, tenantIdentifier, accountRecoveryTokenInfo);
4173+
} catch (SQLException e) {
4174+
throw new StorageQueryException(e);
4175+
}
4176+
}
4177+
4178+
@Override
4179+
public void removeCredential(TenantIdentifier tenantIdentifier, String userId, String credentialId)
4180+
throws StorageQueryException, WebauthNCredentialNotExistsException {
4181+
try {
4182+
int rowsUpdated = WebAuthNQueries.removeCredential(this, tenantIdentifier, userId, credentialId);
4183+
if(rowsUpdated < 1) {
4184+
throw new WebauthNCredentialNotExistsException();
4185+
}
4186+
} catch (SQLException e) {
4187+
throw new StorageQueryException(e);
4188+
}
4189+
}
4190+
4191+
@Override
4192+
public void removeOptions(TenantIdentifier tenantIdentifier, String optionsId)
4193+
throws StorageQueryException, WebauthNOptionsNotExistsException {
4194+
try {
4195+
int rowsUpdated = WebAuthNQueries.removeOptions(this, tenantIdentifier, optionsId);
4196+
if(rowsUpdated < 1) {
4197+
throw new WebauthNOptionsNotExistsException();
4198+
}
4199+
} catch (SQLException e) {
4200+
throw new StorageQueryException(e);
4201+
}
4202+
}
4203+
4204+
@Override
4205+
public List<WebAuthNStoredCredential> listCredentialsForUser(TenantIdentifier tenantIdentifier, String userId)
4206+
throws StorageQueryException {
4207+
try {
4208+
return WebAuthNQueries.listCredentials(this, tenantIdentifier, userId);
4209+
} catch (SQLException e) {
4210+
throw new StorageQueryException(e);
4211+
}
4212+
}
4213+
4214+
@Override
4215+
public void updateUserEmail(TenantIdentifier tenantIdentifier, String userId, String newEmail)
4216+
throws StorageQueryException, io.supertokens.pluginInterface.webauthn.exceptions.UserIdNotFoundException,
4217+
DuplicateUserEmailException {
4218+
try {
4219+
WebAuthNQueries.updateUserEmail(this, tenantIdentifier, userId, newEmail);
4220+
} catch (StorageQueryException e) {
4221+
if (e.getCause() instanceof SQLException){
4222+
ServerErrorMessage errorMessage = ((PSQLException) e.getCause()).getServerErrorMessage();
4223+
PostgreSQLConfig config = Config.getConfig(this);
4224+
4225+
if (isUniqueConstraintError(errorMessage, config.getWebAuthNUserToTenantTable(),
4226+
"email")) {
4227+
throw new DuplicateUserEmailException();
4228+
} else if (isForeignKeyConstraintError(errorMessage,config.getWebAuthNUserToTenantTable(),"user_id")) {
4229+
throw new io.supertokens.pluginInterface.webauthn.exceptions.UserIdNotFoundException();
4230+
}
4231+
}
4232+
throw new StorageQueryException(e);
4233+
}
4234+
}
4235+
4236+
@Override
4237+
public void updateUserEmail_Transaction(TenantIdentifier tenantIdentifier, TransactionConnection con, String userId,
4238+
String newEmail)
4239+
throws StorageQueryException, io.supertokens.pluginInterface.webauthn.exceptions.UserIdNotFoundException,
4240+
DuplicateUserEmailException {
4241+
try {
4242+
Connection sqlCon = (Connection) con.getConnection();
4243+
WebAuthNQueries.updateUserEmail_Transaction(this, sqlCon, tenantIdentifier, userId, newEmail);
4244+
} catch (StorageQueryException e) {
4245+
if (e.getCause() instanceof SQLException){
4246+
ServerErrorMessage errorMessage = ((PSQLException) e.getCause()).getServerErrorMessage();
4247+
PostgreSQLConfig config = Config.getConfig(this);
4248+
4249+
if (isUniqueConstraintError(errorMessage, config.getWebAuthNUserToTenantTable(),
4250+
"email")) {
4251+
throw new DuplicateUserEmailException();
4252+
} else if (isForeignKeyConstraintError(errorMessage,config.getWebAuthNUserToTenantTable(),"user_id")) {
4253+
throw new io.supertokens.pluginInterface.webauthn.exceptions.UserIdNotFoundException();
4254+
}
4255+
}
4256+
throw new StorageQueryException(e);
4257+
}
4258+
}
4259+
4260+
@Override
4261+
public AccountRecoveryTokenInfo getAccountRecoveryTokenInfoByToken_Transaction(TenantIdentifier tenantIdentifier,
4262+
TransactionConnection con,
4263+
String token)
4264+
throws StorageQueryException {
4265+
4266+
Connection sqlCon = (Connection) con.getConnection();
4267+
try {
4268+
return WebAuthNQueries.getAccountRecoveryTokenInfoByToken_Transaction(this, tenantIdentifier, sqlCon, token);
4269+
} catch (SQLException e) {
4270+
throw new StorageQueryException(e);
4271+
}
4272+
}
4273+
4274+
@Override
4275+
public void deleteAccountRecoveryTokenByEmail_Transaction(TenantIdentifier tenantIdentifier,
4276+
TransactionConnection con, String email)
4277+
throws StorageQueryException {
4278+
Connection sqlCon = (Connection) con.getConnection();
4279+
try {
4280+
WebAuthNQueries.deleteAccountRecoveryTokenByEmail_Transaction(this, sqlCon, tenantIdentifier, email);
4281+
} catch (SQLException e) {
4282+
throw new StorageQueryException(e);
4283+
}
4284+
}
4285+
4286+
@Override
4287+
public void deleteExpiredAccountRecoveryTokens() throws StorageQueryException {
4288+
try {
4289+
WebAuthNQueries.deleteExpiredAccountRecoveryTokens(this);
4290+
} catch (SQLException e) {
4291+
throw new StorageQueryException(e);
4292+
}
4293+
}
4294+
4295+
@Override
4296+
public void deleteExpiredGeneratedOptions() throws StorageQueryException {
4297+
try {
4298+
WebAuthNQueries.deleteExpiredGeneratedOptions(this);
4299+
} catch (SQLException e) {
4300+
throw new StorageQueryException(e);
4301+
}
4302+
}
39534303
}

src/main/java/io/supertokens/storage/postgresql/config/PostgreSQLConfig.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,21 @@ public String getOAuthLogoutChallengesTable() {
462462
return addSchemaAndPrefixToTableName("oauth_logout_challenges");
463463
}
464464

465+
public String getWebAuthNUsersTable(){ return addSchemaAndPrefixToTableName("webauthn_users");}
466+
467+
public String getWebAuthNUserToTenantTable(){ return addSchemaAndPrefixToTableName("webauthn_user_to_tenant"); }
468+
469+
public String getWebAuthNGeneratedOptionsTable() { return addSchemaAndPrefixToTableName("webauthn_generated_options"); }
470+
471+
public String getWebAuthNCredentialsTable() { return addSchemaAndPrefixToTableName("webauthn_credentials"); }
472+
473+
public String getWebAuthNAccountRecoveryTokenTable() { return addSchemaAndPrefixToTableName("webauthn_account_recovery_tokens"); }
474+
465475
public String getBulkImportUsersTable() {
466476
return addSchemaAndPrefixToTableName("bulk_import_users");
467477
}
468478

479+
469480
private String addSchemaAndPrefixToTableName(String tableName) {
470481
return addSchemaToTableName(postgresql_table_names_prefix + tableName);
471482
}

0 commit comments

Comments
 (0)