Getting Inherited Config Settings | Howard Dierking

:

Yesterday, I wrote an HttpModule to support enabling Http basic authentication for Web APIs running in an ASP.NET host.  But wait, you say – IIS already supports basic authentication?!?  This is true…kind of.  Basic authentication is supported, but only if the credentials being sent across in Http basic can be resolved to Windows credentials – which IMHO seems like a scenario where I would just use integrated Windows authentication – but that’s beside the point.  The point is that I want to support the Http basic flow and validate the credentials using my own credential store.  This has been well documented, so I’m not going to repeat all of that detail here, but I do want to tell you about one thing that tripped me up.

Part of my logic reads like this.  “If anonymous access is enabled, then you don’t need to bother processing any further.”  This means that I need to find out whether anonymous access is enabled or disabled.  Now, this isn’t a problem if I’m configuring authentication in my local Web.config, but in my case, I’m setting this on my Web site (custom host) in the IIS management console.

Untitled

When I configure at the site level, the configuration information is added to the applicationHost.config file

 
<location path="basic.test.local">
  <system.webserver>
    <security>
      <authentication>
        <basicauthentication enabled="false" />
        <anonymousauthentication enabled="false" />
      </authentication>
    </security>
  </system.webserver>
</location>

Cool – so I just need to access this information in my HttpModule and figure out if anonymous authentication is turned on – should be simple.  The problem I ran into was that there are multiple ways that look like they should accomplish this task (and one does if you do some other stuff), but only 1 way seems to work they way I expected.

I started out by trying to access config from the current HttpContext

 
var x = currentContext.GetSection( 
  "system.webServer/security/authentication/anonymousAuthentication"); 
anonymousEnabled = (bool)x["enabled"]; 

That didn’t work – it was always null, though it would work if I set the values in my local config file.

So I tried the sledge hammer approach using the IIS admin api

 
using(var serverManager = new ServerManager()) { 
  var config = serverManager.GetApplicationHostConfiguration(); 
  var anonymousSection = config.GetSection( 
    "system.webServer/security/authentication/anonymousAuthentication", 
    "basic.test.local"); 
  anonymousEnabled = (bool)anonymousSection["enabled"]; 
} 

This approach actually did give me the value that I wanted, but there were a couple problems with the approach

  • It required me to give my app domain read permissions to %windir%\system32\inetsvr\config – and that just feels wrong on multiple levels
  • It required me to declare my site name – which seems pretty brittle

What I really wanted was a single API that will project the consolidated configuration information from my local Web.config all the way up to my applicationHost.config – I mean, at the end of the day, IIS needs this information, so certainly it’s exposed somewhere, right?

Yes

 
var y = WebConfigurationManager.GetSection( 
  "system.webServer/security/authentication/anonymousAuthentication"); 
anonymousEnabled = (bool)y["enabled"]; 

If you already knew this, awesome – I wish you had been around to help me.  If you didn’t know this, hope it helps.