Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
2 changes: 1 addition & 1 deletion src/Identity/Core/src/DefaultPasskeyHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ await VerifyClientDataAsync(
// NOTE: We simply fail the ceremony in this case.
if (authenticatorData.SignCount <= storedPasskey.SignCount)
{
throw PasskeyException.SignCountLessThanStoredSignCount();
throw PasskeyException.SignCountLessThanOrEqualToStoredSignCount();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Identity/Core/src/PasskeyExceptionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public static PasskeyException ExpectedBackupIneligibleCredential()
public static PasskeyException InvalidAssertionSignature()
=> new("The assertion signature was invalid.");

public static PasskeyException SignCountLessThanStoredSignCount()
public static PasskeyException SignCountLessThanOrEqualToStoredSignCount()
=> new("The authenticator's signature counter is unexpectedly less than or equal to the stored signature counter.");

public static PasskeyException InvalidAttestationObject(Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ public VersionTwoDbContext(DbContextOptions options)
}
}

public class VersionThreeDbContext : IdentityDbContext<IdentityUser, IdentityRole, string>
{
public VersionThreeDbContext(DbContextOptions options)
: base(options)
{
}
}

public class EmptyDbContext : IdentityDbContext<IdentityUser, IdentityRole, string>
{
public EmptyDbContext(DbContextOptions options)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Builder;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test;

public class VersionThreeSchemaTest : IClassFixture<ScratchDatabaseFixture>
{
private readonly ApplicationBuilder _builder;

public VersionThreeSchemaTest(ScratchDatabaseFixture fixture)
{
var services = new ServiceCollection();

services
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build())
.AddDbContext<VersionThreeDbContext>(o =>
o.UseSqlite(fixture.Connection)
.ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning)))
.AddIdentity<IdentityUser, IdentityRole>(o =>
{
// MaxKeyLength does not need to be set in version 3
o.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
})
.AddEntityFrameworkStores<VersionThreeDbContext>();

services.AddLogging();

_builder = new ApplicationBuilder(services.BuildServiceProvider());
var scope = _builder.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope();
var db = scope.ServiceProvider.GetRequiredService<VersionThreeDbContext>();
db.Database.EnsureCreated();
}

[Fact]
public void EnsureDefaultSchema()
{
using var scope = _builder.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope();
var db = scope.ServiceProvider.GetRequiredService<VersionThreeDbContext>();
VerifyVersion3Schema(db);
}

internal static void VerifyVersion3Schema(DbContext dbContext)
{
using var sqlConn = (SqliteConnection)dbContext.Database.GetDbConnection();
sqlConn.Open();
Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp",
"EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled",
"LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail"));
Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp"));
Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserRoles", "UserId", "RoleId"));
Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue"));
Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName"));
Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value"));
Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserPasskeys", "UserId", "CredentialId", "PublicKey", "Name", "CreatedAt",
"SignCount", "Transports", "IsUserVerified", "IsBackupEligible", "IsBackedUp", "AttestationObject",
"ClientDataJson"));

Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetUsers", 256, "UserName", "Email", "NormalizedUserName", "NormalizedEmail", "PhoneNumber"));
Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetRoles", 256, "Name", "NormalizedName"));
Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetUserLogins", 128, "LoginProvider", "ProviderKey"));
Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetUserTokens", 128, "LoginProvider", "Name"));

DbUtil.VerifyIndex(sqlConn, "AspNetRoles", "RoleNameIndex", isUnique: true);
DbUtil.VerifyIndex(sqlConn, "AspNetUsers", "UserNameIndex", isUnique: true);
DbUtil.VerifyIndex(sqlConn, "AspNetUsers", "EmailIndex");
}
}
1 change: 1 addition & 0 deletions src/Identity/Extensions.Core/src/UserManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2188,6 +2188,7 @@ public virtual Task<IList<UserPasskeyInfo>> GetPasskeysAsync(TUser user)
{
ThrowIfDisposed();
var passkeyStore = GetUserPasskeyStore();
ArgumentNullThrowHelper.ThrowIfNull(user);
ArgumentNullThrowHelper.ThrowIfNull(credentialId);

return passkeyStore.FindPasskeyAsync(user, credentialId, CancellationToken);
Expand Down
Loading
Loading