Edit for future readers: Unfortunately, the bounty awarded answer
doesn't work; nothing I can do about that now. But read my own answer
below (through testing) – confirmed to work with minimal code changes
We have an Azure Cloud Service (WebRole) that's entirely in ASP.NET WebAPI 2.2 (no MVC, front end is Angular). Some of our controllers/REST endpoints talk to a 3rd party cloud service over SSL (client cert auth/mutual auth) and the rest of the controllers/endpoints talk to the HTML5/AngularJS front end, also over SSL (but more traditional server auth SSL). We don't have any non-SSL endpoint. We've enabled Client SSL via a cloud service startup task like:
IF NOT DEFINED APPCMD SET APPCMD=%SystemRoot%\system32\inetsrv\AppCmd.exe
%APPCMD% unlock config /section:system.webServer/security/access
Issue: That setting is site-wide so even when users hit the first page (say https://domain.com, returns the index.html for angularJS) their browser asks them for client SSL cert. (image below)
If there a way to either
- Limit the client SSL certificate requests to just the WebAPI controllers that talk to the 3rd party cloud service?
OR
- Skip client SSL auth for our front end powering webapi controllers?
Our server's web.config is complex but the relevant snippet is below:
<system.webServer>
<security>
<access sslFlags="SslNegotiateCert" />
</security>
</system.webServer>
And the screenshot of the client hitting a regular WebAPI endpoint yet attempting client SSL Authentication (happens in any browser, Chrome, Firefox or IE)
Best Answer
Unfortunately, cleftheris's answer that's awarded the bounty does not work. It tries to work too late in the HTTP server pipeline/processing to get the client certificate, but this post gave me some ideas.
The solution is based on
web.config
that calls out for special handling of "directories" (works for virtual folders or WebAPI routes too).Here is the desired logic:
Here is the corresponding configuration
Bonus points
The above will setup the SSL handshake accordingly. Now you still need to check the client SSL certificate in your code if it's the one you expect. That's done as follows
Controller code:
Actual attribute from above that perform SSL Client validation is below. Can be used to decorate the entire controller or just specific methods.