使用客户端开发人员提供的服务证书和自签名客户端证书的Java客户端WCF服务

时间:2012-10-23 21:14:31

标签: c# wcf ssl authentication java-client

我正在开发基于供应商实现的WCF服务,以便从中接收数据。我使用我们的服务器证书使用单向SSL与客户端使用此服务的工作版本。由于最近对其实现进行了更改,我现在需要使用证书而不是用户名和密码来验证其客户端。

他们使用Java开发,我无法控制客户端或他们生成证书的方式。它们不支持WSHttpBinding,所以我必须使用BasicHttpBinding。他们的证书是自签名的,不幸的是在生产中。我尝试使用Transport作为安全性,并根据我们的服务器管理员在我们的服务器上正确安装了他们的证书(我无法访问我们的IIS服务器)。我认为IIS存在证书问题,因为它是自签名的,因此我放弃了该实现。

经过大量研究后,我确定只有通过从OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets[0]获取证书才可以验证服务本身的证书。这是我的第一个WCF服务,所以我相信我已经正确设置但是在从我的WCF测试客户端进行测试时遇到以下错误:The private key is not present in the X.509 certificate。当我从他们的客户那里得到供应商测试时,他们会得到An error occurred when verifying security for the message.

我是否有错误的配置?是否支持此实施?

服务Web.Config:

<?xml version="1.0"?>
    <configuration>
        <system.serviceModel>
                 <behaviors>
                <serviceBehaviors>
                    <behavior name="FileReceiverServiceBehavior">
                        <useRequestHeadersForMetadataAddress/>
                        <serviceMetadata httpsGetEnabled="true"/>
                    </behavior>
                </serviceBehaviors>
            </behaviors>
            <bindings>
                <basicHttpBinding>
                    <binding name="FileReceiverServiceBinding">
                        <security mode="TransportWithMessageCredential">
                            <message clientCredentialType="Certificate"/>
                        </security>
                        <readerQuotas maxStringContentLength="2147483647"/>
                    </binding>
                </basicHttpBinding>
            </bindings>
            <services>
                <service behaviorConfiguration="FileReceiverServiceBehavior" name="FileReceiverService.FileReceiverService">
                    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="FileReceiverServiceBinding" contract="FileReceiverServiceSoap" bindingNamespace="http://www.openuri.org/" />
                    <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
                </service>
            </services>
        </system.serviceModel>
    </configuration>

我的WCF测试客户端配置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="test">
          <clientCredentials>
            <clientCertificate findValue="Users"
                               x509FindType="FindBySubjectName"
                               storeLocation="LocalMachine"
                               storeName="My"/>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_FileReceiverServiceSoap" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None" proxyCredentialType="None"
              realm="" />
            <message clientCredentialType="Certificate" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://mydomain.com/vendor/FileReceiverService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_FileReceiverServiceSoap"
        contract="ServiceReference1.FileReceiverServiceSoap" name="BasicHttpBinding_FileReceiverServiceSoap" behaviorConfiguration="test" />
    </client>
  </system.serviceModel>
</configuration>

更新

供应商向我发送了正确的证书。它是由商业CA颁发的有效证书。当我在本地查看证书时,我可以看到指向受信任根的链,状态显示为“确定”。

如果我使用security mode="Transport"transport clientCredentialType="Certificate"我得到:HTTP请求被禁止使用客户端身份验证方案&#39; Anonymous&#39;

如果我使用security mode="TransportWithMessageCredential"message clientCredentialType="Certificate",我会得到:X.509证书中不存在私钥。

我认为我可能需要严格使用Transport,以便它可以与Java客户端互操作,因此我专注于&#34; HTTP请求被禁止使用客户端身份验证方案&#39; Anonymous&#39;&# 34;错误。这是IIS设置的问题,还是只是在它到达服务器时无法正确验证证书?证书位于“受信任的人”中,我没有尝试过客户certificateValidationMode,也尝试了PeerTrustChainTrustPeerOrChainTrust。任何帮助将不胜感激。

UPDATE2:

我正专注于通过对原始服务器配置进行以下更改并将更改与我的测试客户端进行匹配来实现此功能:

<security mode="Transport">
  <transport clientCredentialType="Certificate"/>

我仍然得到:使用客户端身份验证方案&#39; Anonymous&#39; 禁止HTTP请求。我找到了一个解释here,它基本上证实了服务器无法验证客户端证书。如何让我们的服务器管理员在IIS中配置此应用程序并安装证书以使其正常工作?

1 个答案:

答案 0 :(得分:3)

在我们的评论中经过长时间的讨论后,我会指出你的文章Nine simple steps to X.509 certificates in WCF。我知道这只是一个链接,但它是一篇很长的文章。

似乎您的问题实际上是您的客户没有可以对其进行身份验证的证书。在您拍摄的方案中,每个客户端都需要有一个标识它们的私钥,服务器/服务需要有相应的公钥来验证签名(至少安装在密钥库中)。

您当前的设置似乎每个客户端都将服务器的公钥作为受信任的服务器。因此,您可以让他们通过SSL连接和加密,并且客户端将信任服务器,但服务器实际上不知道客户端是谁,或者至少无法对其进行身份验证而无需识别它们。您之前使用的用户名和密码是以前的识别方式,但现在使用x.509证书,每个拥有用户名 - 密码组合的人都需要一个带私钥的唯一证书才能进行身份验证。

然后,您需要将这些用户映射到Windows / LDAP帐户以便于管理和访问控制,或者您需要实现custom validator(可能还有IIdentity,principal和serivce凭据)为了验证私人证书并“登录”用户。

我希望这对你有所帮助。 Here is one more on x509 custom auth and val

编辑:为响应Update2,尝试在SSL设置下将IIS站点/应用程序设置为“IGNORE用户证书”,并查看是否出现其他错误,反之亦然。如果你将它设置为require,但是代码中没有ASP compatibility模式,IIS没有通过IIdentity,除非你在IIS中设置了某种身份验证方案,否则它可能不会执行任何操作为了你。如果将此设置为忽略,则可以快速设置自定义验证器并查看证书,然后您可以在其上构建链并为其创建某种授权。