WCF self hosted service with certificate authentication - wcf

I have created a self-hosted WCF RESTful service with basic http authentication that runs over https with a self-signed SSL certificate. Everything works fine. When users access the service operations via a web browser,they get a pop up asking for credentials (login/password).
Now I want to do certificate authentication instead of basic, but it does not work. The client's browser(IE/chrome/firefox) never prompts for certificate selection, I always get a HTTP 403 error and when I set a breakpoint in my custom certificate validor it never hits. So I'm definitely missing something here. I tried debugging with Fiddler and it confirms that there is no authentication header in the request.
Here is my code to host the service.
Uri baseAdress = new Uri("https://localhost:8446/");
WebServiceHost host = new WebServiceHost(typeof(RestService));
WebHttpBinding wb = new WebHttpBinding();
wb.Security.Mode = WebHttpSecurityMode.Transport;
wb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
host.AddServiceEndpoint(typeof(IRestService), wb, baseAdress);
host.Credentials.ClientCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.Custom;
host.Credentials.ClientCertificate.Authentication.CustomCertificateValidator =
new MyX509CertificateValidator()
host.Open();
Thanks for any tips.

I found this article which could probably help you: http://blogs.msdn.com/b/james_osbornes_blog/archive/2010/12/10/selfhosting-a-wcf-service-over-https.aspx
It talks about some kind of registering the certificate to netsh,..
Also, please make sure that your certificate issued to localhost (since domain part in url you call should ne same woth cert. Issued to).

Thanks for your input.
I found out what was wrong.
When I created the self signed certificate for the ssl port binding with the makecert tool, I added the "-eku" key which is making the certificate purpose to be for Server Authentication. I recreated another one without that option, so it could be used for all purposes.
Also I made sure that my certificate was in the personal store of the current user.
After that when a client enters the url of my service, they get a pop up asking them to select a certificate, and there is the one that I created.
For those facing the same issue, this post might be useful.

Related

Self signed client certificate does not reach server application

I have the following setup:
A self signed certificate for development purposes
An OWIN hosted Web API, deployed on a local Azure Service Fabric Cluster as a ASF service. The Web API uses HTTPS facilitated with the dev certificate in question.
A simple .net client application that calls the Web API. In that application the ServicePointManager.ServerCertificateValidationCallback method is set so it always returns true (since the CA is not trusted)
Both the client application and the Web API are on the same local development machine. The certificate is installed in that same machine on the "machine store"
Now I am able to make calls to the web api using Fiddler by providing the required client certificate. However when I try to do the same via .net code (be it RestSharp or WebRequest) the client certificate is not present in the RequestContext object on the server side. This result in an Unauthorized response. I do not think the problem is with the client code, the certificate is loaded correctly and assigned to the http client or request. Fiddler shows encrypted tunneling to the server. However the client certificate does not seem to be present at the server side.
I am at a complete loss regarding what am I missing that could cause this behavior. Any help will be deeply appreciated.
Install the certificate into the 'Local Machine/Trusted People'.
The server needs to already trust the certificate before it asks. The CertificateRequest message that it sends lists the acceptable CAs that can sign the client certificate. If the client certificate's signer isn't in that message, it can't send it.
How you accomplish that in your environment is left as an exercise for the reader. In general now that SSL certificates are available free there is little reason to indulge in the time costs and administrative inconveniences of self-signed certificates. IMHO there wasn't even if you were paying for a CA signature.
I had a problem when a service called another service over HTTPS and it couldn't setup a secure connection. My problem was that since the service is running as NETWORK SERVICE, it couldn't find the certificate, because it was looking in the localmachine/my certificate store.
When I was running from my web browser it was working fine because then, my browser found the certificate in the currectuser/my certificate store.
Add the certificate to the machine/my store and see if it helps.

Simplest way to secure Azure Web Role WCF service

Using latest VS 2013 and Azure SDK 2.4, I've created a Web Role and a WCF service in it.
This service will be consumed by a standard generated .NET service reference client proxy.
I am trying to figure out what is the simplest way to secure this WCF service. I mean securing the authentication can not be hacked easy way, like clear text pwd etc.
Some additional info about the use case:
There will be only one user
It is completely OK to store any secret in client side (like username/pwd or certificate) because the client app will run in a secured place
I just would like to prevent my service to be accessed by the public. Only my secured place running client app should access it, I would like no more no less.
So I am googling the web, and more I read more I confused and overwhelmed with the options and possibilities what I do not need I think. When searching for client certificate I find overcomplicated federated auth methods with server side temp certs etc what I am not sure my simple use case requires.
Any help appreciated.
Thanks in advance
If you really want to restrict access then I would look at client certificates. Configuring azure for client certificates seems quite complex to detail in a single SO post so I'll refer you to this blog post client-certificates-in-windows-azure and I'll summarize below [I used this myself recently so I know it works]
In essence you can make your own certificates using makecert [NOTE: you may want an official SSL cert for your site and only use self-signed for your client certificates.]
You then configure your site to accept client certs - normally I'd use appcmd.exe and a startup task but as the blog post points out your site is not ready so instead you need to add this to your webrole OnStart method [I actually went down the appcmd.exe path initially and was very confused].
using (var serverManager = new ServerManager())
{
try
{
var siteName = RoleEnvironment.CurrentRoleInstance.Id + "_Web";
var config = serverManager.GetApplicationHostConfiguration();
var accessSection = config.GetSection("system.webServer/security/access", siteName);
accessSection["sslFlags"] = #"SslNegotiateCert";
serverManager.CommitChanges();
}
catch (Exception ex)
{
...
}
}
In the CertificateAuthHandler you can than validate the certificate and if you want (and I recommend) that the client certificate being sent is from your expected CA (if self-signed) or that the thumbprint of the certificate is the one you expect (if there is only going to be one) or a combination of the above.

wcf client certificate validation

We have a wcf service hosted in IIS. We like to restrict the client callers to known clients so we implemented a custom X509CertificateValidator. The service is configured with WSHttpBinding binding and IIS set to SSL and require client certificate. Everything is working as expected.
However, we found that we have other aspx pages hosted within the same site that should not require client certificate. It breaks our usage pattern.
I read that turning the IIS setting from Required Client Certificate to Accept Client certificate does not work. I tried this out, while still passing in the client cert from client and it seems to invoke my custom validator. However, using wcf proxy library, I'm unable to call it without a client cert to verify not passing one in.
If "accept client certificate" is not an option, what is the best alternative? Adding some type of message inspector?
Thanks very much in advance.

How to configure SSL socket for the javax.xml.ws.Service?

I have a tomcat application that invokes an IIS hosted ssl enabled, client auth enabled Webservice
This Tomcat application talks to multiple wenservices and probably each of them require client auth along with PKI authentication.
For the IIS Webservice the wsdl url can change hence I use
javax.xml.ws.Service(url,qname) constructor by passing the url for the wsdl ...
The thing is I need to call the above with SSL with custom client key. How to I tell the above constructor to use a sslsocket that I create with my custom KeyManager ? I do not want to use
HttpsURLConnection.setDefaultSSLSocketFactory as that will enforce other outgoing ssl connection to follow to my keymanager which is exclusive to the IIS webservice.
Thanks for your reply.
If you follow the answer to your similar question on ServerFault and make sure that Tomcat's <Connectors /> don't use the javax.net.ssl properties, setting your keystore for the default key manager might not be the end of the world. HttpsURLConnections will only authenticate with it to server that ask for it (client-certificate authentication is always requested by the server) and that ask for a client-cert from a CA list that would match your certificate's issuer. This might not be such a big problem in practice.
If you think it's too big a problem, there seems to be an undocumented property called com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory. Its documentation is as follows:
Set this property on the BindingProvider.getRequestContext() to enable
HttpsURLConnection.setSSLSocketFactory(SSLSocketFactory). The property
is set as follows:
SSLSocketFactory sslFactory = ...; Map ctxt =
((BindingProvider)proxy).getRequestContext();
ctxt.put(SSL_SOCKET_FACTORY, sslFactory);
THIS PROPERTY IS EXPERIMENTAL AND IS SUBJECT TO CHANGE WITHOUT NOTICE
IN FUTURE.

WCF client only works after accessing URL with IE

We have a wcf client, which calls an external webservice. The service is accessed over SSL. The certificate is not a self signed cert. It is issued by Verisign.
The client is hosted in IIS 6 and the application pool's identity is a domain service user.
Every time we want our client to access the remote service we get the following well known exception: "Could not establish trust relationship for the SSL/TLS secure channel with authority-.."
It turned out, that once you access the URL with IE on the same server, our WCF client is working as expected and the certificate is accepted!
My conclusion is, that the URL accessed with IE modified the server in a way, that our WCF client is able to do the validation afterwards. What is our WCF client missing?
(I'm aware that one can circumvent certificate validation by returning true in the ServerCertificateValidationCallback, but this is not an option for production.)
Considering the situation as described, I suspect that your IIS hosted client is not able to load the Verisign root certificate. And it is always a bit unclear to me under which account such IIS based client is trying to access the certificate store. It might be your domain service account user, it might be the ASP.NET user, it might be some other system defined account. This often causing the error.
When you browse the service with IE, there is no doubt about the user (your own credentials) being able to load the Verisign root certificate and resolve the trust relationship correctly.
Please:
Make sure the Verisign root certificate in in the Trusted Root Authorities store under the Local Computer Account
Have your app.config of your client refer to the correct root certificate to be loaded from the correct store.
You might want to run ProcessMonitor to find out which user is trying to load the certificate from the store.