WCF - 找不到X509SecurityToken的令牌验证器

时间:2016-07-18 11:25:30

标签: c# wcf soap soap-client

我正在尝试拨打第三方网络服务,我已经到了能够在服务跟踪查看器中实际看到服务器响应的地步。但是,我不断从.NET获得例外:

Cannot find a token authenticator for the 'System.IdentityModel.Tokens.X509SecurityToken' token type. 
Tokens of that type cannot be accepted according to current security settings.

我的app.config看起来像这样(用占位符替换了Thumbprints):

<system.serviceModel>
<behaviors>
  <endpointBehaviors>
    <behavior name="OteBehavior">
      <clientCredentials>
        <serviceCertificate>
          <authentication certificateValidationMode="None"/>
          <defaultCertificate findValue="<ThumbprintPlaceholder1>" x509FindType="FindByThumbprint" storeLocation="CurrentUser" storeName="TrustedPeople"/>
        </serviceCertificate>
        <clientCertificate findValue="<ThumbprintPlaceholder2>" x509FindType="FindByThumbprint"/>
      </clientCredentials>
    </behavior>
  </endpointBehaviors>
</behaviors>
<bindings>
  <customBinding>
    <binding name="MyBinding">
      <textMessageEncoding messageVersion="Soap11" />
      <security authenticationMode="CertificateOverTransport"
                messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"
                requireSecurityContextCancellation="false"
                enableUnsecuredResponse="true"
                allowSerializedSigningTokenOnReply="true">

      </security>
      <httpsTransport maxBufferPoolSize="2147483646" maxBufferSize="2147483646" maxReceivedMessageSize="2147483646" requireClientCertificate="true" />
    </binding>
  </customBinding>
</bindings>
<client>
  <endpoint address="https://example.com:1443/xxx/someService/"
    binding="customBinding" bindingConfiguration="MyBinding"  behaviorConfiguration="OteBehavior"
    contract="ReportGasService.ReportGas" name="ReportGasEndpoint" />
</client>

现在,我已经尝试了有关此异常的所有内容。

  1. authenticationMode设置为MutualCertificate:服务器响应404
  2. 设置allowSerializedSigningTokenOnReply:无变化
  3. 来自服务器的响应包含:

    <ds:KeyInfo Id="KI-1DE4B371623632132E1468838210413180294">
        <wsse:SecurityTokenReference wsu:Id="STR-1DE4B271123632132E1468838710413180295">
            <wsse:Reference URI="#X509-1DE4B271523632132E1468833710413180293" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"></wsse:Reference>
        </wsse:SecurityTokenReference>
    </ds:KeyInfo>
    

    我可以在某处添加x508SecurityToken处理程序,否则会忽略此错误(这样做是否安全)

    异常堆栈跟踪:

    Server stack trace: 
    at System.ServiceModel.Security.ReceiveSecurityHeader.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver, IList`1 allowedTokenAuthenticators, SecurityTokenAuthenticator& usedTokenAuthenticator)
    at System.ServiceModel.Security.ReceiveSecurityHeader.ReadToken(XmlDictionaryReader reader, Int32 position, Byte[] decryptedBuffer, SecurityToken encryptionToken, String idInEncryptedForm, TimeSpan timeout)
    at System.ServiceModel.Security.ReceiveSecurityHeader.ExecuteFullPass(XmlDictionaryReader reader)
    at System.ServiceModel.Security.StrictModeSecurityHeaderElementInferenceEngine.ExecuteProcessingPasses(ReceiveSecurityHeader securityHeader, XmlDictionaryReader reader)
    at System.ServiceModel.Security.ReceiveSecurityHeader.Process(TimeSpan timeout, ChannelBinding channelBinding, ExtendedProtectionPolicy extendedProtectionPolicy)
    at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessageCore(Message& message, TimeSpan timeout)
    at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout)
    at System.ServiceModel.Security.SecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
    at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
    at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
    at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
    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)
    

    上述意味着它是服务器端吗?

2 个答案:

答案 0 :(得分:2)

我找到了解决方案:

  1. authenticationMode="CertificateOverTransport"更改为authenticationMode="MutualCertificate"
  2. 使用MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10
  3. 在生成的客户端中,将ProtectionLevel = ProtectionLevel.Sign添加到ServiceContractAttribute。这样可以避免身体加密。
  4. 我仍然没有完全通过,但我相信这只是从提供商那里获得正确的证书。

    对于其他人,以下是我创建代理的方式:

    var binding = new BasicHttpsBinding();
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
    var address = new EndpointAddress(new Uri("https://xxx/yyy/someService/"));
    binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
    
    var securityElement = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
    securityElement.IncludeTimestamp = true;
    
    var customBinding = new CustomBinding(binding);
    customBinding.Elements.Insert(0, securityElement);
    var client = new ReportGasClient(customBinding, address);
    
    client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindByThumbprint, "BCC3929F9C115D4BCA1C697E2557B7FC7D6C8C8C");
    client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
    client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.CurrentUser, StoreName.TrustedPeople, X509FindType.FindByThumbprint, "87C3B5EE3913937459D2FFBF105ADBD1A578E823");
    

    请注意我只在沙盒环境中将ValidationMode设置为None。这绝不应该用于生产。

答案 1 :(得分:0)

findValue属性的值均不正确。您应该在app.config中为相应的客户端证书设置特定的指纹值。

您可以通过证书MMC加载项查看证书指纹值。

我还会仔细检查客户端X509证书是否正常,只需要服务器端操作。