Lukas
Lukas

Reputation: 613

WCF service behind loadbalancer with custom authorization

Our environment is based on server application which exposes service through WCF. Out customer uses a load balancer - F5. Client application hits it through secured channel and later it uses non-secured HTTP channel. Both client and server uses WsHttpBinding.

Client <> HTTPS <> F5 <> HTTP <> Server

I managed to work with such configuration, but our service uses custom authorization based on JWT tokens and then problem occurs.

I've tested many configurations, but there were various errors.

Currently configuration of client:

var binding = new WSHttpBinding();
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;

binding.Security.Mode = SecurityMode.TransportWithMessageCredential;

binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = true;

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;

Server configuration looks like:

var binding = new WSHttpBinding();
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;

host.Description.Behaviors.Find<ServiceBehaviorAttribute>().AddressFilterMode = AddressFilterMode.Any;

binding.Security.Mode = SecurityMode.None;

binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = true;

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;

host.Description.Behaviors.Find<ServiceAuthorizationBehavior>().ServiceAuthorizationManager = new JWTAuthorizationManager();

Client application sets authorization headers in such way:

channelFactory.Credentials.UserName.UserName = userId;
credentialBehaviour.UserName.Password = token;

Current status is that request goes to the service, but in CheckAccess() method from JWTAuthorizationManager HttpRequestHeader.Authorization is empty. Moreover System.ServiceModel.MustUnderstandSoapException is thrown. When I switched Security.Mode of client to Transport same thing happens but exception isn't thrown.

I'm not familiar with the details of this technology and I'm not sure what really happens.

UPDATE: I've checked what is received by service. I see that Security header exists in the message, but service can't interpret this because of Security Mode set to None. I can't set this to Message because it requires certificate on the server machine, we don't want this.

wireshark'ed message

Upvotes: 0

Views: 353

Answers (1)

Lukas
Lukas

Reputation: 613

I managed with this problem using CustomBinding at the server side:

var binding = new CustomBinding();
var securityHeader = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityHeader.AllowInsecureTransport = true;
securityHeader.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
securityHeader.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
securityHeader.IncludeTimestamp = true;

var textEncoding = new TextMessageEncodingBindingElement();
textEncoding.MessageVersion = MessageVersion.Soap12WSAddressing10;
binding.Elements.Add(textEncoding);

var httpTransport = new HttpTransportBindingElement();
httpTransport.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
httpTransport.MaxReceivedMessageSize = int.MaxValue;
httpTransport.MaxBufferPoolSize = int.MaxValue;
binding.Elements.Add(httpTransport);

Upvotes: 0

Related Questions