WS-Security 从soapUI 到WCF - 绑定&配置 [英] WS-Security from soapUI to WCF - binding & configuration

查看:24
本文介绍了WS-Security 从soapUI 到WCF - 绑定&配置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个 WCF 客户端来调用一个我无法控制的服务,我们只获得了一个 wsdl(带有模式).Web 服务使用 X.509 证书和 WS-Security 规范版本 1.0

I need to create a WCF client to call a service that I have no control over and we have been given a wsdl only (with schemas). The web service uses the X.509 certificate with the WS-Security specification version 1.0

Web 服务提供者已共享soap 消息的原始xml 以突出显示ws-security 标头.使用soapUI,我已经能够创建完全相同的wsse-Security 标头,如下所示:

The web service provider has shared raw xml of the soap message to highlight the ws-security header. Using the soapUI, I have been able to create the exact same wsse-Security header as shown below:

<soapenv:Envelope xmlns:oas="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
  <soapenv:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <ds:Signature Id="SIG-32" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <ds:Reference URI="#id-31">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <InclusiveNamespaces PrefixList="oas oas1 urn urn1 urn2 urn3 xd" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#"/>
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>ucSFZEOTHpe/IOlPVWtU+1xT4sM=</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
          d4CKqie==
        </ds:SignatureValue>
        <ds:KeyInfo Id="KI-9A8D1F611E86CFB79E144316684667546">
          <wsse:SecurityTokenReference oas:Id="STR-9A8D1F611E86CFB79E144316684667547">
            <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
                                ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">5lAB5TaqeFwo23mRVm31LngBT1dQMf94mxeVkyKog==
            </wsse:KeyIdentifier>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>

      <oas:Timestamp oas:Id="TS-30">
        <oas:Created>2015-09-25T07:40:46.670Z</oas:Created>
        <oas:Expires>2015-09-26T11:27:26.670Z</oas:Expires>
      </oas:Timestamp>
    </wsse:Security>
  </soapenv:Header>

  <soapenv:Body oas:Id="id-31">
    ...
  </soapenv:Body>
</soapenv:Envelope>

在soapUI 中,在WS-Security 配置"下,我添加了密钥库(带有我的私有证书的jks)和信任库(带有CA 根公钥的jks).最后,我使用以下设置添加了Outgoing WS-Security Configurations".

In soapUI, under the "WS-Security Configurations" I added the Keystores (jks with my private cert) and Truststores (jks with CA root public key). Finally I added "Outgoing WS-Security Configurations" with the following setting.

使用此 WS-Security 设置,soap 消息会添加 wsse:Security,如上所示.

With this WS-Security setting, the soap message adds the wsse:Security as shown above.

现在,我们正在使用 WCF 在 .NET 上构建 WS 客户端,并且需要有关绑定和安全设置的帮助.可以使用哪些绑定和配置设置来具有与上面要求或显示的相同的 WS-Security 标头?

Now, we are building the WS client on the .NET with WCF, and need help with the Binding and Security settings. What binding and configuration settings can be used to have the same WS-Security header as required or shown above?

从 WSDL,我使用 WSCF.blue 创建了一个客户端代理.虽然,我也可以使用 svcutil.exe 或使用来自 VS 的添加服务引用.

From the WSDL, I created a client-side proxy using WSCF.blue. Although, I could have also used svcutil.exe or using Add Service Reference from VS.

我尝试在代码中创建 customBinding 如下,但是在检查此消息时,wsse 标头与我想要的不同.

I have tried creating the customBinding in code as following, but when inspecting this message the wsse header is not the same as what I want.

例如,它在 Security 标头中添加了一个不需要的 BinarySecurityToken.

For example, it adds a BinarySecurityToken in the Security header which is not desired.

或者 KeyIdentifierX509SubjectKeyIdentifier 而不是 X509v3 例如:<o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier" ...</o:KeyIdentifier>

Or the KeyIdentifier is X509SubjectKeyIdentifier instead of X509v3 for example: <o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier" ...</o:KeyIdentifier>

它还在SignedInfo下添加了额外的多个Reference,即使它通过了模式验证,我也不确定额外的Reference是什么正在做.

It also adds additional multiple Reference under the SignedInfo, and even though it passes schema validation, I am not sure what the additional Reference is doing.

internal static Binding GetCustomBinding()
{
    CustomBinding myBinding = new CustomBinding();

    AsymmetricSecurityBindingElement asBindingElement = new AsymmetricSecurityBindingElement();

    //Have tried these also
    //asBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
    //asBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
    //WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10

    asBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
    asBindingElement.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };

    asBindingElement.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters 
    { 
        //X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier,
        InclusionMode = SecurityTokenInclusionMode.Never
    };


    asBindingElement.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
    //asBindingElement.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
    asBindingElement.SecurityHeaderLayout = SecurityHeaderLayout.LaxTimestampLast;
    asBindingElement.EnableUnsecuredResponse = true;
    asBindingElement.IncludeTimestamp = true;
    asBindingElement.SetKeyDerivation(false);
    asBindingElement.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;

    asBindingElement.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());

    myBinding.Elements.Add(asBindingElement);

    myBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
    //myBinding.Elements.Add(new MtomMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));

    HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
    httpsBindingElement.RequireClientCertificate = true;
    myBinding.Elements.Add(httpsBindingElement);

    return myBinding;
}

此外,我将此行为用于 x509 证书

Additionally, I am using this behaviour for the x509 cert

<behaviors>
  <endpointBehaviors>
    <behavior name="MyBehavior">
      <clientCredentials>
        <clientCertificate findValue="xxx"
          storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
        <serviceCertificate>
          <defaultCertificate findValue="xxx"
            storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
          <authentication certificateValidationMode="None" revocationMode="NoCheck"
            trustedStoreLocation="LocalMachine" />
        </serviceCertificate>
      </clientCredentials>
    </behavior>
  </endpointBehaviors>
</behaviors>

推荐答案

如果您想发送 完全 相同的消息,您可能应该使用 SignedXml 类在 WCF 之外生成签名.使用 WCF,您将无法获得准确的规范化算法/InclusiveNamespace.

If you want to send the exact same message than you should probably use the SignedXml class to generate the signature outside of WCF. With WCF you will not be able to get the exact canonicalization algorithn / InclusiveNamespace.

话虽如此,在大多数情况下,服务器都可以生成类似的消息.您有两种可能的方法.一种是创建一个customMessageEncoder在传出 WCF 消息到达网络之前更改它.因此,您可以告诉 WCF 创建一个极简的消息(例如,没有时间戳)并在编码器中自己添加时间戳(如果 wcf 会创建它,那么它也会对其进行签名)并删除/更改 x.509 令牌引用.在执行包括空格在内的 do (body, signedInfo) 操作时,您应该注意不要更改任何已签名的 xml 节点(因此,如果加载到 XmlDocument,请使用 preserveWhitepsaces).

Having said that most of the time producing a similar message is fine with the server. You have two possible approaches. One is to create a customMessageEncoder which will change the outgoing WCF message before it hits the network. So you can tell WCF to create a minimalist message (e.g. no timestamp) and in the encoder add the timestamp yourself (if wcf would create it then it would also sign it) and also remove/change the x.509 token references. You should be careful not to change any signed xml nodes when doing do (body, signedInfo) including whitespaces (so use preserveWhitepsaces if loading to XmlDocument).

另一种方法是尝试配置 WCF 以发送相同的消息:

Another approach is to try and configure WCF to send the same message:

  • 要排除额外的令牌引用,请创建 x.509 参数像这样:

        X509SecurityTokenParameters x509Params = new X509SecurityTokenParameters();
        x509Params.X509ReferenceStyle =
            X509KeyIdentifierClauseType.SubjectKeyIdentifier;
        x509Params.RequireDerivedKeys = false;
        ;
        x509Params.InclusionMode = SecurityTokenInclusionMode.Never;
        x509Params.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
        x509Params.X509ReferenceStyle = X509KeyIdentifierClauseType.Any;
        ((AsymmetricSecurityBindingElement) sec).InitiatorTokenParameters = x509Params;

  • 时间戳将由 wcf 签名,但可能服务器并不关心,或者不需要时间戳,因此请尝试 requireTimestamp=true/false 并查看哪些有效.您可以使用 MessagePartSpecification 以编程方式禁用时间戳签名.

  • timestamp will be signed by wcf, but possibly the server does not care, or does not require a timestamp, so try requireTimestamp=true/false and see what works. You might be able to programatically disable signing for timestamps by using MessagePartSpecification.

    任何一种方法的重要之处在于了解服务器可能比您想象的更灵活,并从其错误消息中了解真正的阻碍因素是什么.

    The important in either approach is to understand the server might be more flexible than you think and to understand from its error messages what are the real show stoppers.

    这篇关于WS-Security 从soapUI 到WCF - 绑定&amp;配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆