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

3
我正在开发一个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颁发的有效证书。当我本地查看该证书时,可以看到链到可信根并且状态显示为“OK”。

如果我使用security mode="Transport"transport clientCredentialType="Certificate",则会得到:HTTP请求被禁止,客户端身份验证方案为“Anonymous”

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

我认为我可能需要严格使用Transport以便与Java客户端互操作,因此我正在专注于“HTTP请求被禁止,客户端身份验证方案为'Anonymous'”错误。这是IIS设置的问题还是在服务器端无法正确验证证书?该证书在受信任的人员中,并尝试了无客户端certificateValidationMode,但也尝试了PeerTrustChainTrustPeerOrChainTrust。非常感谢您的帮助。

更新2:

我正在专注于对我的原始服务器配置进行以下更改,并将其匹配到我的测试客户端上:

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

我仍然收到:HTTP请求被禁止,客户端身份验证方案为“匿名”。我在这里找到了一个解释(链接),基本上确认了服务器无法验证客户端证书。 我该如何让我们的服务器管理员在IIS中配置此应用程序并安装证书,以便正确运行?

@Rajesh,我使用正确的证书仍然遇到相同的错误。请查看我的更新以获取完整信息。 - user1769388
@user1769388 我没有看到你在web.config中添加自定义验证的地方(你在上面提到了这个)。请查看MSDN关于自定义证书验证的内容:http://msdn.microsoft.com/en-us/library/ms733806.aspx - iMortalitySX
@user1769388,私钥不存在的错误可能表明“algorithmSuite”的选择存在问题。尝试在双方都明确设置它,因为某些证书不支持所有不同的套件。我必须先将我的设置为仅DES,然后再逐步升级。测试这一点的好方法是在证书上设置一个PIN码(或密码),当访问签名(通过客户端)时,它应该提示您,如果没有,则表示该证书不支持您的签名算法。 - iMortalitySX
@user1769388 嗯,不,要实际进行自定义验证,您需要扩展一些基类。请查看此CodeProject以获取相关信息:http://www.codeproject.com/Articles/33872/Custom-Authorization-in-WCF。但我认为您并没有试图走得那么远,是吗? - iMortalitySX
@user1769388 你是否应该同时拥有公钥和私钥取决于你的配置。如果你只从服务器(SSL)加密,那么只需要公钥。但是,如果你最终设置了服务凭证并必须从服务签署消息,则服务器实际上也需要私钥进行签名,每个客户端需要与之匹配的公钥(更复杂但更安全)。 - iMortalitySX
显示剩余6条评论
1个回答

3
在我们的评论区进行了长时间的讨论后,我想指向这篇文章WCF中X.509证书的九个简单步骤。虽然它只是一个链接,但是它是一篇非常长的文章。
看起来你的问题实际上是你的客户端没有证书可以用来认证他们。在你所追求的方案中,每个客户端都需要有一个私钥来识别他们,而服务器/服务需要拥有相应的公钥来验证签名(至少安装在密钥存储中)。
你目前的设置似乎是每个客户端都将服务器的公钥作为受信任的服务器。因此,您可以让他们通过SSL连接和加密,并且客户端将信任服务器,但实际上服务器并不知道客户端是谁,或者至少没有什么可以识别他们的东西。你之前的方式,使用用户名和密码,是他们以前被识别的方式,但现在使用x.509证书,每个拥有用户名-密码组合的人都需要一个带有私钥的唯一证书才能进行身份验证。
然后,您需要将这些用户映射到Windows/LDAP帐户以便进行简单的管理和访问控制,或者您需要实现一个自定义验证器(可能还需要IIdentity、principal和service凭据)来验证私有证书并“登录”用户。
我希望这对您有所帮助。这里还有一个关于x509自定义身份验证和验证的链接

编辑:响应更新2,尝试在SSL设置下将IIS网站/应用程序设置为“忽略用户证书”,看看是否会出现不同的错误,反之亦然。如果您将其设置为需要,但未在代码中启用 ASP兼容性模式,则IIS不会传递IIdentity,并且除非您在IIS中设置了某种身份验证方案,否则它对您没有任何作用。如果将其设置为忽略,则可以快速设置自定义验证器并查看证书通过,然后可以构建链并在其上创建某种授权。


我在尝试设置这个时早先看到了你的第一个链接。问题是,他正在创建服务、客户端以及两个证书。我正在开发基于我们交易伙伴提供的WSDL的服务,以便他们可以从他们的Java客户端进行消费。他们不支持我为他们创建客户端证书的情况。他们仅支持提供他们的证书以验证传入请求时我们的服务器证书。 - user1769388
你的第三段基本上是正确的,除了他们只会为一个Web应用程序拥有一个客户端,通过传递他们公司的证书。考虑到这一点,是否有办法使用我们的服务器证书设置SSL,然后使用他们的证书进行身份验证?正如我在我的更新中所说,我认为我可能必须使用Transport安全性以实现互操作性。如果我们在存储中安装了他们的证书,难道没有办法让IIS验证他们的证书吗? - user1769388
将IIS更改为忽略但保留我的服务会导致“服务'SslRequireCert'的SSL设置与IIS'Ssl'不匹配”。IIS没有将其传递,但我正在尝试设置IIS进行身份验证,因为我最近验证了他们希望在握手期间进行身份验证,而不是通过请求传递证书。我认为我也意识到(我应该更早地意识到)我无法使用他们的证书正确测试此功能,因为它没有他们的私钥,握手将失败。 - user1769388
感谢您的所有帮助。我们的服务器管理员决定此服务不需要。 - user1769388

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接