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

发布于 2024-12-19 04:51:59 字数 5792 浏览 4 评论 0原文

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

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

服务“None”的 SSL 设置与 IIS“Ssl、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>

I have a simple WCF service setup that uses JSON. In this service I want to use client authentication with a client certificate. I've configured IIS 6 to require SSL and to require client certificates by setting the folder /site/services/wcf/json/. This setup is typically referred to as 2-way SSL.

But I am getting an exception whenever I try to test the page with the generated SSL certificate.

The SSL settings for the service 'None' does not match those of the IIS 'Ssl, SslNegotiateCert, SslRequireCert'.

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

I've tested that the certificates are installed properly. I created a basic virtual directory that required client auth. This virtual directory contains a simple .htm file. I've confirmed it requires https and that it challenges me for my client cert and when I proved a valid client cert it displays the .htm page and when I do not proved a valid cert it does not.

When applying these same settings in IIS to my WCF service I get the above exception. I attempted to configure the services to also require SSL and client auth, but I continue to get the exception above.

Here are my settings.

<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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

2024-12-26 04:52:00

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

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

我们的错误如下:

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

这是我们最终得到的最终配置:

<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 不使用 2 向 SSL 并且 JSON 需要 2 向 SSL,那么配置将会复杂得多。

The problem actually ended up being more complex than I am describing above. And the resulting solution ended up being quite simple.

Not mentioned above in the original problem is that we have multiple endpoints: 1. SOAP 2. JSON. These need to be both secured with 2-way SSL.

Our mistakes were the following:

  1. Client and server credentials are not necessary.
  2. Service name must match that of the .svc file.
  3. Endpoint addresses must differ. So for our JSON endpoint we added "json". Also we removed the fully qualified URI from address and let WCF automatically generate it for us.

Here is the final config we ended up with:

<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>

Had we chosen to have SOAP not use 2-way SSL and JSON require 2-way SSL the config would have been a lot more complex.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文