blowdart / idunno.Authentication

A filled with self-loathing implementation of Basic Authentication, and Certificate Authentication to make me feel like a real security person, all for for ASP.NET Core
Apache License 2.0
409 stars 70 forks source link

CertificateAuthenticationEvents is not executed when doing a request to the server #52

Closed Coldplayer1995 closed 2 years ago

Coldplayer1995 commented 2 years ago

Description of the problem you are seeing: I'm doing a request to the controller with the attribute: [Authorize]

What do you think should be happening? I should be entering the event: OnValidateCertificate. I want to validate httpclient Certificate against external CA authority. Why I need to provide any ServerCertificate for the server in the Kestrel is a black box for me. I want to be able to verify it against CA?

What is actually happening? The event OnValidateCertificate is not executed and I immidiatly get 403 Forbidden returned

My ConfigureServices() code

  services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
                .AddCertificate(options =>
                {
                    options.Events = new CertificateAuthenticationEvents
                    {
                        OnValidateCertificate = context =>
                        {
                            //var validationService =
                            //    context.HttpContext.RequestServices.GetService<ICertificateValidationService>();

                            //if (validationService.ValidateCertificate(context.ClientCertificate))
                            //{
                                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();
                            //}

                            return Task.CompletedTask;
                        },
                        OnAuthenticationFailed = context =>
                        {
                            return Task.CompletedTask;
                        }
                    };
                });

ADDED INTO CONFIGURE:
         app.UseAuthentication();
         app.UseAuthorization();
public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>().UseKestrel(
                        options =>
                        {
                            options.Listen(IPAddress.Loopback, 5001, listenOptions =>
                            {
                                listenOptions.UseHttps(new HttpsConnectionAdapterOptions
                                {
                                    ServerCertificate = new X509Certificate2("Certificates/certificate.cert.pfx", "admin"),
                                    ClientCertificateMode = ClientCertificateMode.RequireCertificate,
                                    ClientCertificateValidation = CertificateValidator.DisableChannelValidation
                                });
                            });
                        });
                });
 static async Task SendRequestUsingHttpClient()
        {
            HttpClientHandler handler = new HttpClientHandler();
            X509Certificate clientCert = new X509Certificate2(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "certificate.cert.pfx"), "admin");
            handler.ClientCertificates.Add(clientCert);
            //handler.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            using (var client = new HttpClient(handler))
            {
                client.BaseAddress = new Uri("https://localhost:5001/notification/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage response = await client.GetAsync("api/v1/notification/admin/templates");
                if (response.IsSuccessStatusCode)
                {
                    string content = await response.Content.ReadAsStringAsync();
                    Console.WriteLine("Received response: {0}", content);
                }
                else
                {
                    Console.WriteLine("Error, received status code {0}: {1}", response.StatusCode, response.ReasonPhrase);
                }
            }
        }
blowdart commented 2 years ago

A couple of questions first

As an aside .NET Core 2.1 runtime is out of support now. If you're not targeting .NET Framework as your runtime you're not getting security patches anymore and you need to update to a supported runtime and framework.

Coldplayer1995 commented 2 years ago

We are using .NET 5.0

blowdart commented 2 years ago

.NET 5 has its own, supported version, questions should be directed there.

For k8s you can probably import the root CA into OpenSSL during setup, but I'm afraid that's a k8s question.

Server certificate in this case is the HTTPS certificate kestrel uses, that doesn't touch on client certificate auth at all (aside from https being required by default, and https requiring a certificate) and what you're seeing are instructions for 2.1 which is all the cert auth supports.

As you're asking about .NET 5 I'm going to close this, as this implementation doesn't support it because it became the starting point for inclusion in 3.1.