Служба WCF за балансировщиком нагрузки с пользовательской авторизацией

Наша среда основана на серверном приложении, которое предоставляет услуги через WCF. Наш клиент использует балансировщик нагрузки - F5. Клиентское приложение обращается к нему через защищенный канал, а затем использует незащищенный канал HTTP. И клиент, и сервер используют WsHttpBinding.

Клиент ‹> HTTPS ‹> F5 ‹> HTTP ‹> Сервер

Мне удалось работать с такой конфигурацией, но наш сервис использует пользовательскую авторизацию на основе токенов JWT, и тогда возникает проблема.

Я протестировал много конфигураций, но были разные ошибки.

Текущая конфигурация клиента:

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;

Конфигурация сервера выглядит так:

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

Клиентское приложение устанавливает заголовки авторизации следующим образом:

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

Текущий статус - запрос идет к сервису, но в методе CheckAccess() из JWTAuthorizationManager HttpRequestHeader.Authorization пусто. Кроме того, создается исключение System.ServiceModel.MustUnderstandSoapException. Когда я переключил Security.Mode клиента на Transport, происходит то же самое, но исключение не выдается.

Я не знаком с деталями этой технологии и не уверен, что происходит на самом деле.

ОБНОВЛЕНИЕ: я проверил, что получает служба. Я вижу, что в сообщении есть заголовок безопасности, но служба не может его интерпретировать, поскольку для режима безопасности установлено значение «Нет». Я не могу установить для этого значение «Сообщение», потому что для этого требуется сертификат на сервере, а нам это не нужно.

сообщение от wireshark


person Lukas    schedule 03.07.2019    source источник
comment
На данный момент я вижу два решения, но не знаю, как их достичь: 1. Использовать BasicHttpBinding на сервере с режимом безопасности TransportCredentialOnly. Он отлично работает без Load Balancer, но когда клиенту необходимо использовать защищенный канал для F5 с помощью WsHttpBinding, версия SOAP меняется. 2. Используйте эквивалент WsHttpBinding с возможностью SecurityMode None. Я пробовал CustomBinding, но безуспешно.   -  person Lukas    schedule 04.07.2019


Ответы (1)


Я справился с этой проблемой, используя CustomBinding на стороне сервера:

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);
person Lukas    schedule 05.07.2019