Skip to content

Commit 364564f

Browse files
authored
Raise authenticationFailed event when cert validation fails (#31370)
1 parent c660e9b commit 364564f

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

src/Security/Authentication/Certificate/src/CertificateAuthenticationHandler.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
7979
}
8080

8181
var result = await ValidateCertificateAsync(clientCertificate);
82+
83+
// Invoke the failed handler if validation failed, before updating the cache
84+
if (result.Failure != null)
85+
{
86+
var authenticationFailedContext = await HandleFailureAsync(result.Failure);
87+
if (authenticationFailedContext.Result != null)
88+
{
89+
result = authenticationFailedContext.Result;
90+
}
91+
}
92+
8293
if (_cache != null)
8394
{
8495
_cache.Put(Context, clientCertificate, result);
@@ -87,12 +98,7 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
8798
}
8899
catch (Exception ex)
89100
{
90-
var authenticationFailedContext = new CertificateAuthenticationFailedContext(Context, Scheme, Options)
91-
{
92-
Exception = ex
93-
};
94-
95-
await Events.AuthenticationFailed(authenticationFailedContext);
101+
var authenticationFailedContext = await HandleFailureAsync(ex);
96102
if (authenticationFailedContext.Result != null)
97103
{
98104
return authenticationFailedContext.Result;
@@ -102,6 +108,17 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
102108
}
103109
}
104110

111+
private async Task<CertificateAuthenticationFailedContext> HandleFailureAsync(Exception error)
112+
{
113+
var authenticationFailedContext = new CertificateAuthenticationFailedContext(Context, Scheme, Options)
114+
{
115+
Exception = error
116+
};
117+
118+
await Events.AuthenticationFailed(authenticationFailedContext);
119+
return authenticationFailedContext;
120+
}
121+
105122
private async Task<AuthenticateResult> ValidateCertificateAsync(X509Certificate2 clientCertificate)
106123
{
107124
// If we have a self signed cert, and they're not allowed, exit early and not bother with

src/Security/Authentication/JwtBearer/src/JwtBearerEvents.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
1212
public class JwtBearerEvents
1313
{
1414
/// <summary>
15-
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.
15+
/// Invoked if authentication fails during request processing. The exceptions will be re-thrown after this event unless suppressed.
1616
/// </summary>
1717
public Func<AuthenticationFailedContext, Task> OnAuthenticationFailed { get; set; } = context => Task.CompletedTask;
1818

src/Security/Authentication/test/CertificateTests.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,30 @@ public async Task VerifyUntrustedClientCertEndsUpInForbidden()
284284
var response = await server.CreateClient().GetAsync("https://example.com/");
285285
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
286286
}
287+
288+
[Fact]
289+
public async Task VerifyValidationFailureCanBeHandled()
290+
{
291+
var failCalled = false;
292+
using var host = await CreateHost(
293+
new CertificateAuthenticationOptions
294+
{
295+
Events = new CertificateAuthenticationEvents()
296+
{
297+
OnAuthenticationFailed = context =>
298+
{
299+
context.Fail("Validation failed: " + context.Exception);
300+
failCalled = true;
301+
return Task.CompletedTask;
302+
}
303+
}
304+
}, Certificates.SignedClient);
305+
306+
using var server = host.GetTestServer();
307+
var response = await server.CreateClient().GetAsync("https://example.com/");
308+
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
309+
Assert.True(failCalled);
310+
}
287311

288312
[Fact]
289313
public async Task VerifyClientCertWithUntrustedRootAndTrustedChainEndsUpInForbidden()
@@ -752,7 +776,6 @@ private static async Task<IHost> CreateHost(
752776

753777
await host.StartAsync();
754778

755-
756779
var server = host.GetTestServer();
757780
server.BaseAddress = baseAddress;
758781
return host;

0 commit comments

Comments
 (0)