Configuration

Unlocking Configuration Sections in IIS 7.x

One of our administration applications uses Windows authentication so we can manage some Windows services.  In the past we’ve simply changed the authentication method in IIS Manager and moved on but when as we upgraded our development workstations to Windows 7 and IIS 7.5 we started seeing the error:

HTTP Error 500.19 – Internal Server Error

The requested page cannot be accessed because the related configuration data for the page is invalid.

The Detailed Error Information section gave a bit more information:

This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault=”Deny”), or set explicitly by a location tag with overrideMode=”Deny” or the legacy allowOverride=”false”.

The Config Source section was kind enough to narrow down the problem to the <authentication> element.  Since we need Windows authentication for service administration simply switching back to anonymous authentication wasn’t an option.  We really needed to unlock that section.

The page linked from the Links and More Information section has a ton of information about each of the status codes along with links to other knowledge base articles for more details about error conditions.  According to the knowledge base HTTP Error 500.19 has nine possible causes.  This particular issue is listed as issue 9 and is described in detail on IIS.net.

In short, IIS 7.x locking is controlled primarily by the configuration found in the applicationHost.config file located in the %windir%\system32\inetsrv\config\ folder.  Unlocking the section is a matter of moving the security/authentication section to a new location element and setting the overrideMode attribute to “Allow” so it is unlocked for all applications.  Alternatively, the security/authentication information can be duplicated into a new location element with a path attribute identifying a specific application to unlock it for just that application, leaving it locked for all others.

I opted for the later option and simply added a new location element.  Since I was not only enabling Windows authentication but also disabling anonymous authentication I actually had to unlock both.  When I was done my new location element looked like this:

<configuration>
    <!-- Existing Configuration Excluded -->
    <location path="Default Web Site\MyApplication" overrideMode="Allow">
        <system.webServer>
            <security>
                <authentication>
                    <anonymousAuthentication enabled="false" />
                    <windowsAuthentication enabled="true" />
                </authentication>
            </security>
        </system.webServer>
    </location>
</configuration>

With that in place the error disappeared and I was able to use the application as expected.  Unfortunately I did have some trouble actually editing applicationHost.config since I’m running Windows 7 on a 64-bit system and I needed to edit the file with notepad rather than my trusty Notepad++.

10/29/2010 Update:

A colleague pointed me to the “Feature Delegation” icon at the root (computer) level of IIS Manager (Thanks, Ryan).  Clicking into the Feature Delegation page shows a listing of features and their current override setting.  With few exceptions each of the features can be changed to Read/Write, Read Only, or Not Delegated.  There’s also Reset to Inherited option to remove any customization.

Note: Each feature’s context menu includes a “Custom Site Delegation” option that allows the settings to be changed per site (i.e.: Default Web Site) but doesn’t go as far as individual applications.

Unlocking the sections via the Feature Delegation page would certainly have been easier than editing applicationHost.config directly and should be suitable for most development environments. I think I’d probably stick to editing the configuration file for a production server though just for that added layer of protection.

Adventures in Remoting

I was recently given a “special” project that involved .NET Remoting.  One of our customers requires that security is enabled on the remoting channel between a DMZ server and an internal server.  Normally this wouldn’t be a problem, just edit the config files to enable security on the client and server channels and include some credentials on the client channel.  Unfortunately it’s never that simple and our customer has a company-wide policy that requires that any credentials stored within a configuration file be encrypted.

My first thought was to encrypt the credentials using aspnet_regiis or aspnet_setreg.  It turns out that neither of these utilities support encrypting the <system.runtime.remoting> section of configuration files!  This seems odd since other sections that allow credentials can be encrypted with these utilities but ok, what other options do I have?

Up until this point my experience with remoting has been limited to… Ok, you got me.  I have no remoting experience beyond reading the configuration information for a few wellknowns.  I quickly realize that I’m going to have to get deeper into remoting than I ever cared to.  I’ve already determined that the encrypted credentials are going to need to be managed by one of our configuration utilities and somehow programmatically set on the channel.  The problem is how?

My first idea was that since all of the remoting objects derive either directly or indirectly from MarshalByRefObject I could create a utility method that would read the encrypted credentials from our configuration utility, decrypt them, then apply them to the channel sink properties retrieved from ChannelServices.GetChannelSinkProperties for that MarshalByRefObject instance.  This method would be called from the constructor of each of the classes deriving from MarshalByRefObject.  This soon proved to be a futile effort because little did I know that the constructor wasn’t actually called locally so the credentials would never be applied to the channel so the remoting request would still fail.

At this point I feel like I’m running out of options but keep searching and discover that I can create a custom channel sink provider and a custom channel sink.  The documentation I’ve found is scattered but I think I have enough to scrape up something that will work.  One particularly important tidbit I found read:

“On the client side, custom channel sinks are inserted into the chain of objects between the formatter sink and the last transport sink.”

What this meant to me was that I could be sure that the last channel sink was always going to be the transport sink which is where the credentials needed to be set.  If I inserted a custom sink provider into the chain via the configuration file I could use my provider to walk to the end of the channel sink chain and set the appropriate properties!  After about 20-25 minutes I have a class implementing IClientChannelSinkProvider inserted into the provider sink chain and setting credentials exactly as our customer requires.

I’m really happy with the simplicity of this solution.  I only wish that I had found it sooner rather than spinning my wheels on updating constructors that would never be called on the client.  Not that I can do anything about it now but for future reference was there a better way?