Blog

Beware of RequestUri when exposing WCF REST services through HTTPS

By: Alejandro Villarreal

 

We recently implemented a WCF REST service which authenticates the caller before executing any of the operations it exposes. It also has help page (so users can see the supported operations and the expected inputs) which we want to expose to any user, regardless of authentication. In principle this is very easy: we just needed to identify requests to the “help” section of our service (http://myServiceUrl/help) and allow them to go through without further validation.

 

We have a method that returns “true” for requests that should go through, and “false” for those that shouldn’t, so originally our code to solve the problem looked like this:

 

if (requestUri.RequestUri.ToString().Replace(requestUri.BaseUri.ToString(), String.Empty).StartsWith("help"))
{
    return true;
}

 

Simple, right? Check the URI that was requested, remove the base URI, and check if the remaining string starts with “help”.

 

And indeed, this solution worked perfectly at first. The problem came when we moved the site from an http binding to https. The service itself worked fine, but we just couldn’t access the help page. This particular piece of code seemed like the only candidate where something could be going wrong, but what was it? To find out, I created a self-signed SSL certificate in my machine, configured the development site to use it, and attached Visual Studio to the IIS worker thread for that site.

 

And oh surprise! It seems that for sites with an https binding, IIS sets the RequestUri property to the host-header configured in the certificate, not the host-header in the actual request (at least for single-domain certificates, like the one I created; it’d be interesting to know what does it do for wildcard certificates). So if the certificate was issued for myCertifiedDomain.com, but we access the help page through https://myServiceUrl.com/help, the RequestUri property will contain https://myCertifiedDomain.com/help, while the BaseUri property will contain https://myServiceUrl.com/ (note that it does not have the “help” segment at the end, since this is the base URI). Given these inputs, the String.Replace logic that we had implemented wasn’t ever going to work.

 

To make things a bit more interesting, our service is hosted as an application inside the site in IIS. So in reality, the URLs look something like this:

·         RequestUri: https://myCertifiedDomain.com/serviceApp/help

·         BaseUri: https://myServiceUrl.com/serviceApp/

 

The solution was clear: we had to modify the condition that verifies if the requested resource is the service’s help page. I browsed through the properties exposed in the Uri class (of which both RequestUri and BaseUri are instances), and found a suitable candidate: AbsolutePath. According to MSDN “[AbsolutePath] does not include the scheme, host name, or query portion of the URI”. In my example, this means that I would see the following (highlighted in bold):

·         RequestUri: https://myCertifiedDomain.com/serviceApp/help

·         BaseUri: https://myServiceUrl.com/serviceApp/

 

Voilà! With those inputs we could keep the condition we already used, replacing the URI’s with their corresponding AbsolutePath properties. The code ends up looking like this:

 

if (requestUri.RequestUri.AbsolutePath.Replace(requestUri.BaseUri.AbsolutePath, String.Empty).StartsWith("help"))
{
    return true;
}

 

As you can see, the fix was really simple… once we understood where the problem was. I couldn’t find any documentation for this URL-replacing behavior, or other instances of the same problem, so I hope this post will help somebody in the future.

 

Comments

Leave a comment

 
 
 
 
CAPTCHA Image Validation