需要SSL证书和客户端证书会在WCF JSON服务中引发异常

时间:2011-11-29 23:07:31

标签: .net iis-6 ssl-certificate wcf-security wcf-rest

我有一个使用JSON的简单WCF服务设置。在此服务中,我想使用客户端身份验证和客户端证书。我已经将IIS 6配置为需要SSL并通过设置文件夹/ site / services / wcf / json /来要求客户端证书。此设置通常称为双向SSL。

但是每当我尝试使用生成的SSL证书测试页面时,我都会收到异常。

  

服务“无”的SSL设置与IIS'Ssll,SslNegotiateCert,SslRequireCert'的SSL设置不匹配。

Stack Trace: 

[NotSupportedException: The SSL settings for the service 'None' does not match those of the IIS 'Ssl, SslNegotiateCert, SslRequireCert'.]
   System.ServiceModel.Activation.HostedAspNetEnvironment.ValidateHttpsSettings(String virtualPath, Nullable`1& requireClientCertificate) +117347
   System.ServiceModel.Channels.HttpsChannelListener.ApplyHostedContext(String virtualPath, Boolean isMetadataListener) +97
   System.ServiceModel.Activation.HostedAspNetEnvironment.ApplyHostedContext(TransportChannelListener listener, BindingContext context) +84
   System.ServiceModel.Channels.HttpsTransportBindingElement.BuildChannelListener(BindingContext context) +93
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +63
   System.ServiceModel.Channels.MessageEncodingBindingElement.InternalBuildChannelListener(BindingContext context) +67
   System.ServiceModel.Channels.WebMessageEncodingBindingElement.BuildChannelListener(BindingContext context) +49
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +63
   System.ServiceModel.Channels.Binding.BuildChannelListener(Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, BindingParameterCollection parameters) +125
   System.ServiceModel.Description.DispatcherBuilder.MaybeCreateListener(Boolean actuallyCreate, Type[] supportedChannels, Binding binding, BindingParameterCollection parameters, Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, ServiceThrottle throttle, IChannelListener& result, Boolean supportContextSession) +337
   System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, Boolean supportContextSession, IChannelListener& result) +668
   System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) +1228
   System.ServiceModel.ServiceHostBase.InitializeRuntime() +60
   System.ServiceModel.ServiceHostBase.OnBeginOpen() +27
   System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +50
   System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +318
   System.ServiceModel.Channels.CommunicationObject.Open() +36
   System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +184
   System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +615

我已经测试过证书安装正确。我创建了一个需要客户端身份验证的基本虚拟目录。此虚拟目录包含一个简单的.htm文件。我已经确认它需要https并且它对我的客户端证书提出质疑,当我证明它是有效的客户端证书时它会显示.htm页面,当我没有证明它是有效证书时它不会。

将IIS中的这些相同设置应用于我的WCF服务时,我得到上述异常。我试图将服务配置为还需要SSL和客户端身份验证,但我继续得到上面的例外。

以下是我的设置。

<system.serviceModel>
<!-- behaviors -->
<behaviors>
    <endpointBehaviors>
        <behavior name="jsonBehavior">
            <enableWebScript />
                <clientCredentials>
                <clientCertificate findValue="*.MyCompany.com" storeLocation="LocalMachine" x509FindType="FindBySubjectName" storeName="My" />
            </clientCredentials>
        </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
        <behavior name="">
            <serviceDebug includeExceptionDetailInFaults="true" />
            <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
            <serviceCredentials>
                    <serviceCertificate  findValue="*.MyCompany.com" storeLocation="LocalMachine" x509FindType="FindBySubjectName" storeName="My" />                                              
                </serviceCredentials>
        </behavior>
    </serviceBehaviors>
</behaviors>

<!-- bindings -->
<bindings>
    <webHttpBinding>
        <binding name="webBinding">
            <security mode="Transport">
                <transport clientCredentialType="Certificate"/>
            </security> 
        </binding>
    </webHttpBinding>
</bindings>

<!-- services -->

<services>
    <service name="Service1Json" behaviorConfiguration="">
        <endpoint address="https://www.MyCompany.com/site/services/wcf/json/Service1.svc"
            behaviorConfiguration="jsonBehavior"
            binding="webHttpBinding"
            bindingConfiguration="webBinding"
            contract="MyCompany.Services.Wcf.IService1" />
    </service>
    <service name="Service2Json" behaviorConfiguration="">
        <endpoint address="https://www.MyCompany.com/site/Services/WCF/json/Service2.svc"
            behaviorConfiguration="jsonBehavior"
            binding="webHttpBinding"
            bindingConfiguration="webBinding"
            contract="MyCompany.Services.Wcf.IService2" />
    </service>
    <service name="Service3Json" behaviorConfiguration="">
        <endpoint address="https://www.MyCompany.com/site/services/wcf/json/Service3.svc"
            behaviorConfiguration="jsonBehavior"
            binding="webHttpBinding"
            bindingConfiguration="webBinding"
            contract="MyCompany.Services.Wcf.IService3" />
    </service>
</services>

<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

</system.serviceModel>

1 个答案:

答案 0 :(得分:3)

问题实际上最终比我上面描述的更复杂。最终的解决方案最终变得非常简单。

原始问题上面没有提到我们有多个端点:1。SOAP 2. JSON。这些都需要使用双向SSL进行保护。

我们的错误如下:

  1. 不需要客户端和服务器凭据。
  2. 服务名称必须与.svc文件的名称相匹配。
  3. 端点地址必须不同。因此,对于我们的JSON端点,我们添加了“json”。我们还从地址中删除了完全限定的URI,让WCF自动为我们生成它。
  4. 以下是我们最终的最终配置:

    <system.serviceModel>
    
        <!-- behaviors -->
        <behaviors>
            <endpointBehaviors>
                <behavior name="jsonBehavior">
                    <enableWebScript />
                </behavior>
            </endpointBehaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    
        <!-- bindings -->
        <bindings>
            <basicHttpBinding>
                <binding name="httpBinding">
                    <security mode="None">
                    </security>
                </binding>
            </basicHttpBinding>
            <webHttpBinding>
                <binding name="webBinding">
                    <security mode="None">
                    </security>
                </binding>
            </webHttpBinding>
        </bindings>
    
        <!-- services -->
        <services>
            <service name="MyCompany.Services.Wcf.Service1" behaviorConfiguration="">
                <endpoint address="json"
                    behaviorConfiguration="jsonBehavior"
                    binding="webHttpBinding"
                    bindingConfiguration="webBinding"
                    contract="MyCompany.Services.Wcf.IService1" />
                <endpoint address=""
                    behaviorConfiguration=""
                    binding="basicHttpBinding"
                    bindingConfiguration="httpBinding"
                    contract="MyCompany.Services.Wcf.IService1" />
            </service>
    
            <service name="MyCompany.Services.Wcf.Service2" behaviorConfiguration="">
                <endpoint address="json"
                    behaviorConfiguration="jsonBehavior"
                    binding="webHttpBinding"
                    bindingConfiguration="webBinding"
                    contract="MyCompany.Services.Wcf.IService2" />
                <endpoint address=""
                    behaviorConfiguration=""
                    binding="basicHttpBinding"
                    bindingConfiguration="httpBinding"
                    contract="MyCompany.Services.Wcf.IService2" />
            </service>
    
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    
    </system.serviceModel>
    

    如果我们选择让SOAP不使用双向SSL而JSON需要双向SSL,那么配置就会复杂得多。