如何使用Windows凭据将WCF服务重定向到HTTPS端点

时间:2012-03-14 17:58:43

标签: wcf redirect ssl windows-authentication

以下是我要处理的情况:

我们有一个WCF客户端,它与http端点和https端点一起工作,但在从http重定向(302)到https时却没有。我们有一个F5负载均衡器,它正在执行重定向和SSL功能,但据我所知,它没有对请求做任何意外的事情。重定向似乎是WCF在执行重定向后不希望提供Windows Kerberos身份验证信息的罪魁祸首。

成功通话的顺序(即没有重定向的http)如下:

  • 客户端 - 使用http方案
  • 发送服务的POST请求
  • 服务器 - 回复401未经授权的
  • 客户端 - 发送授权协商POST
  • 服务器 - 以100继续回复
  • 客户端 - 发送肥皂数据并成功完成

当呼叫被重定向并失败时,它会像这样:

  • 客户端 - 使用http方案
  • 发送服务的POST请求
  • 服务器 - 返回302并重定向到同一地址的https方案
  • 客户端 - 为https地址发送 GET (我无法弄清楚为什么这是GET而不是POST)
  • 服务器 - 回复401未经授权的
  • 客户端 - 抛出异常“HTTP请求未经授权使用客户端身份验证方案'协商'。从服务器收到的身份验证标头是'Negotiate,NTLM'。”

它类似于this problem但不完全相同(虽然它确实引用了“破坏WCF协议”,但我没有真正的答案,我可以找到文档)。如果我们关闭F5重定向规则http和https流量工作正常。 WCF真的不能处理这个简单的重定向吗?是否有解决方法或有关此漏洞的任何文档?

客户端配置(请注意,使用https进行测试时,我将TransportCredentialOnly更改为Transport):

<client>
        <endpoint address="http://fooserver/MyService.svc/" binding="basicHttpBinding" bindingConfiguration="clientBinding" contract="Contracts.IMyService" />
</client>
<bindings>
<basicHttpBinding>
    <binding name="clientBinding">
        <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
        </security>
    </binding>
</basicHttpBinding>

服务器配置如下所示:

<system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <services>
        <service behaviorConfiguration="MyServiceBehavior" name="MyService">
            <endpoint address="" binding="basicHttpBinding" bindingConfiguration="securedBinding" contract="Contracts.IMyService">
            </endpoint>
        </service>
    </services>
    <bindings>
        <basicHttpBinding>
            <binding name="securedBinding">
                <security mode="TransportCredentialOnly">
                    <transport clientCredentialType="Windows" proxyCredentialType="Windows"/>
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyServiceBehavior">
                <serviceMetadata httpGetEnabled="true"/>
                <serviceDebug includeExceptionDetailInFaults="true"/>
                <useRequestHeadersForMetadataAddress>
                    <defaultPorts>
                        <add scheme="http" port="80" />
                        <add scheme="https" port="443" />
                    </defaultPorts>
                </useRequestHeadersForMetadataAddress>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

2 个答案:

答案 0 :(得分:1)

  

我无法弄清楚为什么这是GET而不是POST

这是你的问题的原因。收到对POST的302响应后,客户端需要获取新URL的行为。请参阅http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

中的以下内容
  

如果收到302状态代码以响应GET或HEAD以外的请求,则除非用户可以确认,否则用户代理不得自动重定向请求,因为这可能会改变请求的条件。发出的。

此外,以下SO帖子有一些很好的信息:Response.Redirect with POST instead of Get?

因此,WCF通过在302重定向后拒绝重新POST来做它应该做的事情。不幸的是,除了第一次正确指定协议以避免302之外,我不确定如何解决您的问题。

答案 1 :(得分:1)

我刚刚做了类似的事情,我可以确认这不起作用。更糟糕的是,如果不替换默认的WCF HTTP传输实现,可能无法进行更改。

重定向和身份验证都是在内部的WCF HTTP处理中直接处理的。如果您获得 301永久移动并且WCF在重定向后未使用您配置的客户端凭据,则无法手动处理导致问题的重定向。

重定向后发送GET而不是POST的问题理论上应该通过返回 307临时重定向而不是 302 Found 来解决。