The 2nd beta of the WCF Security Guide has been released by the Microsoft patterns and practices group.
Saturday, June 28, 2008
Friday, June 27, 2008
Nice series on Separation of Concerns by bogardj
Jimmy Bogard has written a great series of blog posts showing how to refactor some Data Access code to make it more readable, testable and maintainable. The offending (offensive?) code was found in ASP.NET Pro magazine and had static references that precluded doing any unit testing. Jimmy shows how to separate out those dependencies.
Tuesday, June 24, 2008
Fun with C# 3.0 (#2)
This one is a quickie. Auto-implemented properties.
It allows you specify the property and have the compiler automatically define a backing private instance member. It is way cool.
public class Employee
{
public string Name { set; get; }
public string Job { set; get; }
public int Age { set; get; }
}
Fun with C# 3.0 (#1)
This is the first in a series of posts in which I explore new features of C# 3.0 available in Visual Studio 2008.
In this post, I introduce anonymous types and extension methods.
An anonymous type is an unnamed class that you can define simply by specifying the values of its properties. These properties are read-only and can be accessed through the usual property accessor syntax.
var employee = new { Name = "John Smith", Age = 44, Job = "Manager" };
Console.WriteLine(employee.Name);
Console.WriteLine(employee.Age);
Console.WriteLine(employee.Job);
ProcessData(employee);
The class is created at compile-time and the properties are available via IntelliSense. Note, however that if you want to pass the object to another method, it must be passed as an object, since the class is unnamed.
public void ProcessData(object data)
{
}
Once we have the object in our ProcessData method, we need to access the properties via Reflection. Here's where extension methods come in handy. An extension method is a method that is declared as a static method in static class and is in an accessible namespace. It will appear to add new methods to an object type. For example, I can add a method to the String class that removes spaces:
public static class Extend
{
public static string RemoveSpaces(this string s)
{
return s.Replace(" ", "");
}
}
The "this" parameter modifier indicates that it is an extension method and the type of the parameter (string) is the class that is modified. It is called like so:
Console.WriteLine(employee.Name.RemoveSpaces());
To ease the access to our anonymous type properties, we can create an extension method on the object class. The method will be called ValueOf() and will take the name of the property as a parameter:
public static class ReflectionExtensions
{
public static object ValueOf(this object obj, string name)
{
if (name == null) throw new ArgumentNullException("Property Name");
try
{
return obj.GetType().GetProperty(name).GetValue(obj, null);
}
catch (NullReferenceException)
{
return null;
}
}
}
Now in our ProcessData() method we can access the Property values:
public void ProcessData(object data)
{
Console.WriteLine("Employee Name = " + data.ValueOf("Name"));
Console.WriteLine("Employee Age = " + data.ValueOf("Age"));
Console.WriteLine("Employee Job = " + data.ValueOf("Job"));
}
Wednesday, June 18, 2008
Configuring and Supplying a Factory with Unity
Here is a code-sample which allows the Factory to be Container-dependent, and thus configurable in the container setup code. Notice that I registered the unity instance with itself. If you do not do this, when the Factory is created, Unity will see that a UnityContainer is needed by the constructor and instantiate a new UnityContainer, which will not have the correct configuration. If you have registered the configured unity instance, then it will be supplied to the Factory. Also note that the unity configuration can be changed by other parts of the application, so if you want to avoid that, you might want to make a copy of the container inside the Factory constructor.
using System;
using Microsoft.Practices.Unity;
namespace DI
{
#region Container-independent
public interface I { }
public interface IFactory<T>
{
T Create();
}
public class A : I
{
}
public class Aprime : I
{
}
public class B
{
IFactory<I> Ifactory;
public B(IFactory<I> f) { Ifactory = f; }
public void SomeMethod()
{
I a = Ifactory.Create();
Console.WriteLine(a.ToString());
}
}
#endregion
//--------------------------------------------------------------------------------
#region Unity container Dependent
public class Factory<T> : IFactory<T> where T : class
{
UnityContainer container;
public Factory(UnityContainer unity) { this.container = unity; }
public T Create() { return container.Resolve<T>(); }
}
class Program
{
static void Main(string[] args)
{
UnityContainer unity = new UnityContainer();
// register the Unity container so that this instance is provided to factory
unity.RegisterInstance(unity);
// tell Unity to provide A when asked for interface I
unity.RegisterType<I, A>();
// use the Unity enabled factory
unity.RegisterType(typeof(IFactory<I>), typeof(Factory<I>));
B b = unity.Resolve<B>();
b.SomeMethod();
// now tell Unity to provide Aprime when asked for I
unity.RegisterType<I, Aprime>();
b.SomeMethod();
}
}
#endregion
}
See: http://www.codeplex.com/unity/Thread/View.aspx?ThreadId=29697 for a discussion about this.
Container Dependency anti-pattern
It is good design to minimize the number of dependencies between components in a system. Dependency Injection is used to decouple components from each other. A component should not specify, or require, a particular implementation of a Data Service, Logging Service or any other cross-cutting concern.
One solution to this problem is to use a DI container, such as Unity. This localizes all the dependencies in one place, the shell, or configuration point for your application. The components and services can be assembled and provided to the components as needed.
However, sometimes this leads to an anti-pattern in that components are built with a dependency on the container. This counteracts much of the advantage of using the container. It makes it difficult to share your components with another team that might be using a different container. Do not create container dependencies in your components!
The picocontainer example shows how to solve the problem with constructor injection, but assumes that the dependent container (B) only needs one instance of the A object. The question arises how can B create A objects on the fly as needed?
The solution is to inject a Factory into B via the constructor.
using System;
using Microsoft.Practices.Unity;
namespace DI
{
public class A
{
}
public class B
{
Factory<A> Afactory;
public B(Factory<A> f) { Afactory = f; }
public void SomeMethod()
{
A a = Afactory.Create();
Console.WriteLine(a.ToString());
}
}
public class Factory<T> where T : new()
{
public T Create() { return new T(); }
}
class Program
{
static void Main(string[] args)
{
UnityContainer unity = new UnityContainer();
B b = unity.Resolve<B>();
b.SomeMethod();
}
}
}
If you want to have the factory use a specific container, that could be an acceptable dependency, since it would be a trivial change to write a new Factory class for a different container. I will post this later.
See: http://www.codeplex.com/unity/Thread/View.aspx?ThreadId=29697 for a discussion about this.
UPDATE: See http://initializecomponent.blogspot.com/2008/10/common-service-locator.html
Tuesday, June 17, 2008
Stupid .NET Tricks #1
If you like to Unit Test as much as I do, and you're obsessive about putting your strings in Resources files, it can be kind of tricky to make use of these Resources in your Unit Tests.
I'll show you what I mean. You want to unit test the following:
public string login(user, pw)
{
if (!validUser(user, pw))
{
return "Invalid User";
}
}
OK, so we write a test:
public void TestInvalidUser()
{
MyClass m = new MyClass();
Assert.AreEqual("Invalid User", m.login("Me","X"));
}
Now I want to move the error message into the Resources class that Visual Studio generates for you when you use the String editor on the Project Properties dialog. Now we have:
public string login(user, pw)
{
if (!validUser(user, pw))
{
return Properties.Resources.INVALID_USER;
}
}
and
public void TestInvalidUser()
{
MyClass m = new MyClass();
Assert.AreEqual(Properties.Resources.ERROR_INVALID_USER, m.login("Me","X"));
}
The problem is that the Resources class that VS generates for you will have the internal access modifier and will not be accessible to your test code (unless you include the test in the same assembly, which is sub-optimal). To the rescue comes the InternalsVisibleTo attribute. Add it to your production class, specifying the Test assembly as a friend and you code will compile. I've had mixed success getting Intellisense to recognize that it can access the other assembly, however. It doesn't stop it from compiling anyway.
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("AcmeCorp.ProjectX.Tests.TestSecurity")]
Note, also, that if the production assembly is signed, then the test assembly will need to signed as well, and the public key of the friend assembly will need to be specified as part of the assembly name.
Saturday, June 7, 2008
Silverlight 2 Beta 2 available
Announcement on Scott Guthrie's blog.
The highlights:
- 4.8 MB Download that does not require .NET Framework on the target system
- The tools for VS 2008 will work with VS 2008 and VS 2008 SP1 beta
- Adds more controls to beta 1
- Cross-domain socket support
- Background thread networking
- Support for WCF duplex connections
- Datagrid improvements
- Databinding improvements
- Isolated storage is now 1MB with ability to prompt user to increase storage space
Note that if you want to use VS 2008 SP1 with SL 2 Beta 2, you should install VS 2008 SP1 beta first then the SL2B2 tools.
Thursday, June 5, 2008
Unity, WCF and IIS
This is accomplished with a ServiceHostFactory. The @ServiceHost directive has an attribute named, curiously enough, Factory. This can be used to designate a class which will provide a configured ServiceHost. More on that in a moment. Let's see an example of a service that needs constructor-injection.
I've taken the default Service that Visual Studio 2008 gives you when you create a WCF Web Service, and added a SuffixProvider dependency that is satisfied in the constructor.
namespace WcfService1
{
public class Service1 : IService1
{
private ISuffixProvider provider;
public Service1(ISuffixProvider provider)
{
this.provider = provider;
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite.BoolValue)
{
composite.StringValue += provider.GetSuffix();
}
return composite;
}
}
}
namespace WcfService1
{
public interface ISuffixProvider
{
string GetSuffix();
}
}
namespace WcfService1
{
public class MySuffixProvider : ISuffixProvider
{
#region ISuffixProvider Members
public string GetSuffix()
{
return "estericize";
}
#endregion
}
}
Using the UnityWCF project created in the previous post, I will create a factory that is derived from ServiceHostFactory, and configure a Unity container to supply a concrete implementation of ISuffixProvider. I have done this in code, most likely you will want to configure it from an XML file.
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using Microsoft.Practices.Unity;
using UnityWCF;
namespace WcfService1
{
public class UnityServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(
Type serviceType, Uri[] baseAddresses)
{
UnityServiceHost host = new UnityServiceHost(serviceType, baseAddresses);
UnityContainer unity = new UnityContainer();
host.Container = unity;
//configure container
unity.RegisterType<ISuffixProvider,MySuffixProvider>();
return host;
}
}
}
Finally, edit the Service1.svc file to reference the factory class:
<%@ ServiceHost Language="C#"
Debug="true"
Factory="WcfService1.UnityServiceHostFactory"
Service="WcfService1.Service1"
CodeBehind="Service1.svc.cs" %>
Unity and Interception
His conclusion:
As you can see, the extensibility model of Unity works in that we can add
interception to Unity. So, we can start thinking about moving our cross
cutting concerns to these layers should we so choose if Unity is your container
of choice. There are plenty of containers out there to choose from, so
it's best to give them all a try and pick one based upon features, programming
style, and heck, maybe even licensing.
UPDATE: It looks like the Interception Extensions that Matt mentions in his post only work with Unity 1.0. Hopefully someone will update them for Unity 1.1 soon.
Wednesday, June 4, 2008
Integrating Unity with WCF
You might think Unity is great and all, but how can you use it with your WCF services? You might have a service that depends on a data access object, a security object and a logger. How do you get references to these objects into your services when WCF is instanciating your service for you?
You could create static methods that locate and configure these services, like so:
MyLogger logger = MyLogger.getLogger();
MyDAO dao = MyDAO.getDao();
MySecurity security = MySecurity.getSecurityObject();
We all know why that's bad (tightly coupled). We can't change the implementation of any of these objects, or do unit testing with mocks, without changing the code.
With Unity, or any other DI container, we can configure the container and let it resolve the dependencies. Any object that is needs a reference to another object can have it injected through the constructor. All automatically. So how do we force WCF to use the Unity container to create a fully functional service instance for us with all the dependencies resolved? The key is through the magic of an InstanceProvider.
Before I reveal how this is done, I want to show three use cases that we want to be able to solve, and allude to a fourth. These three use cases will be for self-hosted WCF services.
- We have a configured Unity container, and want to create a ServiceHost that will use it.
- We have a configured Unity container, and an existing ServiceHost instance needs to use it.
- We have an existing ServiceHost instance and want to configure it with a new Unity configuration.
Case 1
// Create new ServiceHost
UnityServiceHost host = new UnityServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IService), binding, address);
// Set existing UnityContainer
host.Container = unity;
host.Open();
Case 2
// Create new ServiceBehavior
UnityServiceBehavior behavior = new UnityServiceBehavior();
// Set existing UnityContainer
behavior.InstanceProvider.Container = unity;
// Add behavior to ServiceHost
behavior.AddToHost(host);
host.Open();
Case 3
// let behavior create a new container
UnityServiceBehavior = new UnityServiceBehavior();
// configure new container
behavior.InstanceProvider.Container.RegisterInstance
behavior.InstanceProvider.Container.RegisterInstance(dao);
behavior.InstanceProvider.Container.RegisterType
// Add behavior to ServiceHost
behavior.AddToHost(host);
host.Open();
The fourth use case is running as an IIS-hosted service, which I will leave for a future post.
Creating an InstanceProvider
When WCF needs to create an instance of a service it invokes an instance provider. The default will create the appropriate type using the default constructor, but we can add a ServiceBehavior that will substitute our custom InstanceProvider. Our provider will be configured with a Unity container and call Resolve() when asked for a new Instance.
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;
namespace UnityWCF
{
public class UnityInstanceProvider : IInstanceProvider
{
public UnityContainer Container { set; get; }
public Type ServiceType { set; get; }
public UnityInstanceProvider() : this(null) {
}
public UnityInstanceProvider(Type type)
{
ServiceType = type;
Container = new UnityContainer();
}
#region IInstanceProvider Members
public object GetInstance(
InstanceContext instanceContext, Message message)
{
return Container.Resolve(ServiceType);
}
public object GetInstance(
InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public void ReleaseInstance(
InstanceContext instanceContext, object instance)
{
}
#endregion
}
}
Create the Service Behavior
The Service Behavior's ApplyDispatchBehavior method will be called before the service is instanciated. This is the point where we create and configure our InstanceProvider. The AddToHost method is used to add the behavior to the ServiceHost, ensuring that it is only added once.
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;
using System.Collections.ObjectModel;
namespace UnityWCF
{
public class UnityServiceBehavior : IServiceBehavior
{
public UnityInstanceProvider InstanceProvider
{ get; set; }
private ServiceHost serviceHost = null;
public UnityServiceBehavior()
{
InstanceProvider = new UnityInstanceProvider();
}
public UnityServiceBehavior(UnityContainer unity)
{
InstanceProvider = new UnityInstanceProvider();
InstanceProvider.Container = unity;
}
public void ApplyDispatchBehavior(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase cdb
in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd
= cdb as ChannelDispatcher;
if (cd != null)
{
foreach (EndpointDispatcher ed
in cd.Endpoints)
{
InstanceProvider.ServiceType
= serviceDescription.ServiceType;
ed.DispatchRuntime.InstanceProvider
= InstanceProvider;
}
}
}
}
public void AddBindingParameters(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters) { }
public void Validate(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase) { }
public void AddToHost(ServiceHost host)
{
// only add to host once
if (serviceHost != null) return;
host.Description.Behaviors.Add(this);
serviceHost = host;
}
}
}
Creating the ServiceHost
The UnityServiceHost will encapsulate a UnityContainer and configure itself with the appropriate InstanceProvider and ServiceBehavior, so that the container will be used to Resolve instances when needed.
using System;
using System.ServiceModel;
using Microsoft.Practices.Unity;
namespace UnityWCF
{
public class UnityServiceHost : ServiceHost
{
public UnityContainer Container { set; get; }
public UnityServiceHost()
: base()
{
Container = new UnityContainer();
}
public UnityServiceHost(
Type serviceType,
params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
Container = new UnityContainer();
}
protected override void OnOpening()
{
new UnityServiceBehavior(Container)
.AddToHost(this);
base.OnOpening();
}
}
}
I have to credit Oran Dennison who showed how to integrate WCF and Spring.NET.
More on the Unity Application Block
Unity is basically a slimmed-down version of ObjectBuilder without the support for interceptors.
Here's an interview with Chris Tavares, the lead developer of Unity.
RB: There are quite a few DI containers already, what was the motivation by your team in creating Unity?
CT: Patterns & practices has been giving guidance around dependency injection for a while now. CAB, Mobile client Software Factory, Smart Client Software Factory, Web Client Software Factory, and Enterprise Library have all used DI in various ways. That last word is the killer: “various”. Each project, although they were all build on ObjectBuilder, did DI differently and incompatibly. Having an explicit, fully featured container that we can use unencumbered allows us to provide better guidance around DI and container based architectures.
There are other reasons as well. We have customers that will not touch open source software for whatever reason. Having a DI container from Microsoft makes them feel safer and lets them get the advantages. It also puts them in a good position to later switch containers if they wish.
Another goal is to raise the profile of Dependency Injection both inside and outside of Microsoft. Having a container from Microsoft helps promote DI both to the general Microsoft .NET developer community and internal Microsoft developers as well.
Interceptors would be a good addition to Unity. This would allow deployment-time configuration of cross-cutting concerns, such as logging, performance monitoring, exception handling and security.
Tuesday, June 3, 2008
Common WCF Security Scenarios
Transport Security with Basic Authentication
The application allows clients to log on using custom authentication.
Shows a client and service secured by Windows security.
This scenario uses transport security (such as HTTPS) to ensure confidentiality and integrity.
Shows a client and service secured by a certificate.
Shows a client and service secured by WCF message security.
The client is a Windows Forms application that allows clients to log on using a domain user name and password.
Servers have certificates, and each client has a certificate. A security context is established through Transport Layer Security (TLS) negotiation.
A variation of the certificate client. Servers have certificates, and each client has a certificate. A security context is established through TLS negotiation.
Shows a client and service secured by a Kerberos domain.
Servers have certificates, and each client has a certificate. The server certificate is distributed with the application and is available out of band.
Federated security that enables the establishment of trust between independent domains.
A client accesses one or more Web services that are distributed across a network. The Web services access additional resources (such as databases or other Web services) that must be secured.
Using a Client Certificate to Restrict Access to a WCF Service Method
Service Configuration
We are going to configure our service for Transport and Message Security with a client certificate, and we are going to add an attribute to a service method to restrict access only to clients that present the correct certificate. We will use the WSHttpBinding. The port is already configured for https from this post.
First configure the binding:
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
To designate the certificate that is permitted to access the service method, you will need to know the subject name and thumbprint of the certificate. Import System.Security.Permissions and decorate the method with the following attribute:
[PrincipalPermission(SecurityAction.Demand,
Name = "CN=joeuser.example.com; ddf5066afceb34a95ff75795ced345ff549464202")]
Here the Name parameter is equal to the certificate Subject followed by a semi-colon, a space, then the certificate Thumbprint. Multiple attributes can be added to support more than one client certificate. The final configuration option is to set the mode on the service to map the certificate information to this format (Subject; Thumbprint). This is done through the ServiceBehaviorAuthorizationMode (set it to UseAspNetRoles). You will need to import System.ServiceModel.Description.
ServiceHost host = ...
ServiceAuthorizationBehavior b = host.Description.Behaviors.Find
b.PrincipalPermissionMode = PrincipalPermissionMode.UseAspNetRoles;
Client Configuration
Now we need to tell the client which certificate to present to the service. The same method is called whether you are using a Client Proxy or have created a ChannelFactory. I will show the example using a ChannelFactory. This must be done before creating the Channel.
factory.Credentials.ClientCertificate.SetCertificate(
System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySerialNumber,
"1a2fa58b000000003a5c");
In this case, I am looking it up by Serial Number, but the certificate can be found by Thumbprint, Subject Name, or a number of other fields. Again, use the MMC Certificate Snap-in to look up the information.
That's all there is to it.
Configuring a WCF Binding for https
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
or simply
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
For WSHttpBinding:
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.
TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Here is a summary of the System-provided Bindings. Note that the NetTcp bindings have Transport security (encryption) enabled by default.
Configuring a port for SSL/TLS
--------------
If you want to use Transport Security with your http WCF service, there are two options:
- Host your service in IIS.
- Configure a port for SSL/TLS and self-host your web service. This will allow you to create a Windows Service that runs your web service over https.
Either way, you will need a certificate that identifies your host as trusted to the client and provides the public and private keys that are used for negotiating the encrypted transfer. For a production environment you will need to obtain the certificate from a Certificate Authority (CA).
For development and testing, we can create our own CA and then issue a test certificate from that CA. It can't be used in production because the clients will not have a trusted relationship with that CA, but we will configure our test client to trust it. You will need the MMC snap-in from my previous post. Run MMC and Open the SSL Snap-in that you previously configured. This way you will see the certificates as they are created in the Certificate Store.
You will also need the makecert.exe tool. You will have it if you have Visual Studio or the .NET Framework SDK. Go to your Start Menu and run the appropriate Command Line Environment.
Finally, you will need httpcfg.exe (download for Windows XP SP2). Vista users will use netsh.exe. This tool will be used to associate the certificate with the port.
The instructions for creating the certificate are based on Chris Jackson's post.
Create the CA certificate
At the command line (all one command),
makecert -pe -n "CN=Test and Dev Root Authority" -ss my -sr LocalMachine -a sha1 -sky signature -r "Test and Dev Root Authority.cer"
Now, if you look in the Local Computer (-sr LocalMachine) section of the SSL Certificates MMC Console, you will find a certificate in the Personal\Certificates folder (-ss my). You may need to refresh (F5) the folder.
Create the Test Certificate
Next, we will create the certificate to be assigned to the port. The name of the certificate must match the hostname in the URL that the client will use to access the service. Otherwise, the client will refuse to complete the handshake. Sometimes you get this error in your browser when the certificate name does not match the URL. Just as in the browser scenario, it is possible to configure the WCF client to ignore the mismatch, but I will leave that to a future post.
If you want to access the service via https://testserver:8081/service, enter the following at the command line (all one command),
makecert -pe -n "CN=testserver" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in "Test and Dev Root Authority" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 "Test and Dev SSL.cer"
Again, you will find a new certificate in the Personal\Certificates folder on the Local Computer main node. If you double-click to view it you will see that it is not trusted. That is because your computer does not trust the CA certificate that we made and used to sign the testserver certificate.
Trust the CA
To trust the new CA certificate drag it from the Personal\Certificates folder to the Trusted Root Certificate Authorities\Certificates folder below it. Now if you open the testserver certificate, it will show as valid.
Configure the port for https
The last step is to configure a port (8081 in this example) to use the testserver certificate for SSL/TLS. The HTTP.SYS driver will use the certificate's thumbprint to look it up in the certificate store, so open the testserver certificate and go to the details tab. Scroll to the bottom and select the Thumbprint property. The text box below it will show the value with spaces:
71 d1 ea 2b 7d 2e cf 75 ac a5 60 1f 66 94 9b b6 ee aa be 44.
We will use the httpcfg.exe command to configure it. It is probably located in C:\Program Files\Support Tools. You will need to remove the spaces from the thumbprint hash value.
httpcfg set ssl -i 0.0.0.0:8081 -h 71d1ea2b7d2ecf75aca5601f66949bb6eeaabe44 -f 2
The -f 2 option will allow us to use client certificates to authenticte the client in a later post. The 0.0.0.0 IP address means all IP addesses on the computer. If you only want to associate it with a single IP address, use that one.
Now you can configure your service to listen on https.
Monday, June 2, 2008
Viewing SSL/TLS Certificates
These articles explain:
How to View Certificates with the MMC Snap-in.
How to retrieve the Thumbprint of a Certificate.
Once you have the hash value for the certificate, it is used as a lookup by the HTTP.SYS driver to locate the server certificate that will be used for https encryption/decryption. I'll explain how to configure the HTTP.SYS driver for SSL/TLS in a future post.