[英]How to supply both UserName and Client Certificate in WCF client (why does this example work)?
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). 考虑一个WCF服务,其目的是在传输层需要客户端证书(IIS中的客户端证书设置为“必需”)。 As well, there will be username authentication at the message layer.
同样,消息层将有用户名验证。
Now I've seen this question already: 现在我已经看到了这个问题:
WCF Client Certificate AND UserName Credentials forbidden WCF客户端证书和用户名凭据被禁止
and I can somewhat understand what's going on there and realize that inherently WCF does not allow both. 我可以在某种程度上理解那里发生了什么,并意识到WCF本身并不允许这两者。 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.
我在代码中执行了与上面引用的链接中的海报相同的步骤,并找到了相同的结果...消息级别的UserName凭据被传递(在我的情况下在SOAP标头中),但客户端证书(尽管是在VS调试中查看请求客户端时附加的)实际上并未由端点处理。
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.
我想知道为什么这个工作完全像我想要的...它超过了IIS客户端证书要求,UserName被传递给WCF服务,一切正常。 Yet WCF does not allow me to do it just using WCF config files or code (that I can find).
然而,WCF不允许我只使用WCF配置文件或代码(我能找到)。 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);
To further complicate matters, the WCF Service that this applies to is a BizTalk service. 更复杂的是,适用的WCF服务是BizTalk服务。
Here's how I ended up doing it. 这是我最终如何做到这一点。
The Server Config: 服务器配置:
<customBinding>
<binding name="CustomCDARequestEndpointBinding">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="UserNameOverTransport" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
The Client Config: 客户端配置:
<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>
The key to getting it working was the <httpsTransport requireClientCertificate="true" />
element and the <security authenticationMode="UserNameOverTransport"
element/attribute. 使其正常工作的关键是
<httpsTransport requireClientCertificate="true" />
元素和<security authenticationMode="UserNameOverTransport"
元素/属性。
This configuration allowed me to submit a message to a WCF (BizTalk) service completely through configuration files, with no changes to actual code. 此配置允许我完全通过配置文件向WCF(BizTalk)服务提交消息,而不更改实际代码。 It still allows me to submit to it VIA WebRequest as well, as shown above.
它仍允许我提交VIA WebRequest,如上所示。
I have to give credit to this post: 我要赞扬这篇文章:
WCF Client Certificate AND UserName Credentials forbidden WCF客户端证书和用户名凭据被禁止
as well as this one: 以及这一个:
Translate non-BizTalk WCF config into BizTalk WCF-Custom endpoint 将非BizTalk WCF配置转换为BizTalk WCF-Custom端点
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中的自定义绑定,因为我认为它有点矫枉过正,但它们真的没什么了不起的,只是一种提供比开箱即用更详细的配置的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.