[WCF]Secure a dynamically added message header via behavior extension(part 2)
[WCF]Secure a dynamically added message header via behavior extension(part 2)
This article is the continue of my previous one demonstrating how to secure a custom message header added dynamically in WCF message. In the previous part 1, I use a custom ContractBehavior to inject the security protectionRequirement that is necessary for securing our dynamically added message header.
In this one, I will provide the example that use a custom endpointBehavior to inject the protection requirement for securing dynamic message header. Things different from part1 include:
ü Use endpointBehavior instead of contractBehavior to customize runtime
ü Use an untyped messageheader instead of a user defined typed header
ü Use code to initialize the WCF runtime instead of configuration file(both client and service)
ü Use channelFactory(instead of auto-generated service proxy) to consume service
Here are complete code of the three projects(the same as part1):
l Shared Library
This class library(referenced by both service and client app) include a service contract and a custom endpointbehavior.
namespace SharedLib { [ServiceContract] public interface ITestService { [OperationContract] string GetData(); } /// <summary> /// my custom endpointBehavior class /// </summary> public class SecureHeaderEndpointBehavior : IEndpointBehavior { public string HeaderName { get; set; } public string HeaderNamespace { get; set; } public ProtectionLevel HeaderProtecionLevel { get; set; } public SecureHeaderEndpointBehavior() { } public SecureHeaderEndpointBehavior(string headerName, string headerNamespace, ProtectionLevel pLevel) { HeaderName = headerName; HeaderNamespace = headerNamespace; HeaderProtecionLevel = pLevel; } #region IEndpointBehavior Members public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { ChannelProtectionRequirements requirements = bindingParameters.Find<ChannelProtectionRequirements>(); //identifier for my custom message header XmlQualifiedName qnHeader = new XmlQualifiedName(HeaderName, HeaderNamespace); //set protectionLevel if(HeaderProtecionLevel != ProtectionLevel.None) { requirements.IncomingSignatureParts.ChannelParts.HeaderTypes.Add(qnHeader); if (HeaderProtecionLevel == ProtectionLevel.EncryptAndSign) requirements.IncomingEncryptionParts.ChannelParts.HeaderTypes.Add(qnHeader); } } public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) {} public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) {} public void Validate(ServiceEndpoint endpoint) {} #endregion } } |
l WCF Service
The service provides a simple implementation of the shared service contract:
public class SimpleTestService :ITestService { #region ITestService Members public string GetData() { string data = ""; OperationContext oc = OperationContext.Current; int i = oc.IncomingMessageHeaders.FindHeader("MyDynamicHeader", "urn:test"); XmlDictionaryReader reader = oc.IncomingMessageHeaders.GetReaderAtHeader(i); data = "data from MyDynamicHeader: " + reader.ReadString(); return data; } #endregion } |
And here is the hosting code:
static void RunService() { string baseUrl = "https://localhost:11111/TestService"; using (ServiceHost host = new ServiceHost(typeof(SimpleTestService), new Uri(baseUrl))) { //configure service ServiceMetadataBehavior smb = new ServiceMetadataBehavior(){ HttpGetEnabled = true}; host.Description.Behaviors.Add(smb); WSHttpBinding binding = new WSHttpBinding( SecurityMode.Message); binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows; ServiceEndpoint sep = host.AddServiceEndpoint(typeof(ITestService), binding, ""); host.Open(); Console.WriteLine("service has started..........."); Console.ReadLine(); } } |
l WCF Client
The client application will use channelFactory to consume WCF service. It first inject our custom endpointBehavior and insert an untyped messageHeader before calling method.
static void CallService() { //init client service proxy string epAddress = "https://localhost:11111/TestService"; WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message); binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows; ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>( binding, epAddress); //here we inject our endpoint behavior into the client side proxy factory.Endpoint.Behaviors.Add( new SecureHeaderEndpointBehavior( "MyDynamicHeader", "urn:test", ProtectionLevel.Sign ));
ITestService client = factory.CreateChannel(); using (OperationContextScope scope = new OperationContextScope((IContextChannel)client)) { OperationContext.Current.OutgoingMessageHeaders.Add( MessageHeader.CreateHeader( "MyDynamicHeader", "urn:test", "Some test data..." )); string data = client.GetData(); Console.WriteLine(data); } } |
Comments
- Anonymous
February 18, 2009
PingBack from http://www.anith.com/?p=11593