I have a simple WCF Client -> Server structure, where the client references the server's WCF service. Authentication is done using X509 certificates.
I want to add a simple form of redundancy to my service. Meaning- to have several servers running, and have the client use a router that would transparently fail-over to a backup server if the main one is dead.
I've looked at WCF 4.0 routing but that was no good.
So what's left is to do that on my own. I've found a nice example that does just that.
However, the author did not use any security at all.
I've tried to add message-level security by adding the following to the router's <client>
binding configuration (I copied it from my existing client's configuration):
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="false"
algorithmSuite="Default" establishSecurityContext="false" />
</security>
using this, I get a
The client certificate is not provided. Specify a client certificate in ClientCredentials.
exception from my server.
So I manually added the certificate to the channel I create in my router's code (complete listing here):
[ServiceContract(Name = "IntermediateServiceManager")]
public interface IIntermediateServiceContract
{
[OperationContract(Name = "ProcessMessage", Action = "*", ReplyAction = "*")]
Message ProcessMessage(Message message);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, AddressFilterMode = AddressFilterMode.Any)]
public class IntermediateServiceManager : IIntermediateServiceContract
{
public Message ProcessMessage(Message requestMessage)
{
ChannelFactory<IIntermediateServiceContract> factory = new ChannelFactory<IIntermediateServiceContract>("MyEndpoint");
factory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,StoreName.My,X509FindType.FindBySubjectName,"mycert.company.com");
IIntermediateServiceContract proxy = factory.CreateChannel();
IClientChannel clientChannel = proxy as IClientChannel;
Message responseMessage = proxy.ProcessMessage(requestMessage);
return responseMessage;
}
}
and now the error I get is
Multiple headers with name 'Security' and namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' and role '' found`.
I've turned on WCF diagnostic, and compared the headers of the message sent from the router with those sent from the client. and indeed, the router messages have 2 security headers.
I'm assuming one was originally added by the client (since it doesn't know that it's now working against a router- it still thinks that this is the actual server), and the second one by the router.
So, logically, the next thing to do is to disable the security I've added at first to the router configuration (simply changed security mode
to None
).
And now the exception I get is
The 'To', 'http://www.w3.org/2005/08/addressing' required message part was not signed
I'm assuming this means that my router has changed the message's To
field, and since no security was configured- the router didn't sign it...
So I guess I'm kind of stuck. The two options I'm currently considering are:
- Somehow tamper with the message's headers and remove the redundant security header.
- Disable security between the client and the router, and have security only between the router and the service.
This, however, has the disadvantage of having to change the client, which I don't want to do.
Any ideas?