I have an ASP.NET MVC Core project using Kestrel as the server. It is both serving up user content (asp.net mvc) and hosts web API controllers that agents (software) communicate with. I have enabled HTTPS and client certificate support. The issue is that I want to require client certificates for agents (software) that call Web APIs but I do not want to require/prompt for client certificates for regular browser based users.
I have enabled HTTPS/client certificate support the following way:
var host = new WebHostBuilder()
.UseKestrel(options =>
{
HttpsConnectionFilterOptions httpsoptions = new HttpsConnectionFilterOptions();
httpsoptions.ServerCertificate = CertUtil.GetServerCert();
httpsoptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
httpsoptions.CheckCertificateRevocation = false;
options.UseHttps(httpsoptions);
})
.UseUrls("http://0.0.0.0:5000", "https://0.0.0.0:5001")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
I have a separate middleware handler setup in Startup.cs to handle custom verification of client certificates. This code does successfully execute and everything works fine in that sense.
The problem is this happens globally and I am only looking to apply client certificates to specific controllers and/or routes; or really I would take any granularity at this point.
Essentially trying to create the same sort of behavior you can get in IIS by creating two virtual directories and then setting SSL Settings to Accept on one and Ignore on the other. The one with Accept will prompt the browser for a cert and the one with Ignore will not.
I tried setting HttpsConnectionFilterOptions to only specify ServerCertificate in hopes that not setting any client certificate related options would allow the server to receive client certificates if they are sent but otherwise not prompt browsers for them. This did not seem to work as my middleware client certificate handler never sees a client cert when calling this function (it does when ClientCertificateMode is set to AllowCertificate.
context.Connection.GetClientCertificateAsync();
I guess in short does Kestrel hosting even allow for more granular client certificate mapping/handling or is it only possible using IIS? IIS is not an option for this project and I would rather prefer not having to create a separate project/process just for the client cert api aspects. Appreciate any help!
I've been trying to do the same thing, with exactly the same requirements as you.
I've come to the conclusion that it's not possible. My workaround is to use 2 WebHostBuilder objects - one for locations that don't need client certs, and one for those that do. This does have the downside that each IWebHost must listen on a different port, but from the scenario you describe I guess that's not a big issue.
I do this within the same process, so this solution fits that requirement.
I had the same issue with context.Connection.GetClientCertificateAsync(); it was always returning null. Then I noticed that I was running Kestrel thru IIS Express all the time.
So in Visual Studio from the Debuger toolbar I changed from IIS Express to my project. Kestrel was started as console application and I was able to get the client certificate.
I think that IIS Express does not support client certificates so the certificate was always ignored.
For the other part of the question; I think Kestrel dos not support this granularity that you are looking out of the box when using the HttpsConnectionFilterOptions. From the Kestrel Connection Filter Options source code the connection will be dropped if the client certificate is null. Maybe you can modify the source code for the HttpsConnectionFilterOptions and create your own filter from it. Then you can use the ClientCertificateValidation property to specify custom certificate validation method that will allow the connection when no client certificate is send.
Hope this helps.
I have figured out how to have Client Certificate only on some routes but when run in Azure Web App, the client cert is not being passed to the code. It is the same problem when running under IIS Express.
In this example, One controller needs no cert, the other two requires different certs.
https://github.com/xavierjohn/ClientCertificateMiddleware
The certificate does get passed through if it is not run under IIS Express.
There is no need to use isolated (new one) IWebHost to control access to dedicated MVC controllers.
Just use Athorization Filter for this purpose.
Related
I have a standard C# Web Api running on IIS that has a custom AuthorizeAttribute to properly authorize calls via a key in the request header variables. Recently, one of my clients calls to the API over SSL have started to fail with an 403 Forbidden error. He is successful when calling the non-SSL url.
The same call - same url, api key etc. works perfectly over SSL from my machine, and none of my other clients are having any issues with this. What could possibly be the issue for this specific client? I have checked some basic things like his client machine time settings etc. are all in order, not sure if this could be some kind of certificate related issue?
try the following:
1- check the proxy on his machine
2- since SSL is used to protect data and safety the data should not change in the way on the server. it could be changed by a virus on the machine (I have the same problem with one of my clients) make sure his system is clean
3- consider calling the API in other ways like (postman, browser, ...)
according to what you write clearly, there is something wrong with his machine. if you find the problem It would be nice to tell me too
I'm working on some WCF application. I already have client-side and server-side. Both communicates using WCF netTcpBinding or netNamedPipe. I want also a certificate only on server side, similar as it is with HTTPS. I've found very helpful guide here click.
So according to this article, I'm interested in option 1 which is
Option one provides (C + I) no authentication will happen for the client, In this case the TCP SSL (not the HTTPS SSL) will be used to provide the Confidentiality and Integrity, and the service will be configured like this below.
For now everything is clear for me, unfortunately later we can read:
also you need to install the root certificate authority certificate for the service certificate on the client machine (typically in the Local Machine/Trusted Root Certification Authorities), and the service needs to have the below behaviour to specify the certificate for the service.
So here comes my question, is there any way to avoid changes on client machine? As mentioned earlier, I'm looking for a solution similar to WEB where the user is not obligated to install any kind of certificate on his machine.
Maybe I'm missing something, but maybe this rule applies only when I'm using a self-trusted/developer certificate? What if I will get certificate from a trusted company like Verisign?
Install the certificate on the client-side simply to guarantee that the service on the server-side is trusted and that communication I secure. Just like visiting a website, we usually have a built-in certificate for the site before we browse the website, so the browser prompts the website is trusted. Unlike self-signed certificate, website certificates are issued by trusted third-party organizations to a specific host (web server), so all we need to do on the client-side is to install authoritative trusted third-party certificate before accessing the website. but we directly install the server-certificate on the client-side when we configure a self-signed certificate in the Local CA.
In fact, Browsers/OS already have some authoritative third-party certificate built-in. such as GlobalSign, VeriSign, so we just need to buy a certificate from them and configure them on the server-side, in which case, the client always trusts the server.
In addition to installing the server-side certificate, we may also need to configure the server-side identity on the client-side, which is usually the public key of the certificate, or the hostname. These configurations are generated automatically if we generate the client proxy and invoke the service by adding a service reference.
Feel free to let me know if there is anything I can help with.
You don‘t need install somethings when you use an certificate issued by an trusted CA like GoDaddy and so on.
I've written a simple WebAPI Service (hosted with OWIN in a Windows Service) and put the [Authorize] attribute on the POST-method. As I understand, only "known" users can now access the service (don't worry, I know, all known users is not really safe yet).
My test client works fine so far when the host and the client are located on the same machine (f.ex. my workstation). However when I deploy the service on a server machine, and try again to call the service, I get a HTTP 400 failure when using the System.Net.Http.HttpClient and set httpClientHandler.UseDefaultCredentials=true, or a HTTP 401 when I use System.Net.WebClient and set webClient.UseDefaultCredentials=True.
So it seems the authentication mechanism acts different depending if the service is hosted local or remote.
For test reason I've also tried to set the credential explicit with user and password, but with exactly the same result.
However, what do I miss here? Any suggestions?
Thank you in advance!
verify the machine keys.
If the authorization server and the resource server are not on the same computer, the OAuth middleware will use the different machine keys to encrypt and decrypt bearer access token. In order to share the same private key between both projects, we add the same machinekey setting in both web.config files.
https://learn.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server
We have self-hosted C# WCF service providing rest API over HTTPS.
Problem:Configuring the certificates for SSL requires admin rights. I assume it is to do with WCF depends on http.sys for http/https handling. The service is meant to be deployed on customer environments. So it would be nice if it can run without requiring admin rights.
Looks like WCF depends on http.sys,
Can I self-host an HTTPS service in WCF without the certificate store and without using netsh http add sslcert?
Like to know if any other embedded web server solution exist that support SSL and not requiring admin rights on the machine?
Checked so far,
http://nancyfx.org/
https://github.com/pvginkel/NHttp
Both doesn't seem to support SSL.
Most windows hosted web stacks rely on the HTTP Server API which is the API around the kernel HTTP stack (a.k.a HTTP.sys). The .Net HttpListener class does so as well (same as WCF, the OWIN self hosted asp.Net and so on which rely on it).
Just making sure, you do know you can authorize the identity you application runs under to bind to an HTTPS URL even if it's not running as an admin account, right? If you could gain admin right just for the installation phase that could solve you problem? (assuming you checked that already)
You can read more on a blog post i wrote about that here
To go into the effort of building an http stack on top of raw sockets would be a great effort and with little gain and so around .Net i doublt you would find anything like that.
Unless, it wished to be cross platform.
Any java based web server would probably do just that, using the JVM's http stack and relying on a java keystore to provide the required certificates for the SSL. (To keep it portable across different OS's)
If you wanna go java i am sure you can find many such web servers.
If you care to try and bind to a web server using CGI have a look at mongoose (Never used it to be honest).
Another option which comes to mind is to use an ssl proxy like Stunnel to stand in front of the web server. It would do the SSL part using non-windows certificate store.
Is it possible to have a web service require ssl on some urls but not on others? The service as a whole provides 1 function but talks to 2 different clients. I can split it into 2 different services if necessary but was wondering if it's possible.
In IIS (i'm using version 7), there is a option for you site called SSL Settings, in there make sure the Require SSL checkbox is unchecked. This will not force SSL on the service.
However, this will not prevent your SSL required client from using the non SSL link, it will basically allow you to hit the service with and without SSL.