Конфигурация WCF для аутентификации простого текстового пароля SOAP через SSL
У меня есть приложение, которое подключается через https к веб-службе на основе SOAP, которая реализует WS-Security. Веб-сервис написан на Java, ожидает простой текстовый пароль, а также правильно установленную метку времени.
После долгих поисков и поисков я не могу понять, как настроить мой клиент WCF для взаимодействия с этим сервисом. В дополнение к правильному ответу, я также был бы признателен за ссылку на учебник, который хорошо объясняет WCF и SOAP.
App.config моего текущего клиента выглядит так:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyServiceSoapBinding" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
<!--security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security-->
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://p1.my.com/tx/services/MyService"
binding="basicHttpBinding" bindingConfiguration="MyServiceSoapBinding"
contract="My.IMyService" name="MyServiceEndpointPort" />
</client>
</system.serviceModel>
</configuration>
и код клиента выглядит так:
string response;
try
{
MyService.MyServiceClient svc = new WcfExample.MyService.MyServiceClient();
svc.ClientCredentials.UserName.UserName = "myUser";
svc.ClientCredentials.UserName.Password = "myPass";
response = svc.ping();
lblPingResponse.Text = response;
}
catch (System.ServiceModel.Security.MessageSecurityException mse)
{
lblPingResponse.Text = "MessageSecurityException: " + mse.Message;
}
catch (Exception ex)
{
lblPingResponse.Text = "Exception: " + ex.Message;
}
Этот код вызывает это исключение:
MessageSecurityException "Обработчику безопасности не удалось найти заголовок безопасности в сообщении. Это может быть связано с тем, что сообщение является незащищенной ошибкой или из-за несоответствия между связывающими сторонами. Это может произойти, если служба настроена для обеспечения безопасности и клиента не использует безопасность."
Версия WSE 3 просто требует следующего для работы:
ServiceUsernameTokenManager.AddUser(userName, password);
UsernameToken token = new UsernameToken(userName, password,
PasswordOption.SendPlainText);
proxy = new _MyServiceWse();
Policy policy = new Policy();
policy.Assertions.Add(new UsernameOverTransportAssertion());
policy.Assertions.Add(new RequireActionHeaderAssertion());
proxy.SetPolicy(policy);
proxy.SetClientCredential(token);
ОБНОВИТЬ:
Теперь запрос достигает сервера, и ответ отправляется обратно с сервера с использованием этой конфигурации в app.config:
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
Затем клиент выбрасывает исключение
"Процессору безопасности не удалось найти заголовок безопасности в сообщении. Это может быть связано с тем, что сообщение является незащищенной ошибкой или из-за несоответствия между связывающими сторонами. Это может произойти, если служба настроена для обеспечения безопасности, а клиент не пользуясь безопасностью."
Похоже, это происходит потому, что клиент отправляет заголовок отметки времени, но служба не возвращает заголовок отметки времени. Это, вероятно, "правильная вещь", но она не очень полезна, потому что там развернуто много веб-сервисов, которые ожидают метку времени, но не возвращают ее.
Если есть способ убедить клиента принять эту ситуацию, я бы хотел узнать об этом. В то же время я посмотрю, могу ли я изменить веб-сервис для возврата метки времени.
2 ответа
Хотя я понимаю, что вы уже пометили ответ от Mark_S как правильный, вы можете найти следующее, что решает вашу проблему.
Ваше сообщение об ошибке адресовано в исправлении Microsoft KB971493: исправление, позволяющее WCF отправлять защищенные сообщения и получать незащищенные ответы, а также отправлять незащищенные сообщения и получать защищенные ответы, доступно для.NET Framework 3.5 с пакетом обновления 1 (SP1).
Windows Communication Foundation (WCF) не имеет функции отправки защищенных сообщений, а затем получения незащищенных ответов или отправки незащищенных сообщений и получения защищенных ответов. Исправление, описанное в этой статье, добавляет новый атрибут enableUnsecuredResponse.
Мне было бы интересно узнать, решит ли это вашу проблему.
Что касается вашей конкретной проблемы, взгляните на несколько похожих вопросов о Stackru и других местах:
- Как пройти аутентификацию в сервисах WCF в BasicHttpBinding?
- http://icoder.wordpress.com/2007/06/22/how-to-setup-a-wcf-service-using-basic-http-bindings-with-ssl-transport-level-security/
Ссылки на полезные учебные пособия и скриншоты, подробно объясняющие WCF: есть MSDN WCF Developer Center, в котором есть все, начиная с учебников для начинающих и заканчивая статьями и примерами кода.
Кроме того, я бы порекомендовал вам взглянуть на скриншоты Pluralsight на WCF - это отличная серия от " Создание вашей первой службы WCF" и " Создание вашего первого клиента WCF" вплоть до довольно сложных тем. Аарон Сконнард очень хорошо объясняет все за 10-15 минут скринкастов - очень рекомендуется!