我正在尝试在客户端和服务器上设置一个具有证书身份验证的WCF服务。我正在经历地狱,循环浏览所有可能的错误消息。
这里的最终目标是用证书对双方进行身份验证。我将为每个客户颁发一个特定的证书,(希望)能让我把它们区分开来。
到目前为止,我有以下配置文件:
服务器配置文件
<configuration>
<system.serviceModel>
<services>
<service name="ServiceApiImplementation" behaviorConfiguration="myBehaviour">
<host>
<baseAddresses><add baseAddress="http://localhost:9110/MyService"/></baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" contract="IServiceAPI" bindingName="SOAP12Binding">
<identity>
<certificateReference findValue="ServerCertificate" storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName"/>
</identity>
</endpoint>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="SOAP12Binding" receiveTimeout="00:02:00" closeTimeout="00:01:00" openTimeout="00:01:00" sendTimeout="00:01:00">
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="myBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="ServerCertificate" storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
客户端配置文件
<system.serviceModel>
<client>
<endpoint address="http://localhost:9110/MyService" binding="wsHttpBinding"
bindingConfiguration="SOAP12Binding_IServiceAPI" contract="IServiceAPI"
behaviorConfiguration="behaviour1" name="SOAP12Binding_IServiceAPI">
<identity>
<!-- Value obtained when "Adding a Service Reference in visual studio" -->
<certificate encodedValue="xxxxxxxxxxxxx" />
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="behaviour1">
<clientCredentials>
<clientCertificate findValue="ClientCertificate" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName"/>
<serviceCertificate>
<defaultCertificate findValue="ServerCertificate" storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
<authentication certificateValidationMode="ChainTrust" trustedStoreLocation="LocalMachine" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="SOAP12Binding_IServiceAPI">
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
我已经为客户端和服务器生成了一个rootCA和几个证书,赋予了适当的权限,并将它们放入存储中(LocalMachine和CurrentUSer都是出于绝望)。据我所知,这一点正在发挥作用。
调用服务时出现问题。最近的错误是:
收到来自另一方的不安全或不正确的故障聚会有关故障代码和详细信息,请参阅内部FaultException。
无法处理该消息。这很可能是因为操作'http://tempuri.org/IServiceAPI/MyMethod'是不正确,或者因为邮件包含无效或过期的安全上下文令牌,或者因为在绑定。如果服务由于不活动而中止了通道。阻止服务过早中止空闲会话会增加上的接收超时服务端点的绑定。
甚至(以前的错误)
传出邮件的标识检查失败。预期身份是'身份(http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn)'对于'http://localhost:9110/MyService'目标终结点。
根据我在配置文件中的实验,错误消息会有所不同。现在客户端和服务器都在同一台机器上运行,所以,至少,我希望每个应用程序都能通过rootCA对另一个应用程序进行身份验证。
请注意,我使用消息安全性和wsHttpBinding,因为它们似乎是正确的选择。除了发布一个可以被标准JAVA框架使用的服务之外,我没有任何大的限制。
有人能帮我解决这个烂摊子吗?
任何帮助都将不胜感激
此致,
我设法解决了最初的问题。
关于双向证书身份验证,我发现以下代码项目文章提供了一个工作演示:http://www.codeproject.com/Articles/36683/9-simple-steps-to-enable-X-509-certificates-on-WCF#Step%201:-%20创建%20客户端%20和%20服务器%20证书
当然,这个例子使用了对等信任,但到目前为止,我从未能够让一个工作原型无论如何都能工作。从这一点开始,我认为唯一的陷阱是将证书链存储在正确的位置,并将私钥的访问权限授予运行项目的用户。有关如何授予证书私钥权限的解释,请参阅本文:http://msdn.microsoft.com/en-us/library/ff647171.aspx#Step6
对于问题的第二部分:如何在WCF服务中区分客户端证书,您可以使用以下代码来获取客户端的证书指纹:
X509Certificate2 certificate = null;
if(ServiceSecurityContext.Current.AuthorizationContext.ClaimSets == null)
throw new Exception("No claim set");
foreach(var claim in ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
if(claim is X509CertificateClaimSet)
{
X509CertificateClaimSet xcset = claim as X509CertificateClaimSet;
certificate = xcset.X509Certificate;
break;
}
if(certificate == null)
throw new Exception("No X509 certificate found");
string clientCertificateThumbprint = certificate.Thumbprint;
这将获得客户端的指纹,该指纹对于您向其颁发证书的每个客户端都是不同的。当然,所有其他证书数据都是可用的。
无法处理该消息。这很可能是因为http://tempuri.org/IServiceAPI/MyMethod'不正确,或者因为消息包含无效或过期的安全上下文令牌,或者因为绑定之间存在不匹配。如果服务由于不活动而中止通道,则安全上下文令牌将无效。为了防止服务过早中止空闲会话,请增加服务端点绑定上的接收超时。
这表示服务请求超时。请参阅Windows事件查看器或启用服务登录。请参阅:http://msdn.microsoft.com/en-us/library/ms732023.aspx
传出邮件的标识检查失败。所需的标识为"identity"(http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn)'用于'http://localhost:9110/MyService'目标终结点。
这表示indentity
节点错误地指向了错误的位置。自生成证书以来,您是否更改了服务的位置?如果你在事后搬家,那是无效的。