Skip to content

Commit 416f3f0

Browse files
authored
Merge pull request #88 from popicka70/master
Fix logout in NuGet
2 parents cd464e7 + a760519 commit 416f3f0

10 files changed

Lines changed: 56 additions & 46 deletions

MrWho.ClientAuth/MrWhoClientAuthBuilderExtensions.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@ public static AuthenticationBuilder AddMrWhoAuthentication(
3636
// Decide default require-https if not set
3737
bool requireHttps = options.RequireHttpsMetadata ?? options.Authority.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
3838

39-
// Configure authentication with a local cookie scheme and OIDC challenge scheme
39+
// Configure authentication with a local cookie scheme and OIDC challenge + sign-out scheme
4040
var builder = services.AddAuthentication(auth =>
4141
{
4242
auth.DefaultScheme = cookieScheme;
4343
auth.DefaultChallengeScheme = oidcScheme;
44+
auth.DefaultSignOutScheme = oidcScheme; // ensure SignOutAsync() triggers OIDC end-session
4445
})
4546
.AddCookie(cookieScheme, cookie =>
4647
{
@@ -69,6 +70,10 @@ public static AuthenticationBuilder AddMrWhoAuthentication(
6970
oidc.CallbackPath = options.CallbackPath;
7071
oidc.SignedOutCallbackPath = options.SignedOutCallbackPath;
7172
oidc.RemoteSignOutPath = options.RemoteSignOutPath;
73+
if (!string.IsNullOrWhiteSpace(options.SignedOutRedirectUri))
74+
{
75+
oidc.SignedOutRedirectUri = options.SignedOutRedirectUri;
76+
}
7277

7378
// Ensure Identity.Name and roles resolve using standard OIDC claims by default
7479
oidc.TokenValidationParameters = new TokenValidationParameters
@@ -147,6 +152,13 @@ public static AuthenticationBuilder AddMrWhoAuthentication(
147152
}
148153
return Task.CompletedTask;
149154
},
155+
OnRedirectToIdentityProviderForSignOut = ctx =>
156+
{
157+
var logger = ctx.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>()
158+
.CreateLogger("MrWho.ClientAuth.OIDC");
159+
logger.LogInformation("Initiating OIDC end-session for client_id={ClientId}. IdTokenHint? {HasHint}", ctx.Options.ClientId, !string.IsNullOrEmpty(ctx.ProtocolMessage.IdTokenHint));
160+
return Task.CompletedTask;
161+
},
150162
OnTokenResponseReceived = ctx =>
151163
{
152164
var logger = ctx.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>()
@@ -162,7 +174,6 @@ public static AuthenticationBuilder AddMrWhoAuthentication(
162174
var identity = ctx.Principal?.Identities?.FirstOrDefault();
163175
if (identity != null)
164176
{
165-
// If there's no "name" claim, try to synthesize one from preferred_username, email, then sub
166177
bool hasName = identity.HasClaim(c => c.Type == "name");
167178
if (!hasName)
168179
{

MrWho.ClientAuth/MrWhoClientAuthLoginLogoutEndpointExtensions.cs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ public static IEndpointConventionBuilder MapMrWhoLoginEndpoint(
4646
}
4747

4848
/// <summary>
49-
/// Maps /logout endpoint(s) that perform local cookie sign-out and, if configured, remote OIDC sign-out.
49+
/// Maps /logout endpoint(s) that perform local cookie sign-out and then remote OIDC end-session if configured.
5050
/// Supports both GET and POST. Query string: ?returnUrl=/relative/path (defaults to "/").
5151
/// </summary>
5252
/// <remarks>
5353
/// Sign-out flow:
5454
/// 1. Signs out the default authenticate scheme (cookie) if present.
55-
/// 2. Signs out using the default sign-out scheme; if none, tries default challenge scheme (OIDC) for upstream logout.
56-
/// 3. Redirects back to returnUrl afterwards.
55+
/// 2. Always attempts OIDC sign-out via the default sign-out scheme (or challenge scheme) to propagate logout server-side.
56+
/// 3. Redirects back to returnUrl afterwards (OIDC handler will handle its own redirect if configured).
5757
/// </remarks>
5858
public static IEndpointRouteBuilder MapMrWhoLogoutEndpoints(
5959
this IEndpointRouteBuilder endpoints,
@@ -85,16 +85,11 @@ async Task Handle(HttpContext context)
8585

8686
if (signOutScheme is not null)
8787
{
88-
// Avoid double sign-out if both point to same underlying scheme (e.g., only cookies).
89-
if (defaultAuth?.Name != signOutScheme.Name)
90-
{
91-
var props = new AuthenticationProperties { RedirectUri = returnUrl };
92-
await context.SignOutAsync(signOutScheme.Name, props);
93-
return; // Upstream handler will handle redirect.
94-
}
88+
var props = new AuthenticationProperties { RedirectUri = returnUrl };
89+
await context.SignOutAsync(signOutScheme.Name, props);
90+
return; // Upstream handler handles redirect/end-session.
9591
}
9692

97-
// Fallback local redirect.
9893
context.Response.Redirect(returnUrl);
9994
}
10095

MrWho.ClientAuth/MrWhoClientAuthOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ public sealed class MrWhoClientAuthOptions
8686
public string SignedOutCallbackPath { get; set; } = "/signout-callback-oidc";
8787
public string RemoteSignOutPath { get; set; } = "/signout-oidc";
8888

89+
/// <summary>
90+
/// Optional post logout redirect (sets ProtocolMessage.PostLogoutRedirectUri). If null, it is omitted.
91+
/// </summary>
92+
public string? SignedOutRedirectUri { get; set; }
93+
8994
/// <summary>
9095
/// Optional extra configuration hook for OpenIdConnectOptions.
9196
/// </summary>

MrWho/appsettings.Development.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,9 @@
3333
},
3434
"MrWho": {
3535
"CookieSeparationMode": "ByClient"
36-
}
36+
},
37+
"environmentVariables": {
38+
"GOOGLE_APPLICATION_CREDENTIALS": "C:\\etc\\secrets\\mrwho-1755324848344-21f187c4a986.json"
39+
},
40+
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel.googleapis.com"
3741
}

MrWhoAdmin.AppHost/AppHost.cs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,25 @@
44

55
var builder = DistributedApplication.CreateBuilder(args);
66

7-
// Aspire no longer provisions databases; we connect to an external persistent DB.
8-
9-
// Compute local full path to the GCP service account key for dev runs
10-
// NOTE: Do NOT commit keys to source control. Prefer secrets outside the repo in production.
11-
var credsRelative = Path.Combine("..", "MrWho", "etc", "secrets", "mrwho-1755324848344-21f187c4a986.json");
12-
var credsFullPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), credsRelative));
13-
var gcpProjectId = "mrwho-1755324848344";
14-
157
var mrWho = builder.AddProject<Projects.MrWho>("mrwho")
16-
.WithExternalHttpEndpoints()
17-
.WithEnvironment("GOOGLE_APPLICATION_CREDENTIALS", credsFullPath)
18-
.WithEnvironment("GOOGLE_CLOUD_PROJECT", gcpProjectId);
8+
.WithExternalHttpEndpoints();
199

2010
var adminWeb = builder.AddProject<Projects.MrWhoAdmin_Web>("webfrontend")
2111
.WithExternalHttpEndpoints()
2212
.WithHttpHealthCheck("/health")
2313
.WithReference(mrWho)
24-
.WaitFor(mrWho)
25-
.WithEnvironment("GOOGLE_APPLICATION_CREDENTIALS", credsFullPath)
26-
.WithEnvironment("GOOGLE_CLOUD_PROJECT", gcpProjectId);
14+
.WaitFor(mrWho);
2715

2816
var demo1 = builder.AddProject<Projects.MrWhoDemo1>("mrwhodemo1")
2917
.WithExternalHttpEndpoints()
3018
.WithHttpHealthCheck("/health")
3119
.WithReference(mrWho)
32-
.WaitFor(mrWho)
33-
.WithEnvironment("GOOGLE_APPLICATION_CREDENTIALS", credsFullPath)
34-
.WithEnvironment("GOOGLE_CLOUD_PROJECT", gcpProjectId);
20+
.WaitFor(mrWho);
3521

3622
var demoNuget = builder.AddProject<Projects.MrWhoDemoNuget>("mrwhodemonuget")
3723
.WithExternalHttpEndpoints()
3824
.WithHttpHealthCheck("/health")
3925
.WithReference(mrWho)
40-
.WaitFor(mrWho)
41-
.WithEnvironment("GOOGLE_APPLICATION_CREDENTIALS", credsFullPath)
42-
.WithEnvironment("GOOGLE_CLOUD_PROJECT", gcpProjectId);
26+
.WaitFor(mrWho);
4327

4428
builder.Build().Run();

MrWhoAdmin.AppHost/MrWhoAdmin.AppHost.csproj

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@
1010
<UserSecretsId>d7603390-f3d0-42d0-ad23-a0348219a61e</UserSecretsId>
1111
</PropertyGroup>
1212

13-
<ItemGroup>
14-
<Content Include="etc\secrets\mrwho-1755324848344-21f187c4a986.json">
15-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
16-
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
17-
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
18-
</Content>
19-
</ItemGroup>
20-
2113
<ItemGroup>
2214
<ProjectReference Include="..\MrWhoDemo1\MrWhoDemo1.csproj" />
2315
<ProjectReference Include="..\MrWho\MrWho.csproj" />

MrWhoAdmin.AppHost/appsettings.Development.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
},
88
"Database": {
99
"Provider": "PostgreSql" // SqlServer | PostgreSql | MySql | MariaDb
10-
}
10+
},
11+
"environmentVariables": {
12+
"GOOGLE_APPLICATION_CREDENTIALS": "C:\\etc\\secrets\\mrwho-1755324848344-21f187c4a986.json"
13+
},
14+
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel.googleapis.com"
1115
}

MrWhoDemo1/appsettings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@
55
"Microsoft.AspNetCore": "Warning"
66
}
77
},
8-
"AllowedHosts": "*"
8+
"AllowedHosts": "*",
9+
"environmentVariables": {
10+
"GOOGLE_APPLICATION_CREDENTIALS": "C:\\etc\\secrets\\mrwho-1755324848344-21f187c4a986.json"
11+
},
12+
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel.googleapis.com"
913
}

MrWhoDemoNuget/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
options.Authority = builder.Configuration["Authentication:Authority"] ?? "https://localhost:7113";
1212
options.ClientId = builder.Configuration["Authentication:ClientId"] ?? "mrwho_demo_nuget";
1313
options.ClientSecret = builder.Configuration["Authentication:ClientSecret"]; // null for public
14+
options.SaveTokens = true;
15+
options.SignedOutCallbackPath = "/signout-callback-oidc";
1416

1517
options.Scopes.Clear();
1618
options.Scopes.Add("openid");

MrWhoDemoNuget/appsettings.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@
66
}
77
},
88
"AllowedHosts": "*",
9-
"Authentication": {
9+
"AuthenticationX": {
1010
"Authority": "https://localhost:7113",
1111
"ClientId": "mrwho_demo1",
1212
"ClientSecret": "Demo1Secret2024!"
13-
}
13+
},
14+
"Authentication": {
15+
"Authority": "https://mrwho.onrender.com",
16+
"ClientId": "FeLineWeb",
17+
"ClientSecret": "poO8iCF80g8S_Dq95qMH6uqpWoxAmN_EtBxLeJTv7jw"
18+
},
19+
"environmentVariables": {
20+
"GOOGLE_APPLICATION_CREDENTIALS": "C:\\etc\\secrets\\mrwho-1755324848344-21f187c4a986.json"
21+
},
22+
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel.googleapis.com"
1423
}

0 commit comments

Comments
 (0)