I have a service and client gRPC service.
In my client application, I would like to include a client certificate, so only this application could call to the server.
The reason for that it is to avoid another person could develop an application an call to my service.
Also I want to use JWT token to identify each user, because it user will have different permissions.
My gRPC service is hosted in a ASP Core application,using .NET 7, and this is the program.cs file:
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}");
}
How it is shown, I have configure the kestrel server, in the ConfigureHttpsDefaults section, to require a client certificate.
However, when I create the client, I don't include any certificate, and the client get repose from the service. I would expect I get an authentication exception.
Perhaps is it not possible to use two authentication options, in this case certificate and JWT token?
Thanks.