I am building a small feature in ASP.NET Core Certificate authentication as given in official docs.
Note: I am not building APIs, I am just trying to secure some Action methods of some controllers so that these secured action methods are opened only when the client has the client certificate.
The below image shows that I am able to secure the Index action method which now requires client certificate. Other action method which is Privacy does not require client certificate. The result is that Index action does opens in browser (403 error is received) but Privacy action is opened up in browser
Full Codes
1. Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o =>
o.ClientCertificateMode =
ClientCertificateMode.RequireCertificate);
});
});
2. Startup.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
context.Success();
}
else
{
context.Fail("invalid cert");
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.Fail("invalid cert");
return Task.CompletedTask;
}
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
3. MyCertificateValidationService.cs
public class MyCertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
var cert = new X509Certificate2(Path.Combine("localhost_root_l1.pfx"), "1234");
if (clientCertificate.Thumbprint == cert.Thumbprint)
{
return true;
}
return false;
}
}
4. Action methods that are secured and unsecured
[Authorize]
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
Note: Index action method requires client authentication while Privacy does not require client certificate.
The Problems: The problems which I am getting are:
CertificateAuthenticationEvents
&OnAuthenticationFailed
located onConfigureServices()
method of startup.cs file I not called. I checked them by placing breakpoints but breakpoint is not reached.MyCertificateValidationService.cs class
ValidateCertificate()
method is also not called up. I have also checked it with breakpoint
Please help me to implement Certificate Authorization.
Update
I created 2 certificates in C# as explained in this tutorial. These are:
- Root certificate called root_localhost.pfx
- Client certificate called client.pfx
I did 2 things with these certificates:
a. I added root_localhost.pfx to the Trusted Root Certification Authorities (on Windows) for the Local Computer (using CertManager).
b. I imported the Client certificate on by chrome browser.
Next, I selected the project in VS 2019 (console) instead of 'IIS Express' and run my project. I opened the website url in incognito window, the URL happens to be - https://localhost:5001
Chrome asks to select the certificate, see image below:
On selecting it i get This site can’t be reached - ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, see below image:
Why it is happening????