背景(稍长(:
几年前,我为一位客户编写了一个WCF服务,该服务被配置为使用安全模式="Transport"的basicHttpBinding和clientCredentialType="Certificate",即客户端使用(客户端(证书对自己进行身份验证。该服务使用自定义AuthorizationManager来检查传入证书的指纹是否存在于有效证书指纹的预定义列表中。如果传入的证书被认为是有效的,则允许操作继续(如果不是,则抛出异常(。
这项服务已经完美地运行了大约四年,每个人都很开心。然而,正如经常发生的那样,需求发生了变化,最近我的客户被开发人员联系,希望将他们的应用程序连接到我的客户服务。唯一的问题是,这些开发人员正在使用Java的某些变体作为他们的首选平台,现在我们面临着一些严重的问题。长话短说,没有人能够让他们的Java实现(例如Metro、Axis2(与当前配置的服务一起工作。
上周,我们尝试将绑定更改为wsHttpBinding,安全模式="TransportWithMessageCredential",Message clientCerdentialType="UserName",从而使其与用Java编写的客户端(Metro,JAX-WS(一起工作。我还向配置文件中的服务凭据元素添加了一个自定义UserNamePassWordValidatorType。
然后我注释掉了自定义AuthorizationManager,因为没有来自客户端的证书。
瞧,这一次我们让SoapUI和Java客户端都可以与服务对话。
(顺便说一句,我们的服务是在Windows服务中自行托管的(
尽管很高兴,我们还是决定用两个绑定来配置服务,一个是已经工作了很长时间没有出现故障的现有basicHttpBinding,另一个是新测试的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(在不同的URL上创建另一个承载WCF服务的Windows服务。然后,这两个服务将有一个单独的配置。
备选方案2(创建托管在同一Windows服务中的两个服务实现,并在元素中公开它们,每个实现都有自己的绑定和serviceBehavior
备选方案3(弄清楚是否有可能保持当前配置,并让CustomUserNameValidator和AuthorizationManager和平共存
很抱歉发了这么长的帖子,但在为我的问题提供背景时,我需要彻底。
问题1(有人让WCF使用非平凡的配置来处理Java客户端吗?
问题2(有人对如何解决备选方案3有什么建议吗?(如果可能的话(
问题3(您会推荐上述备选方案中的哪一个(如果有的话(?
问题4(你知道还有其他我没有想到的选择吗?
为了记录在案,我已经研究了WCF互操作性工具,但我真的看不出它能对我们有什么帮助
请告诉我。
提前谢谢。
--norgie
我将首先在//服务中添加第二个元素,并用一个新的@bindingConfiguration属性和一个不同的@address属性来配置它。我认为这将比备选方案1、2或3更简单;或者可能是备选方案3,我不知道。
Web服务的存在是为了提供与语言、供应商、平台和供应商无关的互操作。WCF和Java每天都在现实世界的解决方案中进行互操作。
您看过这个关于WCF和Java互操作的系列吗?
此外,使用一些诊断工具可以让您看到.NET/WCF客户端消息和Java客户端消息之间的差异,这听起来会让您受益匪浅。使用Fiddler或其他嗅探器实用程序可以查看线路上的消息。启用WCF跟踪以查看WCF在收到消息后会执行什么操作。