具有证书身份验证的 WCF 服务:"The caller was not authenticated by the service"
WCF service with certificate authentication: "The caller was not authenticated by the service"
我正在尝试使用 certificate-based 身份验证设置 WCF 服务,遵循本指南:https://msdn.microsoft.com/en-au/library/ff648360.aspx?f=255&MSPPError=-2147217396
我已经完成了所有步骤(我认为),总结起来是:
1) 生成了 self-signed CA 证书并将其安装为 machine-level 受信任的 CA:
2) 为服务生成证书(由 CA 证书签署,CN=QvxServiceCert
)并将其安装在 machine-level:
3) 配置 WCF 服务终结点行为以使用证书。我的服务配置如下所示:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="QvxServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="CN=QvxServiceCert" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="esqQvxScheduler.Service.QvxSchedulerAPI" behaviorConfiguration="QvxServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding"
name="wsHttpEndpoint" bindingName="" contract="esqQvxScheduler.Service.IQvxSchedulerAPI" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/QvxSchedulerAPI/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
4) 为客户端生成证书(同样由 CA 证书签名,这个有 CN=QvxClientCert
)并安装在 user-level:
5) 配置 WCF 客户端行为以使用它进行身份验证。这是我的客户端配置:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="qvxClientBehavior">
<clientCredentials>
<clientCertificate findValue="CN=QvxClientCert" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpoint">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/QvxSchedulerAPI/" binding="wsHttpBinding" behaviorConfiguration="qvxClientBehavior"
bindingConfiguration="wsHttpEndpoint" contract="QvxSchedulerAPI.IQvxSchedulerAPI"
name="wsHttpEndpoint">
<identity>
<certificate encodedValue="[A LONG AUTOGENERATED STRING THE MEANING OF WHICH I HAVE NO IDEA]" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
6) 通过在命令行上发出以下命令,为运行客户端的用户授予对证书的访问权限:cacls "C:\Users\MyUsername\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-742627442-1779984360-2302642487-1000" /E /G "MyUser-PC\MyUsername":R
这一切都是按照指南完成的,我没有看到任何问题。一切似乎都很好......但是当我尝试从我的客户端调用服务时,我得到了这个令人沮丧的模糊和无用的异常:
Unhandled Exception: System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service. ---> System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.TlsnegoTokenProvider.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.CommunicationObjectSecurityTokenProvider.Open(TimeSpan timeout)
at System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
好吧,经过大量试验和错误后,结果证明您要么必须为您的 CA 安装 CRL,要么必须明确指定您不需要撤销检查,方法是将其添加到您的行为的 ClientCredentials 标签:
<serviceCertificate>
<authentication revocationMode="NoCheck"/>
</serviceCertificate>
服务端反之亦然:
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck"/>
</clientCertificate>
此外,您需要删除客户端中自动生成的证书标记,并将其替换为查找证书的指令:
<identity>
<certificateReference findValue="CN=QvxServiceCert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
</identity>
我正在尝试使用 certificate-based 身份验证设置 WCF 服务,遵循本指南:https://msdn.microsoft.com/en-au/library/ff648360.aspx?f=255&MSPPError=-2147217396
我已经完成了所有步骤(我认为),总结起来是:
1) 生成了 self-signed CA 证书并将其安装为 machine-level 受信任的 CA:
2) 为服务生成证书(由 CA 证书签署,CN=QvxServiceCert
)并将其安装在 machine-level:
3) 配置 WCF 服务终结点行为以使用证书。我的服务配置如下所示:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="QvxServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="CN=QvxServiceCert" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="esqQvxScheduler.Service.QvxSchedulerAPI" behaviorConfiguration="QvxServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding"
name="wsHttpEndpoint" bindingName="" contract="esqQvxScheduler.Service.IQvxSchedulerAPI" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/QvxSchedulerAPI/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
4) 为客户端生成证书(同样由 CA 证书签名,这个有 CN=QvxClientCert
)并安装在 user-level:
5) 配置 WCF 客户端行为以使用它进行身份验证。这是我的客户端配置:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="qvxClientBehavior">
<clientCredentials>
<clientCertificate findValue="CN=QvxClientCert" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpoint">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/QvxSchedulerAPI/" binding="wsHttpBinding" behaviorConfiguration="qvxClientBehavior"
bindingConfiguration="wsHttpEndpoint" contract="QvxSchedulerAPI.IQvxSchedulerAPI"
name="wsHttpEndpoint">
<identity>
<certificate encodedValue="[A LONG AUTOGENERATED STRING THE MEANING OF WHICH I HAVE NO IDEA]" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
6) 通过在命令行上发出以下命令,为运行客户端的用户授予对证书的访问权限:cacls "C:\Users\MyUsername\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-742627442-1779984360-2302642487-1000" /E /G "MyUser-PC\MyUsername":R
这一切都是按照指南完成的,我没有看到任何问题。一切似乎都很好......但是当我尝试从我的客户端调用服务时,我得到了这个令人沮丧的模糊和无用的异常:
Unhandled Exception: System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service. ---> System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.TlsnegoTokenProvider.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.CommunicationObjectSecurityTokenProvider.Open(TimeSpan timeout)
at System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
好吧,经过大量试验和错误后,结果证明您要么必须为您的 CA 安装 CRL,要么必须明确指定您不需要撤销检查,方法是将其添加到您的行为的 ClientCredentials 标签:
<serviceCertificate>
<authentication revocationMode="NoCheck"/>
</serviceCertificate>
服务端反之亦然:
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck"/>
</clientCertificate>
此外,您需要删除客户端中自动生成的证书标记,并将其替换为查找证书的指令:
<identity>
<certificateReference findValue="CN=QvxServiceCert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
</identity>