Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I set in the server that a client certificate it is needed, but the server responses when the client doesn't include any client certficate #47952

Closed
1 task done
ComptonAlvaro opened this issue Apr 28, 2023 · 5 comments
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved

Comments

@ComptonAlvaro
Copy link

ComptonAlvaro commented Apr 28, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I have asked this in this issue: #47638, but it closed as solved but really i don't think it was answered correctly.

I open t his new issue because it is closed and I don't know if the reply that I added it would be seen or not because it is close. I don't know how GitHub works in this case. So first of all, I am sorry if I open this new issue when I shouldn't do it.

Well, in the first question, I asked why if I set the server to requiered a client certificate, the server responses to a client when the client doesn't include any client certificate. I guess that the server should refuse the connection.

In the first issue, it was replied that to validate the client certificate, I should to implement the logic of ClientCertificateValidation in the HttpOptions. Well, I think this would be the next step, when I get a client certificate, to be sure it is correct. But my problem is that the server response when it doesn't get the certificate of the client, so, how to validate it? and how to validate it is the server responses although the client doesn't add a certificate?

So I would like this:

1.- First, that the server doesn't response if the client doesn't include a client certificate.
2.- In the server, execute the validation of the client certificate when the client add a certificate.

I add my actual code to have the code in this post:

Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;


var builder = WebApplication.CreateBuilder(args);


var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();



try
{
    builder.WebHost.ConfigureKestrel((context, options) =>
    {
        string miStrCertificado = File.ReadAllText(builder.Configuration.GetSection("Certificados:Certificado").Value!);
        string miStrKey = File.ReadAllText(builder.Configuration.GetSection("Certificados:Key").Value!);
        X509Certificate2 miCertficadoX509 = X509Certificate2.CreateFromPem(miStrCertificado, miStrKey);

        X509Certificate2 miCertificado2 = new X509Certificate2(miCertficadoX509.Export(X509ContentType.Pkcs12));

        miCertficadoX509.Dispose();

        options.ListenAnyIP(Convert.ToInt32(builder.Configuration.GetSection("Servidor:Puerto").Value!), listenOptions =>
        {
            listenOptions.Protocols = HttpProtocols.Http2;
            listenOptions.UseHttps(miCertificado2);
        });


        options.ConfigureHttpsDefaults(miHttpsOptions =>
        {
            miHttpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
            miHttpsOptions.ServerCertificate = miCertificado2;
        });
    });




    builder.Services.AddHttpContextAccessor();

    

    builder.Services.AddGrpc();
    builder.Services.AddCodeFirstGrpc();



    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(builder.Configuration.GetSection("JwtAuthApp.Server:JwtTokenService:ClaveCifradoToken").Value!)),
                RequireExpirationTime = true,
                RequireSignedTokens = true,
                ClockSkew = TimeSpan.FromSeconds(10),

                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
            };
        });


    builder.Services.AddAuthorization();





    var app = builder.Build();

    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.MapGrpcService<MyGrpcService>();




    await app.RunAsync();
}
catch (Exception ex)
{
    Console.Write($"ERROR: {ex.Message}");
}

Thansk so much.

Expected Behavior

The server should refuse the client request if the client doesn't add a client certificate and the server has configurated to requiere client certificate.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

.NET Core 7

Anything else?

No response

@Tratcher
Copy link
Member

Tratcher commented Apr 28, 2023

This might be an ordering issue. What if you call ConfigureHttpsDefaults before ListenAnyIP? Or, if you didn't use ConfigureHttpsDefaults and instead used the UseHttps overload with the required parameters.

@ComptonAlvaro
Copy link
Author

@Tratcher Changing the ordering as you suggest it works, as well if I use the UseHttps overload to set up it.

Thanks so much.

@mitchdenny
Copy link
Member

mitchdenny commented May 1, 2023

This issue was originally mentioned here:
#47638

I maked that issue as answered but @ComptonAlvaro doesn't feel it was, so now we've got this issue open, and one more:

#47955

It would be great to either close this one, or the other new one and try to consolidate since it all seems to be related to the same inquiry. In the initial issue I posted the following sample which shows how requiring a client certificate, and client certificate auth interact (note it the example I accept any certificate if provided):

using Microsoft.AspNetCore.Authentication.Certificate;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using System.Security.Claims;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, options) =>
{
    options.ConfigureHttpsDefaults(httpsOptions =>
    {
        httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
    });
});

builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
{
    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;
        }
    };
});

builder.Services.AddAuthorization();

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/", () => "Hello World!").RequireAuthorization();

app.Run();

My issue doesn't cover gRPC specifically though.

Edit [amcasey]: I'm pretty sure @mitchdenny meant to refer to #47955, though he may (also?) have meant #47988.

@amcasey
Copy link
Member

amcasey commented May 1, 2023

@Tratcher Changing the ordering as you suggest it works, as well if I use the UseHttps overload to set up it.

Thanks so much.

I understand this to mean that this portion of your question has been answered.

@amcasey amcasey closed this as completed May 1, 2023
@amcasey amcasey added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label May 1, 2023
@ghost ghost added the Status: Resolved label May 1, 2023
@ComptonAlvaro
Copy link
Author

yes, the two solutions the @Tratcher has proposed works. I can change the order or use the UseHttps() overload. I am using this second one, the UseHttps() overload, but I have tried the first one, changing the order of the code and it works too.

@ghost ghost locked as resolved and limited conversation to collaborators Jun 1, 2023
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved
Projects
None yet
Development

No branches or pull requests

4 participants