WCF配置SSL下的SOAP明文密码认证

3
我有一个应用程序,通过https连接到实现WS-Security的基于SOAP的Web服务。该Web服务是用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> 

客户端会抛出异常。
"安全处理器无法在消息中找到安全头。这可能是因为消息是未经保护的故障,或者由于通信方之间存在绑定不匹配。如果服务配置了安全性而客户端未使用安全性,则可能会发生此情况。"
这似乎是因为客户端发送了时间戳标头,但服务没有返回时间戳标头。这可能是“正确的做法”,但并不是很有帮助,因为有许多Web服务部署在那里,期望有一个时间戳但却没有返回。
如果有办法说服客户端接受这种情况,我想知道。与此同时,我将研究是否可以更改Web服务以返回时间戳。
2个回答

5
尽管我意识到您已经将Mark_S的答案标记为正确,但您可能会发现以下内容解决了您的问题。
您的错误消息在Microsoft Hotfix KB971493中得到了解决:.NET Framework 3.5 SP1可用一个热补丁程序,使WCF能够发送安全消息并接收不安全响应,并发送不安全消息并接收安全响应。
Windows Communication Foundation (WCF)没有发送安全消息然后接收不安全响应或发送不安全消息并接收安全响应的功能。本文所述的热补丁添加了一个新的enableUnsecuredResponse属性。
如果这解决了您的问题,我会很感兴趣。

虽然这正是我想要的,但我想知道如何将BasicHttpBinding用作CustomHttpBinding,但启用enableUnsecuredResponse设置为true?因为BasicHttpBinding中没有enableUnsecuredResponse开关。 - daehaai
@Junto:谢谢,这是一个更好的答案,所以我接受它。不幸的是,我现在无法验证这个问题,但它似乎直接回答了我的原始问题,并且其他人似乎从中受益。 - Eric J.

3

针对您的具体问题,可以参考Stackoverflow和其他网站上的一些类似问题:

有用的教程和屏幕录像链接,详细解释了WCF:MSDN WCF Developer Center拥有从初学者教程到文章和示例代码的所有内容。

此外,我建议您查看Pluralsight关于WCF的屏幕录像 - 这是一个非常好的系列,从“创建第一个WCF服务”和“创建第一个WCF客户端”一直讲到相当高级的主题。Aaron Skonnard在10-15分钟的屏幕录像中非常清楚地解释了所有内容 - 强烈推荐!

@marc_s:感谢您的回复。然而,SO问题似乎暗示您必须手工定制SOAP头。那真的是唯一的解决方案吗?Wordpress链接讨论了配置服务器,而不是客户端。Plurlasight视频需要订阅/付款,并且似乎涵盖了一般的WCF,就我所看到的而言,并没有涉及到具体的问题。 - Eric J.
@Eric J:Pluralsight的屏幕录像绝对不需要任何订阅费用 - 这些都是完全免费的,值得你花时间去学习!至于SOAP头 - 如果您需要发送自定义SOAP头,您可以使用消息契约来定义消息的头和正文元素,或者您将不得不创建一些逻辑来将这些SOAP头注入到消息中。 - marc_s
看起来其中一些是免费的一段时间。“我们提供了一个限时的访客通行证,允许您访问Pluralsight On-Demand!库中每个模块的一些片段。” 我会去看看。我也更新了问题并找到了一些附加信息。非常感谢你的帮助! - Eric J.
@Eric J:啊,好的——嗯,是的,有免费的屏幕录像(screencasts),但当然,Pluralsight也有他们的WCF点播库,需要付费——他们可能会提供一些片段作为试用 :-) 但仅仅这些屏幕录像已经非常有用了。 - marc_s

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接