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?

Advertisements