Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Tuesday, August 12, 2008

Web Services Security Guide for WCF

Microsoft Patterns and Practices has released the WCF security guide.

Parts

Part I, "Security Fundamentals for Web Services"
Part II, "Fundamentals of WCF Security"
Part III, "Intranet Application Scenarios"
Part IV, "Internet Application Scenarios"

Tuesday, July 1, 2008

Saturday, June 28, 2008

Thursday, June 5, 2008

Unity, WCF and IIS

In a previous post, I showed how to integrate Unity with WCF when you are self-hosting a service. What's not clear is how to get IIS to use the Unity-enabled host when it starts hosting your service.

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" %>

Wednesday, June 4, 2008

Integrating Unity with WCF

Update (Feb 14, 2012): I fixed an issue in the code.

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.

  1. We have a configured Unity container, and want to create a ServiceHost that will use it.
  2. We have a configured Unity container, and an existing ServiceHost instance needs to use it.
  3. We have an existing ServiceHost instance and want to configure it with a new Unity configuration.
Here is what these use cases will look like in code:

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(logger);

behavior.InstanceProvider.Container.RegisterInstance(dao);

behavior.InstanceProvider.Container.RegisterType(typeof(MySecurity));
// 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.

Tuesday, June 3, 2008

Common WCF Security Scenarios

An example of a public, unsecured client and service.
A basic Windows Communication Foundation (WCF) service developed to provide information on a secure private network to a WCF application.
Transport Security with Basic Authentication
The application allows clients to log on using custom authentication.
Transport Security with Windows Authentication
Shows a client and service secured by Windows security.
Transport Security with an Anonymous Client
This scenario uses transport security (such as HTTPS) to ensure confidentiality and integrity.
Transport Security with Certificate Authentication
Shows a client and service secured by a certificate.
Message Security with an Anonymous Client
Shows a client and service secured by WCF message security.
Message Security with a User Name Client
The client is a Windows Forms application that allows clients to log on using a domain user name and password.
Message Security with a Certificate Client
Servers have certificates, and each client has a certificate. A security context is established through Transport Layer Security (TLS) negotiation.
Message Security with a Windows Client
A variation of the certificate client. Servers have certificates, and each client has a certificate. A security context is established through TLS negotiation.
Message Security with a Windows Client without Credential Negotiation
Shows a client and service secured by a Kerberos domain.
Message Security with Mutual Certificates
Servers have certificates, and each client has a certificate. The server certificate is distributed with the application and is available out of band.
Message Security with Issued Tokens
Federated security that enables the establishment of trust between independent domains.
Trusted Subsystem
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.
from MSDN

Using a Client Certificate to Restrict Access to a WCF Service Method

This post is based on this article.

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

Both BasicHttpBinding and WSHttpBinding support Transport Security (https). However, neither do it by default. The binding must be configured correctly. Here is how to do it in code:

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

Note that what we usually refer to as SSL is now really TLS (Transport Layer Security).
--------------
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.

Saturday, May 31, 2008

WCF Books

Learning WCF: A Hands-on Guide by Michele Leroux Bustamante
A good beginners guide to WCF.

Programming WCF Services by Juval Lowy
Explains the architectural aspects of WCF and how it was engineered.

Essential Windows Communication Foundation (WCF): For .NET Framework 3.5 by Steve Resnick, Richard Crane, Chris Bowen
Good guide to the changes introduced by Visual Studio 2008 and .NET 3.5


Inside Windows Communication Foundation by Justin Smith
This is a great reference to WCF internals. Advanced programmers only.