Skip to content

Commit 0dfd01b

Browse files
committed
Fail-Fast Strategy & Options Improvement
1 parent cd6331b commit 0dfd01b

File tree

11 files changed

+262
-4
lines changed

11 files changed

+262
-4
lines changed

samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/CodeBeam.UltimateAuth.Sample.BlazorServer.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net10.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Version>0.0.1-preview</Version>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.1" />
11+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" />
1212
<PackageReference Include="MudBlazor" Version="9.0.0-preview.1" />
1313
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="9.0.0-preview.2" />
1414
<PackageReference Include="Scalar.AspNetCore" Version="2.12.18" />

samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454

5555
builder.Services.AddUltimateAuth();
5656

57-
builder.Services.AddUltimateAuthServer(o => {
57+
builder.Services.AddUltimateAuthServer(o =>
58+
{
5859
o.Diagnostics.EnableRefreshHeaders = true;
5960
//o.Session.MaxLifetime = TimeSpan.FromSeconds(32);
6061
//o.Session.TouchInterval = TimeSpan.FromSeconds(9);

src/CodeBeam.UltimateAuth.Core/Extensions/ServiceCollectionExtensions.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ public static class ServiceCollectionExtensions
3333
/// </summary>
3434
public static IServiceCollection AddUltimateAuth(this IServiceCollection services, IConfiguration configurationSection)
3535
{
36-
services.Configure<UAuthOptions>(configurationSection);
36+
services.AddOptions<UAuthOptions>()
37+
.Configure<DirectCoreConfigurationMarker>((options, marker) =>
38+
{
39+
marker.MarkConfigured();
40+
configurationSection.Bind(options);
41+
});
3742
return services.AddUltimateAuthInternal();
3843
}
3944

@@ -45,6 +50,12 @@ public static IServiceCollection AddUltimateAuth(this IServiceCollection service
4550
public static IServiceCollection AddUltimateAuth(this IServiceCollection services, Action<UAuthOptions> configure)
4651
{
4752
services.Configure(configure);
53+
services.AddOptions<UAuthOptions>()
54+
.Configure<DirectCoreConfigurationMarker>((options, marker) =>
55+
{
56+
marker.MarkConfigured();
57+
configure(options);
58+
});
4859
return services.AddUltimateAuthInternal();
4960
}
5061

@@ -74,6 +85,10 @@ public static IServiceCollection AddUltimateAuth(this IServiceCollection service
7485
/// </summary>
7586
private static IServiceCollection AddUltimateAuthInternal(this IServiceCollection services)
7687
{
88+
services.TryAddSingleton<DirectCoreConfigurationMarker>();
89+
services.AddSingleton<IPostConfigureOptions<UAuthOptions>, UAuthOptionsPostConfigureGuard>();
90+
91+
7792
services.AddSingleton<IValidateOptions<UAuthOptions>, UAuthOptionsValidator>();
7893
services.AddSingleton<IValidateOptions<UAuthSessionOptions>, UAuthSessionOptionsValidator>();
7994
services.AddSingleton<IValidateOptions<UAuthTokenOptions>, UAuthTokenOptionsValidator>();
@@ -87,6 +102,32 @@ private static IServiceCollection AddUltimateAuthInternal(this IServiceCollectio
87102
services.TryAddSingleton<IUAuthProductInfoProvider, UAuthProductInfoProvider>();
88103
services.TryAddSingleton<SeedRunner>();
89104

105+
//services.PostConfigure<UAuthOptions>(options =>
106+
//{
107+
// var hasRuntimeMarker = services.Any(sd => sd.ServiceType == typeof(IUAuthRuntimeMarker));
108+
109+
// if (hasRuntimeMarker && options.AllowDirectCoreConfiguration)
110+
// {
111+
// throw new InvalidOperationException(
112+
// "Direct core configuration is not allowed in server-hosted applications. " +
113+
// "Configure authentication policies via AddUltimateAuthServer instead.");
114+
// }
115+
//});
116+
117+
//services.PostConfigure<UAuthOptions, DirectCoreConfigurationMarker>(
118+
//(options, marker) =>
119+
//{
120+
// if (!options.AllowDirectCoreConfiguration && marker.IsConfigured)
121+
// {
122+
// throw new InvalidOperationException(
123+
// "Direct core configuration is not allowed. " +
124+
// "Set AllowDirectCoreConfiguration = true only for advanced, non-server scenarios, " +
125+
// "or configure authentication policies via AddUltimateAuthServer.");
126+
// }
127+
//});
128+
129+
130+
90131
return services;
91132
}
92133
}

src/CodeBeam.UltimateAuth.Core/Options/UAuthOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ namespace CodeBeam.UltimateAuth.Core.Options;
1313
/// </summary>
1414
public sealed class UAuthOptions
1515
{
16+
public bool AllowDirectCoreConfiguration { get; set; } = false;
17+
1618
/// <summary>
1719
/// Configuration settings for interactive login flows,
1820
/// including lockout thresholds and failed-attempt policies.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using CodeBeam.UltimateAuth.Core.Runtime;
2+
using Microsoft.Extensions.Options;
3+
4+
namespace CodeBeam.UltimateAuth.Core.Options;
5+
6+
internal sealed class UAuthOptionsPostConfigureGuard : IPostConfigureOptions<UAuthOptions>
7+
{
8+
private readonly DirectCoreConfigurationMarker _directConfigMarker;
9+
private readonly IEnumerable<IUAuthRuntimeMarker> _runtimeMarkers;
10+
11+
public UAuthOptionsPostConfigureGuard(DirectCoreConfigurationMarker directConfigMarker, IEnumerable<IUAuthRuntimeMarker> runtimeMarkers)
12+
{
13+
_directConfigMarker = directConfigMarker;
14+
_runtimeMarkers = runtimeMarkers;
15+
}
16+
17+
public void PostConfigure(string? name, UAuthOptions options)
18+
{
19+
var hasServerRuntime = _runtimeMarkers.Any();
20+
21+
if (hasServerRuntime && _directConfigMarker.IsConfigured)
22+
{
23+
throw new InvalidOperationException(
24+
"Direct core configuration is not allowed in server-hosted applications. " +
25+
"Configure authentication policies via AddUltimateAuthServer instead.");
26+
}
27+
28+
if (!hasServerRuntime && !_directConfigMarker.IsConfigured && options.AllowDirectCoreConfiguration == false)
29+
{
30+
return;
31+
}
32+
33+
if (!hasServerRuntime && _directConfigMarker.IsConfigured && options.AllowDirectCoreConfiguration == false)
34+
{
35+
throw new InvalidOperationException(
36+
"Direct core configuration is not allowed. " +
37+
"Set AllowDirectCoreConfiguration = true only for advanced, non-server scenarios.");
38+
}
39+
}
40+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace CodeBeam.UltimateAuth.Core.Runtime;
2+
3+
/// <summary>
4+
/// Internal marker indicating that UAuthOptions
5+
/// were configured directly by the application.
6+
/// </summary>
7+
internal sealed class DirectCoreConfigurationMarker
8+
{
9+
public bool IsConfigured { get; private set; }
10+
11+
public void MarkConfigured()
12+
{
13+
IsConfigured = true;
14+
}
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace CodeBeam.UltimateAuth.Core.Runtime;
2+
3+
/// <summary>
4+
/// Marker interface indicating that UltimateAuth is running in a specific runtime context (e.g. server-hosted).
5+
/// Implementations must be provided by integration layers such as UltimateAuth.Server.
6+
/// </summary>
7+
public interface IUAuthRuntimeMarker
8+
{
9+
}

src/CodeBeam.UltimateAuth.Server/Extensions/ServiceCollectionExtensions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using CodeBeam.UltimateAuth.Core.Infrastructure;
77
using CodeBeam.UltimateAuth.Core.MultiTenancy;
88
using CodeBeam.UltimateAuth.Core.Options;
9+
using CodeBeam.UltimateAuth.Core.Runtime;
910
using CodeBeam.UltimateAuth.Credentials;
1011
using CodeBeam.UltimateAuth.Policies.Abstractions;
1112
using CodeBeam.UltimateAuth.Policies.Defaults;
@@ -19,6 +20,7 @@
1920
using CodeBeam.UltimateAuth.Server.Infrastructure;
2021
using CodeBeam.UltimateAuth.Server.MultiTenancy;
2122
using CodeBeam.UltimateAuth.Server.Options;
23+
using CodeBeam.UltimateAuth.Server.Runtime;
2224
using CodeBeam.UltimateAuth.Server.Services;
2325
using CodeBeam.UltimateAuth.Server.Stores;
2426
using Microsoft.Extensions.Configuration;
@@ -67,6 +69,8 @@ public static IServiceCollection AddUltimateAuthServer(this IServiceCollection s
6769

6870
private static IServiceCollection AddUltimateAuthServerInternal(this IServiceCollection services)
6971
{
72+
services.AddSingleton<IUAuthRuntimeMarker, ServerRuntimeMarker>();
73+
7074
services.TryAddSingleton<IOpaqueTokenGenerator, OpaqueTokenGenerator>();
7175
services.TryAddSingleton<IJwtTokenGenerator,JwtTokenGenerator>();
7276
services.TryAddSingleton<IJwtSigningKeyProvider, DevelopmentJwtSigningKeyProvider>();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using CodeBeam.UltimateAuth.Core.Runtime;
2+
3+
namespace CodeBeam.UltimateAuth.Server.Runtime;
4+
5+
internal sealed class ServerRuntimeMarker : IUAuthRuntimeMarker
6+
{
7+
}

src/CodeBeam.UltimateAuth.Server/ProductInfo/UAuthServerProductInfo.cs renamed to src/CodeBeam.UltimateAuth.Server/Runtime/UAuthServerProductInfo.cs

File renamed without changes.

0 commit comments

Comments
 (0)