diff --git a/src/WebAuthn.Net.Storage.SqlServer/README.md b/src/WebAuthn.Net.Storage.SqlServer/README.md index 3e89e2f..76efe2b 100644 --- a/src/WebAuthn.Net.Storage.SqlServer/README.md +++ b/src/WebAuthn.Net.Storage.SqlServer/README.md @@ -15,34 +15,36 @@ As the library is intended to be integrated into existing applications, they may ```tsql CREATE TABLE [CredentialRecords] ( - [Id] uniqueidentifier NOT NULL, - [RpId] nvarchar(256) NOT NULL, - [UserHandle] varbinary(128) NOT NULL, - [CredentialId] varbinary(1024) NOT NULL, - [Type] int NOT NULL, - [Kty] int NOT NULL, - [Alg] int NOT NULL, - [Ec2Crv] int NULL, - [Ec2X] varbinary(256) NULL, - [Ec2Y] varbinary(256) NULL, - [RsaModulusN] varbinary(1024) NULL, - [RsaExponentE] varbinary(32) NULL, - [OkpCrv] int NULL, - [OkpX] varbinary(32) NULL, - [SignCount] bigint NOT NULL, - [Transports] nvarchar(max) NOT NULL, - [UvInitialized] bit NOT NULL, - [BackupEligible] bit NOT NULL, - [BackupState] bit NOT NULL, - [AttestationObject] varbinary(max) NULL, - [AttestationClientDataJson] varbinary(max) NULL, - [Description] nvarchar(200) NULL, - [CreatedAtUnixTime] bigint NOT NULL, - [UpdatedAtUnixTime] bigint NOT NULL, + [Id] uniqueidentifier NOT NULL, + [RpId] nvarchar(256) NOT NULL, + [UserHandle] varbinary(128) NOT NULL, + [CredentialId] varbinary(1024) NOT NULL, + [Type] int NOT NULL, + [Kty] int NOT NULL, + [Alg] int NOT NULL, + [Ec2Crv] int NULL, + [Ec2X] varbinary(256) NULL, + [Ec2Y] varbinary(256) NULL, + [RsaModulusN] varbinary(1024) NULL, + [RsaExponentE] varbinary(32) NULL, + [OkpCrv] int NULL, + [OkpX] varbinary(32) NULL, + [SignCount] bigint NOT NULL, + [Transports] nvarchar(max) NOT NULL, + [UvInitialized] bit NOT NULL, + [BackupEligible] bit NOT NULL, + [BackupState] bit NOT NULL, + [AttestationObject] varbinary(max) NULL, + [AttestationClientDataJson] varbinary(max) NULL, + [Description] nvarchar(200) NULL, + [CreatedAtUnixTime] bigint NOT NULL, + [UpdatedAtUnixTime] bigint NOT NULL, CONSTRAINT [PK_CredentialRecords] PRIMARY KEY ([Id]) ); -ALTER TABLE [CredentialRecords] ADD CONSTRAINT [Transports should be formatted as JSON] CHECK (ISJSON(Transports)=1); -CREATE UNIQUE INDEX [IX_CredentialRecords_RpId_UserHandle_CredentialId] ON [CredentialRecords] ([RpId], [UserHandle], [CredentialId]); +ALTER TABLE [CredentialRecords] + ADD CONSTRAINT [Transports should be formatted as JSON] CHECK (ISJSON(Transports) = 1); +CREATE UNIQUE INDEX [IX_CredentialRecords_UserHandle_CredentialId_RpId] ON [CredentialRecords] ([UserHandle], [CredentialId], [RpId]); +CREATE UNIQUE INDEX [IX_CredentialRecords_CredentialId_RpId] ON [CredentialRecords] ([CredentialId], [RpId]); ``` ## Local dev environment diff --git a/src/WebAuthn.Net.Storage.SqlServer/Storage/DefaultSqlServerCredentialStorage.cs b/src/WebAuthn.Net.Storage.SqlServer/Storage/DefaultSqlServerCredentialStorage.cs index 45f5ea4..49ac670 100644 --- a/src/WebAuthn.Net.Storage.SqlServer/Storage/DefaultSqlServerCredentialStorage.cs +++ b/src/WebAuthn.Net.Storage.SqlServer/Storage/DefaultSqlServerCredentialStorage.cs @@ -46,8 +46,9 @@ public virtual async Task FindDescriptorsAsync( ArgumentNullException.ThrowIfNull(context); cancellationToken.ThrowIfCancellationRequested(); var dbPublicKeysEnumerable = await context.Connection.QueryAsync(new(@" -SELECT Type, CredentialId, Transports, CreatedAtUnixTime FROM CredentialRecords -WHERE RpId = @rpId AND UserHandle = @userHandle;", +SELECT Type, CredentialId, Transports, CreatedAtUnixTime +FROM CredentialRecords +WHERE UserHandle = @userHandle AND RpId = @rpId;", new { rpId, @@ -92,7 +93,7 @@ public virtual async Task FindDescriptorsAsync( var exisingId = await context.Connection.QuerySingleOrDefaultAsync(new(@" SELECT Id FROM CredentialRecords -WHERE RpId = @rpId AND UserHandle = @userHandle AND CredentialId = @credentialId;", +WHERE UserHandle = @userHandle AND CredentialId = @credentialId AND RpId = @rpId;", new { rpId, @@ -166,10 +167,9 @@ public virtual async Task SaveIfNotRegisteredForOtherUserAsync( cancellationToken.ThrowIfCancellationRequested(); var existingCount = await context.Connection.ExecuteScalarAsync(new( @" -SELECT COUNT(Id) FROM CredentialRecords -WHERE - RpId = @rpId - AND CredentialId = @credentialId;", +SELECT COUNT(CredentialId) +FROM CredentialRecords +WHERE CredentialId = @credentialId AND RpId = @rpId;", new { rpId = credential.RpId, @@ -288,11 +288,9 @@ public virtual async Task UpdateCredentialAsync( cancellationToken.ThrowIfCancellationRequested(); var recordIdToUpdate = await context.Connection.QuerySingleOrDefaultAsync(new( @" -SELECT Id FROM CredentialRecords -WHERE - RpId = @rpId - AND UserHandle = @userHandle - AND CredentialId = @credentialId;", +SELECT Id +FROM CredentialRecords +WHERE UserHandle = @userHandle AND CredentialId = @credentialId AND RpId = @rpId;", new { rpId = credential.RpId,