简体   繁体   中英

.net core 3.0 Certificate authentication

Recently I have migrated an API from .net core 2.2 to .net core 3.0 in order to implement an authentication using certificates.

I have followed this Microsoft documentations: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-3.0 to do my work. But I'm facing an issue: When I call a controller Method decorated with an [Authorize] attribute, the certificate validation is never performed. If there is no certificate in the request's header, I get a 403 which is the required behavior, but If I put a certificate the supposed behavior should be the verification by the thumbprint, but nothing...

Here my certificate validation service:

public class CertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate, string thumbprintToChek) =>
        clientCertificate.Thumbprint.Equals(thumbprintToChek);
}

As said in the documentation, in StartUp.cs I have set up the following lines of code inside the ConfigureServices method

services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
            .AddCertificate(options => // code from ASP.NET Core sample
            {
                options.AllowedCertificateTypes = CertificateTypes.All;
                options.Events = new CertificateAuthenticationEvents
                {
                    OnCertificateValidated = context =>
                    {
                        var validationService = context.HttpContext.RequestServices.GetService<CertificateValidationService>();

                        if (validationService.ValidateCertificate(context.ClientCertificate, Configuration.GetValue<string>("Apim:CertificateThumbprint")))
                        {
                            var claims = new[]
                            {
                                new Claim(ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer),
                                new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer)
                            };

                            context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
                            context.Success();
                        }
                        else
                        {
                            context.Fail("Invalid certificate.");
                        }

                        return Task.CompletedTask;
                    }
                };

                options.Events = new CertificateAuthenticationEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        context.Fail("Certificate not valid.");

                        return Task.CompletedTask;
                    }

                };
            });

        services.AddCertificateForwarding(options =>
        {
            options.CertificateHeader = "X-ARR-ClientCert";
            options.HeaderConverter = (headerValue) =>
            {
                X509Certificate2 clientCertificate = null;
                if (!string.IsNullOrWhiteSpace(headerValue))
                {
                    byte[] bytes = headerValue.ToByteArray();
                    clientCertificate = new X509Certificate2(bytes);
                }
                return clientCertificate;
            };
        });

I have also populated the Configure method with the following code:

app.UseCertificateForwarding();
app.UseAuthentication();

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

So when I make a request to the API, the CertificateForwarding delegation is well called, but Authentication delegation, never.

However, I have tried to implement this authentication in a brand new project (just for tests) it worked perfectly.

Your assignment to options.Events is done twice. This way the default implementation of OnCertificateValidated overwrites your eventhandler and your CertificateValidationService will never be called.

Combining the two eventhandlers should give the expected result:

options.Events = new CertificateAuthenticationEvents
{
    OnCertificateValidated = context =>
    {
        // Your implementation here.
    },
    OnAuthenticationFailed = context =>
    {
        // Your implementation here.
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM