Add client certificate to .NET Core HttpClient
Make all configuration in Main() like this:
public static void Main(string[] args)
{
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
string env="", sbj="", crtf = "";
try
{
var whb = WebHost.CreateDefaultBuilder(args).UseContentRoot(Directory.GetCurrentDirectory());
var environment = env = whb.GetSetting("environment");
var subjectName = sbj = CertificateHelper.GetCertificateSubjectNameBasedOnEnvironment(environment);
var certificate = CertificateHelper.GetServiceCertificate(subjectName);
crtf = certificate != null ? certificate.Subject : "It will after the certification";
if (certificate == null) // present apies even without server certificate but dont give permission on authorization
{
var host = whb
.ConfigureKestrel(_ => { })
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseConfiguration(configuration)
.UseSerilog((context, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
})
.Build();
host.Run();
}
else
{
var host = whb
.ConfigureKestrel(options =>
{
options.Listen(new IPEndPoint(IPAddress.Loopback, 443), listenOptions =>
{
var httpsConnectionAdapterOptions = new HttpsConnectionAdapterOptions()
{
ClientCertificateMode = ClientCertificateMode.AllowCertificate,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
ServerCertificate = certificate
};
listenOptions.UseHttps(httpsConnectionAdapterOptions);
});
})
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls("https://*:443")
.UseStartup<Startup>()
.UseConfiguration(configuration)
.UseSerilog((context, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
})
.Build();
host.Run();
}
Log.Logger.Information("Information: Environment = " + env +
" Subject = " + sbj +
" Certificate Subject = " + crtf);
}
catch(Exception ex)
{
Log.Logger.Error("Main handled an exception: Environment = " + env +
" Subject = " + sbj +
" Certificate Subject = " + crtf +
" Exception Detail = " + ex.Message);
}
}
Configure file startup.cs like this:
#region 2way SSL settings
services.AddMvc();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CertificateAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CertificateAuthenticationDefaults.AuthenticationScheme;
})
.AddCertificateAuthentication(certOptions =>
{
var certificateAndRoles = new List<CertficateAuthenticationOptions.CertificateAndRoles>();
Configuration.GetSection("AuthorizedCertficatesAndRoles:CertificateAndRoles").Bind(certificateAndRoles);
certOptions.CertificatesAndRoles = certificateAndRoles.ToArray();
});
services.AddAuthorization(options =>
{
options.AddPolicy("CanAccessAdminMethods", policy => policy.RequireRole("Admin"));
options.AddPolicy("CanAccessUserMethods", policy => policy.RequireRole("User"));
});
#endregion
The certificate helper
public class CertificateHelper
{
protected internal static X509Certificate2 GetServiceCertificate(string subjectName)
{
using (var certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
{
certStore.Open(OpenFlags.ReadOnly);
var certCollection = certStore.Certificates.Find(
X509FindType.FindBySubjectDistinguishedName, subjectName, true);
X509Certificate2 certificate = null;
if (certCollection.Count > 0)
{
certificate = certCollection[0];
}
return certificate;
}
}
protected internal static string GetCertificateSubjectNameBasedOnEnvironment(string environment)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile($"appsettings.{environment}.json", optional: false);
var configuration = builder.Build();
return configuration["ServerCertificateSubject"];
}
}
ASP.NET Core 2.1: Add client certificate to registered typed HTTP clients
You are correct in your experience that AddHttpMessageHandler
is required to return a type of DelegatingHandler
as this function is used to extend the request pipeline. In order to create an HttpClientHandler
with a client certificate attached, you should instead use ConfigurePrimaryHttpMessageHandler
to create and return the configured instance of HttpClientHandler
.
.NET Core adding client certificate to POST to Kestrel REST API on Linux fails server cert validation
Turns out this is actually working! I just needed to get the correct certificates in place!
Specifically, I had to include the Root CA and Intermediate CA at the Server side.
The Client side, I had to include only the Root CA to verify.
HttpClient connecting via certification validation
The error complains that the server certificate is invalid. Perhaps it has expired or revoked. Sometimes the root authority certificate itself is compromised and revoked. This is rare but it has happened in the past.
Perhaps a test server uses a self-signed certificate for development. Self-signed certificates are invalid by definition because they aren't signed by a trusted authority.
HTTPS isn't used to encrypt the connection, it's used to ensure that no other server gets "in the middle" of the client and server. It does that by ensuring the remote server is who its certificate says it is. Obviously, the certificate needs to be valid - which means it needs to be signed by a trusted source. Without validation someone could add a malicious proxy to your network that would pose as the remote server, intercept your calls and send them to the remote server.
If the server service has expired or been revoked, the server admin will have to renew it.
To use a self-signed certificate without compromising security is to trust it. The .NET Core SDK will add the self-signed certificate used by .NET Core projects to the trusted certificates of the local machine. On other machines you can navigate to the API URL with a browser, click on the warning that appears at the left of the address bar and trust the certificate
Related Topics
Best Way to Check If a Data Table Has a Null Value in It
C# - Comparing Items Between 2 Lists
Post Byte Array to Web API Server Using Httpclient
How to Call Another Controller Action from a Controller in MVC
Launch an Application and Send It to Second Monitor
How to Convert a List to Ienumerable
Adding an Incremental Number to Duplicate String
Using Linq to Remove Elements from a List<T>
How to Match Hyphens With Regular Expression
Extract First Element from Json
How to Calculate the Average of Each Row in Multidimensional Array
How to Close a File That Is Already Opened in a Directory
Client Specific Role Based Authentication
How to Secure the Asp.Net_Sessionid Cookie
How to Convert Word Files to Pdf Programmatically
Removing Elements from Json Based on a Condition in C#
How to Print the Elements With Text Value That Contains in a List Selenium C#