Improved .NET Remoting, Part 2: Secure TCP

WEBINAR:On-Demand

.NET remoting enables application communication. It is a generic system that different applications can use to communicate with one another. .NET objects are exposed to remote processes, thus allowing interprocess communication. The applications can be located on the same computer, different computers on the same network, or even computers across separate networks.

Remoting communication is not secure by default, however. The 1.0 and 1.1 versions of the Microsoft Framework offered two options for making it secure:

Use the HttpChannel, host the remoting server inside of IIS, and use SSL to secure communication between the client and server.

Do something similar to this example from Microsoft, which is complicated, not supported, and requires you to create custom code.

The 2.0 version of the Microsoft Framework provides additional security-related functionality within the System.Runtime.Remoting.Channels.Tcp namespace. The TCP communication now can be secured either through code or the application configuration files. The classes support encryption and authentication using the Security Support Provider Interface (SSPI). It relies internally on the NegotiateStream class to secure the communication.

This article shows how to create and consume .NET remoting clients and servers using Visual Studio 2005 and the Microsoft .NET Framework 2.0, focusing on the security enhancements to the TCP channel and how to use them within your applications. It includes the following examples for communicating over secure TCP and securing the communication both in code and through the configuration file:

Create a remotable object.

Create a server to expose the remotable object.

Create a client to connect to the server and consume the object.

Show an example using the configuration file rather than code to control the security.

All you need to follow along is a familiarity with remoting, which you can acquire by referring to a prior article on the topic.

Create a Remotable Object

A remotable object is nothing more than an object that inherits from MarshalByRefObject. The following sample demonstrates a simple class to expose the omnipresent hello world message as an example. This object exposes a single method HelloWorld that will return a string. Anything that is serializable can be returned from the method call.

The first step is to create a new C# class library project. Add a class called SampleObject and put in the following code. Compile the class to make sure you have everything correct.

Create a Server to Expose the Remotable Object via TCP

To create a server object that will act as a listener to accepts remote object requests, you create an instance of the channel and then register it for use by clients on a specific port. You can register the service as WellKnownObjectMode.SingleCall, which results in a new instance of the object for each client, or as WellKnownObjectMode.Singleton, which results in one instance of the object used for all clients.

For this example, create a server listener. Because the service needs to be bound to an available port, choose a port that you know to be unused on your computer. (The example code uses 8080.) To see a list of the used ports on your computer, open a command prompt and issue the command "netstat -a". It may produce a long list, so make sure the command prompt buffer sizes are set to allow scrolling. Compile the class to make sure you have everything correct.

Create a new C# console application project. Add a class called SampleRemotingServer and paste in the following code:

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace CodeGuru.RemotingSample
{
/// <remarks>
/// Sample server to demonstrate the use of secure .NET Remoting.
/// </remarks>
public class SampleRemotingServer
{
public static void Main()
{
// Set up the configuration parameters through a dictionary
IDictionary properties = new Hashtable();
properties.Add("port", 8080);
properties.Add("secure", true);
properties.Add("impersonate", true);
// Create an instance of a channel
TcpServerChannel serverChannel =
new TcpServerChannel(properties, null);
ChannelServices.RegisterChannel(serverChannel);
// Register as an available service with the name HelloWorld
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(SampleObject),
"HelloWorld.rem",
WellKnownObjectMode.Singleton );
Console.WriteLine("Listening on {0}",
serverChannel.GetChannelUri());
Console.WriteLine("Press the enter key to exit...");
Console.ReadLine();
}
}
}

Add a reference in your project to System.Runtime.Remoting; otherwise, the TcpChannel and other related classes will not be found. In addition, add a reference to the project containing the SampleObject. Otherwise, the code will not compile because it won't know how to find a reference to SampleObject.

To secure the communication programmatically, you need to configure the server connection. Notice how the example code passes parameter information in through a Dictionary. You can configure a number of additional parameters (Find more parameters in the VS 2005 Beta Docs on MSDN.) The parameters you will use on the server side for this example are as follows:

port: Specifies the port number on which the channel will listen.

secure: Indicates whether or not the channel is to be secured. (When secured, the channel can require user credentials, as well as encrypt and sign the communication. If the TcpServerChannel is secure, the TcpClientChannel must also be secure. Otherwise, no connection is made.)

impersonate: Indicates whether or not the server should impersonate the client.

Create a TCP Client to Use the Remotable Object

Now that you have your remotable object and a server object to listen for requests, create a client to consume it. The client will be very simple. It will connect to the server, create an instance of the object from the server, and then execute the HelloWorld method.

Create a new C# console application project. Add a class called SampleRemotingClient and paste in the following code:

Add a reference to System.Runtime.Remoting in the project; otherwise, the TcpChannel and other related classes will not be found. In addition, add a reference to the project containing the SampleObject. Otherwise, the code will not compile because it won't know how to find a reference to SampleObject. You could use the Activator object to create a remote instance, but this example simply uses the RemotingConfiguration object to register the SampleObject to be created from the remote location.

You also need to pass parameters to the client channel, which you'll do the same way as the server parameters in the previous section. The parameters you'll use on the client side are as follows:

secure: Indicates whether or not the channel is to be secured. (When secured, the channel can require user credentials, as well as encrypt and sign the communication. If the TcpServerChannel is secure, the TcpClientChannel must also be secure. Otherwise, no connection is made.)

connectionTimeout: Dictates number of milliseconds to wait for a successful connection. (The default value is to wait indefinitely, which you'll change for this example.)

tokenImpersonationLevel: Indicates how the client is to be authenticated with the server.

Improved .NET Remoting, Part 2: Secure TCP

WEBINAR:On-Demand

Putting It All Together to Test the IPC Remoting Sample

Once you have created the projects and successfully compiled each of them, you are ready to try it out. Start the server by running the compiled executable. After the server successfully starts, the console window will display with the message "Press the enter key to exit..." (see Figure 1).

[RemotingServer.jpg]

Figure 1. The Server Successfully Starts

The server is listening, so now you are ready to run the client. Executing the client, whether by running the executable or debugging in Visual Studio, should result in "Hello World!" being displayed in a separate console window (see Figure 2). The window will pause until you press the Enter key to allow you time to see the resulting output message.

[RemotingClient.jpg]

Figure 1.The Client Successfully Executes

You should change some of the sample code. For example, if you change the client tokenImpersonationLevel to "Identification" and run the code, you'll receive an exception because the authentication configuration of the client and server do not match.

Using Application Configuration Files

Setting up the security in the application code is all well and good. However, I personally would prefer not to have to change code to make modifications to the way the security behaves in communication. This is where the application configuration files come into the picture. You can accomplish the same thing you did in the parameter setup of both the client and the server through the use of configuration files. You can set up and control the entire connection through configuration files. Just replace the code for configuring and setting up the channel and move it into the configuration files.

RemotingServerSample Configuration File

Add an application configuration file to your server. The following is the App.config file:

The wellknown element specifies your mode, the object to create, the assembly location, and the URI to assign it. The channel element specifies that you want secure communication, to use port 8080, and to impersonate the user.

The server code becomes much simpler because the channel setup is now pushed into the configuration file:

A Step Towards Secure Computing

.NET remoting is a powerful way to enable interprocess communication. The security enhancements to the Runtime.Remoting.Channels.Tcp namespace are a welcome step towards secure computing. It helps to ensure that objects flowing between your applications are secure during transport.

Future Columns

The topic of the next column is yet to be determined. If you have something in particular that you would like to see explained here, contact me at mstrawmyer@crowechizek.com.

About the Author

Mark Strawmyer

Mark Strawmyer is a Senior Architect of .NET applications for large and mid-size organizations. He specializes in architecture, design and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the fifth year in a row. You can reach Mark at mark.strawmyer@crowehorwath.com.

Advertiser Disclosure:
Some of the products that appear on this site are from companies from which QuinStreet receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. QuinStreet does not include all companies or all types of products available in the marketplace.

Thanks for your registration, follow us on our social networks to keep up-to-date