skip to Main Content

Oct 6, still pending. Although the suggestion of adding the [Authorize] did somehow get a step further, there was still nothing associated with the X509 certificate readable from the request anywhere. Still unsure how to get and even recognize the certificate was even supplied. Really appreciate some assist.

As just asked, "what server am I using"… At present, I dont specifically know what Visual Studio is using. I have not explicitly done any setup of IIS vs Kestrel.

Probably something simple, but I have looked and found many things about reading a client X509-certificate as part of a post. Here is the following scenario. VERY BASIC — on my stand-alone machine, not a server anywhere, just my machine:

Using Visual Studio 2022. Web-side ASP.NET Core Web API project, support HTTPS, support certificate authentication.

Prepared self-signed HTTPS certificate for my machine for handling "localhost".

Simple controller method that returns a string.

Second project Visual Studio 2022 desktop app, C# .NET / WPF application.

WPF asks user for their PIN for their personal certificate.

Prepare a webrequest post to localhost.

Adds personal certificate to request and submits to localhost https site.

ASP.NET Core Web API gets request, but when I try to look for the certificate, nothing appears to be found for me to confirm it was even included. Below are applicable components of code.

From ASP.NET Core Web API:

Program.cs:

using Microsoft.AspNetCore.Authentication.Certificate;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();


builder.Services.AddAuthentication(
        CertificateAuthenticationDefaults.AuthenticationScheme)
    .AddCertificate(options =>
    {
        options.AllowedCertificateTypes = CertificateTypes.All;
        options.RevocationMode = X509RevocationMode.NoCheck;
        options.Events = new CertificateAuthenticationEvents
        {
            OnCertificateValidated = context =>
            {
                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;
            }
        };
    });

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
}

app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Submit controller:

using Microsoft.AspNetCore.Mvc;

namespace MySampleNet.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class Submit : Controller
    {
        public string Index()
        {
            // not getting any client certificate from request posted
            var x = Request.HttpContext.Connection.ClientCertificate;
            return "Simple Return Text";
        }
    }
}

WPF application making the web request call:

    public void MyTesting()
    {
        var postURL = "https://localhost:7266/submit";

        // method prompts user to pick a certificate, enter PIN
        // validates PIN before adding to the web post below
        var cert = PickCACCertificate();
        var request = WebRequest.Create(postURL) as HttpWebRequest;

        // Set up the request properties.
        request.Method = "POST";
        request.Accept = "*/*";

        request.ClientCertificates.Add(cert);
        request.UseDefaultCredentials = false;
        request.PreAuthenticate = true;
        request.AllowAutoRedirect = true;

        var webResponse = request.GetResponse() as HttpWebResponse;

        var responseReader = new StreamReader(webResponse.GetResponseStream());

        // try catch will handle any possible NULL response stream.
        var fullResponse = responseReader.ReadToEnd();
        webResponse.Close();
    }

2

Answers


  1. You need to put [Authorize] attribute on either, MVC controller or controller action. ASP.NET core will not authenticate client and populate identity if this attribute is not presented.

    Login or Signup to reply.
  2. I don’t think you are configuring Kestrel to require a client certificate.

    Checking the sample Program.cs you appear to be missing

    builder.Services.Configure<KestrelServerOptions>(options =>
    {
        options.ConfigureHttpsDefaults(options =>
            options.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
    });
    

    You can also configure it in your appsettings.json

    "Kestrel": {
      "Endpoints": {
          "RequireClientCert": {
              "Url" : "https://localhost::7266",
              "ClientCertificateMode": "RequireCertificate"
          }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search