Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore;

internal static class IdentityUserPasskeyExtensions
{
extension<TKey>(IdentityUserPasskey<TKey> passkey)
where TKey : IEquatable<TKey>
{
public void UpdateFromUserPasskeyInfo(UserPasskeyInfo passkeyInfo)
{
passkey.Data.Name = passkeyInfo.Name;
passkey.Data.SignCount = passkeyInfo.SignCount;
passkey.Data.IsBackedUp = passkeyInfo.IsBackedUp;
passkey.Data.IsUserVerified = passkeyInfo.IsUserVerified;
}

public UserPasskeyInfo ToUserPasskeyInfo()
=> new(
passkey.CredentialId,
passkey.Data.PublicKey,
passkey.Data.CreatedAt,
passkey.Data.SignCount,
passkey.Data.Transports,
passkey.Data.IsUserVerified,
passkey.Data.IsBackupEligible,
passkey.Data.IsBackedUp,
passkey.Data.AttestationObject,
passkey.Data.ClientDataJson)
{
Name = passkey.Data.Name
};
}
}
40 changes: 4 additions & 36 deletions src/Identity/EntityFrameworkCore/src/UserOnlyStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,10 +625,7 @@ public virtual async Task AddOrUpdatePasskeyAsync(TUser user, UserPasskeyInfo pa
var userPasskey = await FindUserPasskeyByIdAsync(passkey.CredentialId, cancellationToken).ConfigureAwait(false);
if (userPasskey != null)
{
userPasskey.Data.Name = passkey.Name;
userPasskey.Data.SignCount = passkey.SignCount;
userPasskey.Data.IsBackedUp = passkey.IsBackedUp;
userPasskey.Data.IsUserVerified = passkey.IsUserVerified;
userPasskey.UpdateFromUserPasskeyInfo(passkey);
UserPasskeys.Update(userPasskey);
}
else
Expand All @@ -655,20 +652,7 @@ public virtual async Task<IList<UserPasskeyInfo>> GetPasskeysAsync(TUser user, C
var userId = user.Id;
var passkeys = await UserPasskeys
.Where(p => p.UserId.Equals(userId))
.Select(p => new UserPasskeyInfo(
p.CredentialId,
p.Data.PublicKey,
p.Data.CreatedAt,
p.Data.SignCount,
p.Data.Transports,
p.Data.IsUserVerified,
p.Data.IsBackupEligible,
p.Data.IsBackedUp,
p.Data.AttestationObject,
p.Data.ClientDataJson)
{
Name = p.Data.Name,
})
.Select(p => p.ToUserPasskeyInfo())
.ToListAsync(cancellationToken)
.ConfigureAwait(false);

Expand Down Expand Up @@ -708,26 +692,10 @@ public virtual async Task<IList<UserPasskeyInfo>> GetPasskeysAsync(TUser user, C
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
ArgumentNullException.ThrowIfNull(user);
ArgumentNullException.ThrowIfNull(credentialId);

var passkey = await FindUserPasskeyAsync(user.Id, credentialId, cancellationToken).ConfigureAwait(false);
if (passkey != null)
{
return new UserPasskeyInfo(
passkey.CredentialId,
passkey.Data.PublicKey,
passkey.Data.CreatedAt,
passkey.Data.SignCount,
passkey.Data.Transports,
passkey.Data.IsUserVerified,
passkey.Data.IsBackupEligible,
passkey.Data.IsBackedUp,
passkey.Data.AttestationObject,
passkey.Data.ClientDataJson)
{
Name = passkey.Data.Name,
};
}
return null;
return passkey?.ToUserPasskeyInfo();
}

/// <summary>
Expand Down
39 changes: 4 additions & 35 deletions src/Identity/EntityFrameworkCore/src/UserStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -770,9 +770,7 @@ public virtual async Task AddOrUpdatePasskeyAsync(TUser user, UserPasskeyInfo pa
var userPasskey = await FindUserPasskeyByIdAsync(passkey.CredentialId, cancellationToken).ConfigureAwait(false);
if (userPasskey != null)
{
userPasskey.Data.SignCount = passkey.SignCount;
userPasskey.Data.IsBackedUp = passkey.IsBackedUp;
userPasskey.Data.IsUserVerified = passkey.IsUserVerified;
userPasskey.UpdateFromUserPasskeyInfo(passkey);
UserPasskeys.Update(userPasskey);
}
else
Expand All @@ -799,20 +797,7 @@ public virtual async Task<IList<UserPasskeyInfo>> GetPasskeysAsync(TUser user, C
var userId = user.Id;
var passkeys = await UserPasskeys
.Where(p => p.UserId.Equals(userId))
.Select(p => new UserPasskeyInfo(
p.CredentialId,
p.Data.PublicKey,
p.Data.CreatedAt,
p.Data.SignCount,
p.Data.Transports,
p.Data.IsUserVerified,
p.Data.IsBackupEligible,
p.Data.IsBackedUp,
p.Data.AttestationObject,
p.Data.ClientDataJson)
{
Name = p.Data.Name
})
.Select(p => p.ToUserPasskeyInfo())
.ToListAsync(cancellationToken)
.ConfigureAwait(false);

Expand Down Expand Up @@ -851,27 +836,11 @@ public virtual async Task<IList<UserPasskeyInfo>> GetPasskeysAsync(TUser user, C
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
ArgumentNullException.ThrowIfNull(user);
ArgumentNullException.ThrowIfNull(credentialId);

var passkey = await FindUserPasskeyAsync(user.Id, credentialId, cancellationToken).ConfigureAwait(false);
if (passkey != null)
{
return new UserPasskeyInfo(
passkey.CredentialId,
passkey.Data.PublicKey,
passkey.Data.CreatedAt,
passkey.Data.SignCount,
passkey.Data.Transports,
passkey.Data.IsUserVerified,
passkey.Data.IsBackupEligible,
passkey.Data.IsBackedUp,
passkey.Data.AttestationObject,
passkey.Data.ClientDataJson)
{
Name = passkey.Data.Name
};
}
return null;
return passkey?.ToUserPasskeyInfo();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,31 @@

using System.Data.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test;

public class InMemoryContext :
InMemoryContext<IdentityUser, IdentityRole, string>
{
private InMemoryContext(DbConnection connection) : base(connection)
private InMemoryContext(DbConnection connection, IServiceProvider serviceProvider) : base(connection, serviceProvider)
{ }

public static new InMemoryContext Create(DbConnection connection)
=> Initialize(new InMemoryContext(connection));
public static new InMemoryContext Create(DbConnection connection, IServiceCollection services = null)
{
services = ConfigureDbServices(services);
return Initialize(new InMemoryContext(connection, services.BuildServiceProvider()));
}

public static IServiceCollection ConfigureDbServices(IServiceCollection services = null)
{
services ??= new ServiceCollection();
services.Configure<IdentityOptions>(options =>
{
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
});
return services;
}

public static TContext Initialize<TContext>(TContext context) where TContext : DbContext
{
Expand All @@ -28,17 +42,25 @@ public class InMemoryContext<TUser> :
where TUser : IdentityUser
{
private readonly DbConnection _connection;
private readonly IServiceProvider _serviceProvider;

private InMemoryContext(DbConnection connection)
private InMemoryContext(DbConnection connection, IServiceProvider serviceProvider)
{
_connection = connection;
_serviceProvider = serviceProvider;
}

public static InMemoryContext<TUser> Create(DbConnection connection)
=> InMemoryContext.Initialize(new InMemoryContext<TUser>(connection));
public static InMemoryContext<TUser> Create(DbConnection connection, IServiceCollection services = null)
{
services = InMemoryContext.ConfigureDbServices(services);
return InMemoryContext.Initialize(new InMemoryContext<TUser>(connection, services.BuildServiceProvider()));
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite(_connection);
{
optionsBuilder.UseSqlite(_connection);
optionsBuilder.UseApplicationServiceProvider(_serviceProvider);
}
}

public class InMemoryContext<TUser, TRole, TKey> : IdentityDbContext<TUser, TRole, TKey>
Expand All @@ -47,17 +69,25 @@ public class InMemoryContext<TUser, TRole, TKey> : IdentityDbContext<TUser, TRol
where TKey : IEquatable<TKey>
{
private readonly DbConnection _connection;
private readonly IServiceProvider _serviceProvider;

protected InMemoryContext(DbConnection connection)
protected InMemoryContext(DbConnection connection, IServiceProvider serviceProvider)
{
_connection = connection;
_serviceProvider = serviceProvider;
}

public static InMemoryContext<TUser, TRole, TKey> Create(DbConnection connection)
=> InMemoryContext.Initialize(new InMemoryContext<TUser, TRole, TKey>(connection));
public static InMemoryContext<TUser, TRole, TKey> Create(DbConnection connection, IServiceCollection services = null)
{
services = InMemoryContext.ConfigureDbServices(services);
return InMemoryContext.Initialize(new InMemoryContext<TUser, TRole, TKey>(connection, services.BuildServiceProvider()));
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite(_connection);
{
optionsBuilder.UseSqlite(_connection);
optionsBuilder.UseApplicationServiceProvider(_serviceProvider);
}
}

public abstract class InMemoryContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public InMemoryEFUserStoreTestWithGenerics(InMemoryDatabaseFixture fixture)

var services = new ServiceCollection();
services.AddHttpContextAccessor();
services.Configure<IdentityOptions>(options =>
{
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
});
services.AddDbContext<InMemoryContextWithGenerics>(
options => options
.UseSqlite(_fixture.Connection)
Expand Down
5 changes: 5 additions & 0 deletions src/Identity/EntityFrameworkCore/test/EF.Test/DbUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public static IServiceCollection ConfigureDbServices<TContext>(
.UseSqlite(connection);
});

services.Configure<IdentityOptions>(options =>
{
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
});

return services;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ protected virtual void SetupAddIdentity(IServiceCollection services)
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.User.AllowedUserNameCharacters = null;
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
})
.AddRoles<TRole>()
.AddDefaultTokenProviders()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ protected override void SetupAddIdentity(IServiceCollection services)
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.User.AllowedUserNameCharacters = null;
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
})
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<TestDbContext>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ public async Task FindByEmailThrowsWithTwoUsersWithSameEmail()
userB.Email = "dupe@dupe.com";
IdentityResultAssert.IsSuccess(await manager.CreateAsync(userB, "password"));
await Assert.ThrowsAsync<InvalidOperationException>(async () => await manager.FindByEmailAsync("dupe@dupe.com"));

}

[ConditionalFact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Data.Common;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test;

Expand All @@ -23,7 +24,14 @@ public ScratchDatabaseFixture()
}

private DbContext CreateEmptyContext()
=> new DbContext(new DbContextOptionsBuilder().UseSqlite(_connection).Options);
{
var services = new ServiceCollection();
services.Configure<IdentityOptions>(options => options.Stores.SchemaVersion = IdentitySchemaVersions.Version3);
return new DbContext(new DbContextOptionsBuilder()
.UseSqlite(_connection)
.UseApplicationServiceProvider(services.BuildServiceProvider())
.Options);
}

public DbConnection Connection => _connection;

Expand Down
Loading
Loading