![](/img/trans.png)
[英]How to configure a wcf service client to use both certificate and username credentials at the message level?
[英]WCF Client Certificate AND UserName Credentials forbidden
我在让 WCF 客户端连接到需要客户端证书和用户名/密码的服务器时遇到问题。
我已经验证使用 JUST 客户端证书可以使用这个:
var binding = new WSHttpBinding(SecurityMode.Transport);
binding.Security.Transport = new HttpTransportSecurity();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var ea = new EndpointAddress(EndpointUrl);
using (var p = new ServiceReference1.AAAClient(binding, ea))
{
try
{
p.ClientCredentials.ClientCertificate.SetCertificate(
System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
CertificateSubject);
var x = p.RequiresClientCertificateOnly();
Console.WriteLine("Status: " + x.status);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine();
}
下一个合乎逻辑的步骤是添加用户名/密码部分,但它返回 403 未经授权。 我知道凭据和证书是有效的,因为我在中间使用了 fiddler 来提供客户端证书和用户名/密码,并且它工作正常,只是通过 WCF 使用它似乎不起作用,或者同时使用发送客户端证书和用户名/密码。
尝试使用两者的代码如下(尝试使用 WSHttpBinding 和 BasicHttpBinding - 两者的结果相同):
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
var ea = new EndpointAddress(EndpointUrl);
using (var p = new ServiceReference1.PingPortTypeClient(binding, ea))
{
try
{
p.ClientCredentials.ClientCertificate.SetCertificate(
System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
CertificateSubject);
p.ClientCredentials.UserName.UserName = Username;
p.ClientCredentials.UserName.Password = Password;
var x = p.pingDatabase();
Console.WriteLine("Status: " + x.status);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine();
当我直接在浏览器中转到 URL 时 - 我收到错误消息:
HTTP 错误 403.7 - 禁止 您尝试访问的页面要求您的浏览器具有 Web 服务器可识别的安全套接字层 (SSL) 客户端证书。
这表明在上面的第二个示例中没有发送证书,因为它收到了相同的错误 (403)。
有人可以帮我配置 WCF 以提供客户端证书和用户名/密码吗? 我浏览了网络,这里的“类似问题”根本没有帮助。 现在变得非常沮丧 - 我错过了什么?
如果您需要用户名(消息级别)和证书(传输级别),则必须使用自定义绑定。 例如:
<customBinding>
<binding name="NewBinding0">
<textMessageEncoding messageVersion="Default" />
<security authenticationMode="UserNameOverTransport">
<secureConversationBootstrap />
</security>
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
messageVersion 的值取决于您是要使用 WSHttp 还是 BasicHttp。 目前我已将其设置为“默认”,即 WSHttp,对于 Basic,将其设置为“Soap11”。
不是这个问题的答案,但问题标题把我带到了这里,所以也许其他人也有:
我需要一个 Soap11 绑定,同时具有证书(对于网关)和传输级别(对于应用程序)的用户名。 (这两个部件都由客户现场的不同团队和不同供应商维护。)
尽管名称为带有UserNameOverTransport
的customBinding
在 Soap-header(消息级别)中发送用户名和密码,而不是在 http-header(传输级别)中,导致SecurityRequestChannel.ProcessReply
此内部FaultException
源自应用程序:
FaultException: MustUnderstand headers: [{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood.
将basicHttpBinding
与<security mode="TransportCredentialOnly">
会导致:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
经过大量的反复试验,结果证明这可以通过组合配置和代码来完成。
<basicHttpBinding>
<binding name="myBasicHttpBindingForTransportCertificate">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
<endpointBehaviors>
<behavior name="myCertificateBehavior">
<clientCredentials>
<clientCertificate findValue="my certificate subject" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
</clientCredentials>
</behavior>
(我使用这个答案动态加载了它。)
using (new OperationContextScope(client.InnerChannel))
{
…
var httpRequestProperty = new HttpRequestMessageProperty();
httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] =
"Basic " + Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes($"{username}:{password}"));
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
(感谢这个对“WCF TransportCredentialOnly 不发送用户名和密码”的旧回答。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.