Skip to content

Commit 9b0dbf7

Browse files
committed
Completed EFCore Credential Store
1 parent 7424945 commit 9b0dbf7

31 files changed

Lines changed: 518 additions & 424 deletions

src/CodeBeam.UltimateAuth.Server/Flows/Login/LoginOrchestrator.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ namespace CodeBeam.UltimateAuth.Server.Flows;
2121
internal sealed class LoginOrchestrator : ILoginOrchestrator
2222
{
2323
private readonly ILoginIdentifierResolver _identifierResolver;
24-
private readonly ICredentialStore _credentialStore; // authentication
25-
private readonly ICredentialValidator _credentialValidator;
24+
private readonly IEnumerable<ICredentialProvider> _credentialProviders; // authentication
2625
private readonly IUserRuntimeStateProvider _users; // eligible
2726
private readonly ILoginAuthority _authority;
2827
private readonly ISessionOrchestrator _sessionOrchestrator;
@@ -35,8 +34,7 @@ internal sealed class LoginOrchestrator : ILoginOrchestrator
3534

3635
public LoginOrchestrator(
3736
ILoginIdentifierResolver identifierResolver,
38-
ICredentialStore credentialStore,
39-
ICredentialValidator credentialValidator,
37+
IEnumerable<ICredentialProvider> credentialProviders,
4038
IUserRuntimeStateProvider users,
4139
ILoginAuthority authority,
4240
ISessionOrchestrator sessionOrchestrator,
@@ -48,8 +46,7 @@ public LoginOrchestrator(
4846
IOptions<UAuthServerOptions> options)
4947
{
5048
_identifierResolver = identifierResolver;
51-
_credentialStore = credentialStore;
52-
_credentialValidator = credentialValidator;
49+
_credentialProviders = credentialProviders;
5350
_users = users;
5451
_authority = authority;
5552
_sessionOrchestrator = sessionOrchestrator;
@@ -99,21 +96,24 @@ public async Task<LoginResult> LoginAsync(AuthFlowContext flow, LoginRequest req
9996
return LoginResult.Failed(AuthFailureReason.LockedOut, factorState.LockedUntil, 0);
10097
}
10198

102-
var credentials = await _credentialStore.GetByUserAsync(request.Tenant, userKey.Value, ct);
103-
104-
// TODO: Add .Where(c => c.Type == request.Factor) when we support multiple factors per user
105-
foreach (var credential in credentials.OfType<ICredentialDescriptor>())
99+
foreach (var provider in _credentialProviders)
106100
{
107-
if (!credential.Security.IsUsable(now))
108-
continue;
109-
110-
var result = await _credentialValidator.ValidateAsync((ICredential)credential, request.Secret, ct);
101+
var credentials = await provider.GetByUserAsync(request.Tenant, userKey.Value, ct);
111102

112-
if (result.IsValid)
103+
foreach (var credential in credentials)
113104
{
114-
credentialsValid = true;
115-
break;
105+
if (credential.IsDeleted || !credential.Security.IsUsable(now))
106+
continue;
107+
108+
if (await provider.ValidateAsync(credential, request.Secret, ct))
109+
{
110+
credentialsValid = true;
111+
break;
112+
}
116113
}
114+
115+
if (credentialsValid)
116+
break;
117117
}
118118
}
119119
}

src/credentials/CodeBeam.UltimateAuth.Credentials.Contracts/Dtos/CredentialSecurityState.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public sealed class CredentialSecurityState
99
public Guid SecurityStamp { get; }
1010

1111
public bool IsRevoked => RevokedAt != null;
12-
public bool IsExpired => ExpiresAt != null;
12+
public bool IsExpired(DateTimeOffset now) => ExpiresAt != null && ExpiresAt <= now;
1313

1414
public CredentialSecurityState(
1515
DateTimeOffset? revokedAt = null,
@@ -26,7 +26,7 @@ public CredentialSecurityStatus Status(DateTimeOffset now)
2626
if (RevokedAt is not null)
2727
return CredentialSecurityStatus.Revoked;
2828

29-
if (ExpiresAt is not null && ExpiresAt <= now)
29+
if (IsExpired(now))
3030
return CredentialSecurityStatus.Expired;
3131

3232
return CredentialSecurityStatus.Active;

src/credentials/CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore/Abstractions/CredentialUserMapping.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/credentials/CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore/CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
<ItemGroup>
2727
<ProjectReference Include="..\..\CodeBeam.UltimateAuth.Core\CodeBeam.UltimateAuth.Core.csproj" />
28+
<ProjectReference Include="..\..\persistence\CodeBeam.UltimateAuth.EntityFrameworkCore.Abstractions\CodeBeam.UltimateAuth.EntityFrameworkCore.Abstractions.csproj" />
2829
<ProjectReference Include="..\CodeBeam.UltimateAuth.Credentials.Contracts\CodeBeam.UltimateAuth.Credentials.Contracts.csproj" />
2930
<ProjectReference Include="..\CodeBeam.UltimateAuth.Credentials.Reference\CodeBeam.UltimateAuth.Credentials.Reference.csproj" />
3031
<ProjectReference Include="..\CodeBeam.UltimateAuth.Credentials\CodeBeam.UltimateAuth.Credentials.csproj" />

src/credentials/CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore/Configuration/ConventionResolver.cs

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/credentials/CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore/Configuration/CredentialUserMappingBuilder.cs

Lines changed: 0 additions & 74 deletions
This file was deleted.

src/credentials/CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore/Configuration/CredentialUserMappingOptions.cs

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using CodeBeam.UltimateAuth.Core.Domain;
2+
using CodeBeam.UltimateAuth.Core.MultiTenancy;
3+
using CodeBeam.UltimateAuth.Credentials.Contracts;
4+
using CodeBeam.UltimateAuth.EntityFrameworkCore;
5+
using Microsoft.EntityFrameworkCore;
6+
7+
namespace CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore;
8+
9+
internal sealed class UAuthCredentialDbContext : DbContext
10+
{
11+
public DbSet<PasswordCredentialProjection> PasswordCredentials => Set<PasswordCredentialProjection>();
12+
13+
private readonly TenantContext _tenant;
14+
15+
public UAuthCredentialDbContext(DbContextOptions<UAuthCredentialDbContext> options, TenantContext tenant)
16+
: base(options)
17+
{
18+
_tenant = tenant;
19+
}
20+
21+
protected override void OnModelCreating(ModelBuilder b)
22+
{
23+
ConfigurePasswordCredential(b);
24+
}
25+
26+
private void ConfigurePasswordCredential(ModelBuilder b)
27+
{
28+
b.Entity<PasswordCredentialProjection>(e =>
29+
{
30+
e.HasKey(x => x.Id);
31+
32+
e.Property(x => x.Version).IsConcurrencyToken();
33+
34+
e.Property(x => x.Tenant)
35+
.HasConversion(
36+
v => v.Value,
37+
v => TenantKey.FromInternal(v))
38+
.HasMaxLength(128)
39+
.IsRequired();
40+
41+
e.Property(x => x.UserKey)
42+
.HasConversion(
43+
v => v.Value,
44+
v => UserKey.FromString(v))
45+
.HasMaxLength(128)
46+
.IsRequired();
47+
48+
e.Property(x => x.SecretHash)
49+
.HasMaxLength(512)
50+
.IsRequired();
51+
52+
e.Property(x => x.SecurityStamp).IsRequired();
53+
e.Property(x => x.RevokedAt);
54+
e.Property(x => x.ExpiresAt);
55+
e.Property(x => x.LastUsedAt);
56+
e.Property(x => x.Source).HasMaxLength(128);
57+
e.Property(x => x.CreatedAt).IsRequired();
58+
e.Property(x => x.UpdatedAt);
59+
e.Property(x => x.DeletedAt);
60+
61+
e.HasIndex(x => new { x.Tenant, x.Id }).IsUnique();
62+
e.HasIndex(x => new { x.Tenant, x.UserKey });
63+
e.HasIndex(x => new { x.Tenant, x.UserKey, x.DeletedAt });
64+
e.HasIndex(x => new { x.Tenant, x.RevokedAt });
65+
e.HasIndex(x => new { x.Tenant, x.ExpiresAt });
66+
67+
e.HasQueryFilter(x => _tenant.IsGlobal || x.Tenant == _tenant.Tenant);
68+
});
69+
}
70+
}

src/credentials/CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore/EfCoreAuthUser.cs

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using CodeBeam.UltimateAuth.Credentials.Reference;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.Extensions.DependencyInjection;
4+
5+
namespace CodeBeam.UltimateAuth.Credentials.EntityFrameworkCore;
6+
7+
public static class ServiceCollectionExtensions
8+
{
9+
public static IServiceCollection AddUltimateAuthEntityFrameworkCoreCredentials(this IServiceCollection services, Action<DbContextOptionsBuilder> configureDb)
10+
{
11+
services.AddDbContextPool<UAuthCredentialDbContext>(configureDb);
12+
services.AddScoped<IPasswordCredentialStore, EfCorePasswordCredentialStore>();
13+
return services;
14+
}
15+
}

0 commit comments

Comments
 (0)