如何在 WCF 客户端中同时提供用户名和客户端证书(为什么这个例子有效)? [英] How to supply both UserName and Client Certificate in WCF client (why does this example work)?

查看:35
本文介绍了如何在 WCF 客户端中同时提供用户名和客户端证书(为什么这个例子有效)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一个 WCF 服务,其中的目的是在传输层需要客户端证书(客户端证书在 IIS 中设置为必需").同样,在消息层会有用户名认证.

Consider a WCF service in which the intent is to have Client Certificates required at the Transport layer (Client Certificates set to "Required" in IIS). As well, there will be username authentication at the message layer.

现在我已经看到这个问题了:

Now I've seen this question already:

WCF 客户端证书和用户名凭据被禁止

而且我可以有点理解那里发生了什么,并意识到 WCF 本质上不允许两者兼而有之.我在代码中执行了与上面引用的链接中的海报相同的步骤,并发现了相同的结果……正在传递消息级用户名凭据(在我的情况下是在 SOAP 标头中),但是客户端证书(尽管是在 VS 调试中查看请求客户端时附加)实际上并未被端点处理.

and I can somewhat understand what's going on there and realize that inherently WCF does not allow both. I went through the same steps in code as the poster in the link referenced above and found the same result...the message-level UserName credentials were being passed (in the SOAP header in my case), but the Client Cert (despite being attached when the request client is viewed in VS debug) was not actually being processed by the endpoint.

现在是让我困惑的部分.我决定稍微破解它.我想知道为什么这和我想要的完全一样......它超过了 IIS 客户端证书要求,用户名被传递给 WCF 服务,一切正常.然而 WCF 不允许我只使用 WCF 配置文件或代码(我可以找到)来做到这一点.为什么?

So now comes the part that has me confused. I decided to hack it somewhat. I'm wondering why this works exactly like I'm wanting...it gets past IIS Client Cert requirement, the UserName gets passed to the WCF Service and all just works. Yet WCF does not allow me to do it just using WCF config files or code (that I can find). Why?

            // sets up a proxy client based on endpoint config
            // basically just here to get the URL.
            this.InitializeSubmitClient();

            // these get used to create the HttpWebRequest
            string url = this.submitClient.Endpoint.Address.ToString();
            string action = "SubmitCDA";

            // this deserializes an XML file which is the "shell" of SOAP document and inject username/password into SOAP Security node
            XmlDocument soapEnvelopeXml = XMLHelper.CreateSoapDocument(this.txtSubmitCdaXmlFile.Text, this.txtAdAccount.Text, this.txtPassword.Text);
            HttpWebRequest webRequest = XMLHelper.CreateWebRequest(url, action);

            // saves the SOAP XML into the webRequest stream.
            XMLHelper.InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);

            // attach the cert
            if (this.chkSendClientCert.Checked)
            {
                X509Certificate myCert = X509Certificate.CreateFromCertFile(@"C:\temp\CDX-IHAT_DevClientCert.cer");
                webRequest.ClientCertificates.Add(myCert);
            }
            else
            {
                webRequest.ClientCertificates.Clear();
            }

            // begin async call to web request.
            IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);

更复杂的是,这适用于 WCF 服务是 BizTalk 服务.

To further complicate matters, the WCF Service that this applies to is a BizTalk service.

推荐答案

这是我最终的做法.

服务器配置:

  <customBinding>
    <binding name="CustomCDARequestEndpointBinding">                    
      <textMessageEncoding messageVersion="Soap11" />
      <security authenticationMode="UserNameOverTransport" />
      <httpsTransport requireClientCertificate="true" />
    </binding>
  </customBinding>

客户端配置:

<system.ServiceModel>
  <bindings>
    <customBindings>
      <binding name="CustomBinding_ITwoWayAsync">
          <security defaultAlgorithmSuite="Default"
            authenticationMode="UserNameOverTransport"
            requireDerivedKeys="true"
            includeTimestamp="true"
            messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
          >
            <localClientSettings detectReplays="false" />
            <localServiceSettings detectReplays="false" />
          </security>
          <textMessageEncoding messageVersion="Soap11" />
          <httpsTransport requireClientCertificate="true" />
      </binding>
    </customBinding>
  </bindings>
  <behaviors>
    <endpointBehaviors>
      <behavior name="ohBehave">
        <clientCredentials useIdentityConfiguration="false">
        <clientCertificate findValue="6D0DBF387484B25A16D0E3E53DBB178A366DA954" storeLocation="CurrentUser"
          x509FindType="FindByThumbprint" />            
        </clientCredentials>          
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <client>
     <endpoint address="https://myservice/CDASubmitService/CDASubmit.svc"
        binding="customBinding" bindingConfiguration="SubmitDev" behaviorConfiguration="ohBehave"
        contract="CDASubmitService.CDASubmit" name="SubmitDev" />
  </client>
</system.serviceModel>

让它工作的关键是 <httpsTransport requireClientCertificate="true"/> 元素和 <security authenticationMode="UserNameOverTransport" 元素/属性.

The key to getting it working was the <httpsTransport requireClientCertificate="true" /> element and the <security authenticationMode="UserNameOverTransport" element/attribute.

此配置允许我完全通过配置文件向 WCF (BizTalk) 服务提交消息,而无需更改实际代码.它仍然允许我通过 WebRequest 提交给它,如上所示.

This configuration allowed me to submit a message to a WCF (BizTalk) service completely through configuration files, with no changes to actual code. It still allows me to submit to it VIA WebRequest as well, as shown above.

我必须感谢这篇文章:

WCF 客户端证书和用户名凭据被禁止

还有这个:

将非 BizTalk WCF 配置翻译成 BizTalk WCF-自定义端点

终于让我走上了正轨.我总是回避 WCF 中的自定义绑定,因为我认为它是矫枉过正的,但它们真的没什么疯狂的,只是一种提供比现成可用的更详细配置的方法.

for finally getting me on the right track. I always shied away from Custom Bindings in WCF because I assumed it was overkill, but they are really nothing crazy, just a way to supply more detailed config than is available out of the box.

这篇关于如何在 WCF 客户端中同时提供用户名和客户端证书(为什么这个例子有效)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆