背景(有点长):
几年前,我为客户编写了一个 WCF 服务,该服务配置为使用 basicHttpBinding,安全模式 = "Transport",clientCredentialType = "Certificate",即客户端使用(客户端)证书对自己进行身份验证。该服务使用自定义 AuthorizationManager 检查传入证书的指纹是否存在于有效证书指纹的预定义列表中。如果传入的证书被认为是有效的,则允许操作继续(如果不是,则抛出异常)。
该服务已经完美运行了大约四年,每个人都很高兴。然而,由于经常发生需求变化,最近开发人员联系了我的客户,希望将他们的应用程序连接到我的客户服务。唯一的问题是这些开发人员正在使用 Java 的一些变体作为他们的首选平台,现在我们面临着一些严重的问题。长话短说,没有人设法让他们的 Java 实现(例如 Metro、Axis2)与当前配置的服务一起工作。
上周,我们尝试通过将绑定更改为安全模式 =“TransportWithMessageCredential”和 Message clientCeredentialType =“UserName”的 wsHttpBinding 来使其与用 Java(Metro、JAX-WS)编写的客户端一起工作。我还在配置文件中的服务凭证元素中添加了一个自定义 UserNamePassWordValidatorType。
然后我注释掉了自定义 AuthorizationManager,因为没有来自客户端的证书。
瞧,这一次我们让 SoapUI 和 Java 客户端都可以与服务对话。
(顺便说一句,我们的服务在 Windows 服务中自托管)
很高兴,我们决定使用两个绑定配置服务,现有的基本HttpBinding 已经运行了很长时间而没有出现故障,以及新测试的 wsHttpBinding。所以我们会有类似的东西:
<services>
<service name="SuperDuperService" behaviorConfiguration="superDuperBehaviour">
<endpoint binding="basicHttpBinding" contract="ISuperDuperService" bindingConfiguration="SecureTransport"/>
<endpoint binding="wsHttpBinding" address="stws" contract="ISuperDuperService" bindingConfiguration="SecureTransportAndSoap"/>
<endpoint binding="mexHttpsBinding" address="mex" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://<url + port>/SuperDuperService"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="SecureTransport" maxBufferSize="2065536" maxBufferPoolSize="524288" maxReceivedMessageSize="2065536">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
<readerQuotas maxDepth="32" maxStringContentLength="6553600" maxArrayLength="2065536"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
<wsHttpBinding>
<binding name="SecureTransportAndSoap">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="superDuperBehaviour">
<serviceCredentials>
<!-- The following element specifies the certificate use by this service for HTTPS (SSL) based transport security -->
<serviceCertificate findValue="<some identifier>"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode ="Custom" customUserNamePasswordValidatorType
="SupportClasses.CustomUserNameValidator,SupportClasses"/>
</serviceCredentials>
<!-- The following element specifies how we're authorizing based on the client certificates received -->
<serviceAuthorization serviceAuthorizationManagerType="SupportClasses.AuthorizationManager, SupportClasses"/>
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
那么你可能会问的问题在哪里?好吧,看到那个<serviceBehavior>
元素了吗?您可能知道此元素全局应用于服务,这意味着在运行时将调用 CustomUserNameValidator 和 AuthorizationManager。后者会抱怨当客户端使用 wsHttpBinding 调用服务时没有证书存在!
啊!
替代解决方案。
到目前为止,这些是我提出的替代解决方案:
备选方案 1)创建另一个 Windows 服务,在不同的 URL 上托管我们的 WCF 服务。然后这两个服务将有一个单独的配置。
备选方案 2)创建两个托管在同一个 Windows 服务中的服务实现,并将它们都暴露在元素中,每个都有自己的绑定和 serviceBehaviour
备选方案 3)确定是否有可能保留当前配置并让 CustomUserNameValidator 和 AuthorizationManager 和平共存
很抱歉这篇长文,但在为我的问题提供背景时,我需要彻底。
问题 1)有没有人让 WCF 使用非平凡的配置与 Java 客户端一起工作?
问题 2)有没有人对如何解决替代方案 3 提出建议?(如果可能的话)
问题 3)如果有的话,您会推荐上述替代方案中的哪一个?
问题 4)您知道我还没有想到的其他替代方案吗?
作为记录,我研究了 WCF 互操作性工具,但我真的看不出它对我们有什么帮助。如果有人阅读本文后使用互操作性“向导”取得了良好的效果,
请告诉我。
提前致谢。
——诺吉