I am testing a self-hosted Asp Net Core Web server (Kestrel), and I am struggling with the client authentication using self-signed certificates. This is my startup code
WebApplicationBuilder webBuilder = WebApplication.CreateBuilder();
var webHostBuilder = builder.WebHost;
X509Certificate2 rootCert = new X509Certificate2(hostCertFilePath, hostCertPassword);
webHostBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o =>
{
o.ServerCertificate = rootCert;
o.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
});
});
webHostBuilder.UseKestrel(o =>
{
o.Listen(IPAddress.Parse(myHttpsEndPointIpAddr), myHttpsEndPointPort,
listenOptions =>
{
listenOptions.UseHttps();
});
o.Listen(IPAddress.Parse(myHttpEndPointIpAddr), myHttpEndPointPort);
});
var services = webBuilder.Services;
services.AddTransient<MyCustomCertificateValidationService>();
services
.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.SelfSigned;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices
.GetService<MyCustomCertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
context.Success();
}
else
{
context.Fail("invalid cert");
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.Fail("invalid cert");
return Task.CompletedTask;
}
};
});
...
var app = webBuilder.Build();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
This my custom certification class
public class MyCustomCertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
// todo: check certificate thumbnail
return false;
}
}
But even if MyCustomCertificateValidationService has a method ValidateCertificate() that returns false, the controller method is still called when a client accesses the url with the route to the controller method. This is what is displayed in the log:
...
AspNetCore.Routing.EndpointRoutingMiddleware : Request matched endpoint ‘GetMyData…‘
AspNetCore.Authentication.Certificate.CertificateAuthenticationHandler : Certificate was not authenticated. Failure message: invalid cert
AspNetCore.Routing.EndpointMiddleware : Executing endpoint ‘GetMyData…‘
...
Any clue why the controller method is still called?
Of course you can do that. There is a handy way to implement your requirement using middleware for sure. Please try the code snippe below:
Http/Https Request Middleare Based On Environment:
Note: In application
request context
we are checking two important value, first if the request is secure meanscIsHttps
and theapplication environment
, inDevelopment
environment we will allowhttp
request. Therefore, other than,dev
or anyenv
based on our requirement we will rejecthttp
request.Register Middleware on Program.cs:
Note: Make sure you have followed the correct middleware order. In order to avoid short circuiting, you could place this middleware way down of your all current middleware.
Output: