如何使WCF客户端符合特定的WS-Security - 注册用户名令牌和SecurityTokenReference [英] How to make WCF Client conform to specific WS-Security - sign UsernameToken and SecurityTokenReference

查看:271
本文介绍了如何使WCF客户端符合特定的WS-Security - 注册用户名令牌和SecurityTokenReference的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个WCF客户端调用,我无法控制的服务。

I need to create a wcf client to call a service that I have no control over.

我一直在考虑一个WSDL和工作的soapUI项目。

I have been given a wsdl and a working soapui project.

该服务同时使用用户名/密码和X509证书。

The service uses both a username/password and a x509 certificate.

更新

我现在明白了问题是什么,但我仍不能确定哪些步骤,我需要采取能够创建所需的消息,所以任何帮助,将不胜感激。

I now understand what the problem is, but am still unsure what steps I need to take to be able to create the required message, so any help would be much appreciated.

我需要双方签署的用户名令牌和SecurityTokenReference。

I need to sign both the UsernameToken and the SecurityTokenReference.

我不得不创建自定义绑定从这个帖子已被删除其不再使用的代码。我不再是一个SecurityBindingElement添加到绑定,而不是我补充一点,安全元素写入到页眉的新行为。

The code I had to create the custom binding has been removed from this post as its no longer used. I no longer add a SecurityBindingElement to the binding, instead I add a new behaviour that writes the security element into the header.

所以安全节点从头开始通过继承创建该SignedXml类,增加签约引用,然后调用ComputeSignature创建安全头中的签名节点。

So the security node is created from scratch by subclassing the SignedXml class, adding signing references and then calling ComputeSignature to create the Signature node within the Security header.

您需要通过XML签入SignedXml构造此上班。这是没有问题的传入的UsernameToken,这似乎是正确的签名。

You need to pass the xml to sign into the SignedXml constructor for this to work. It is no problem passing in the UsernameToken and this appears to be signed correctly.

的问题是,当ComputeSignature()被称为SecurityTokenReference时才创建,所以我米不能够签名参考添加到该元件中,因为它没有在它需要的时间存在

The problem is that the SecurityTokenReference is only created when ComputeSignature() is called, so I'm not able to add a signing Reference to this element, as it does not exist at the time it is required (within the overridden GetIdElement method of SignedXml which is called prior to ComputeSignature())

我使用创建签名块插入到安全标头中的代码如下:

The code I'm using to create the signature block to insert into the Security header is as follows

   string certificatePath = System.Windows.Forms.Application.StartupPath + "\\" + "Certs\\sign-and-    enc.p12";

    XmlDocument xd = new XmlDocument();
    xd.LoadXml(xml);

    // Set Certificate 
    System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new X509Certificate2(certificatePath, "password");
    MySignedXml signedXml = new MySignedXml(xd);
    signedXml.SigningKey = cert.PrivateKey;

    // Create a new KeyInfo object. 
    KeyInfo keyInfo = new KeyInfo();
    keyInfo.Id = "";

    MemoryStream keyInfoStream = new MemoryStream();
    XmlWriter keyInfoWriter = XmlWriter.Create(keyInfoStream);

    WSSecurityTokenSerializer.DefaultInstance.WriteKeyIdentifierClause(keyInfoWriter, new LocalIdKeyIdentifierClause("token_reference", typeof(X509SecurityToken)));   

    keyInfoWriter.Flush();
    keyInfoStream.Position = 0;
    XmlDocument keyInfoDocument = new XmlDocument();
    keyInfoDocument.Load(keyInfoStream);

    XmlAttribute attrib = keyInfoDocument.CreateAttribute("ValueType");
    attrib.InnerText = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
    keyInfoDocument.ChildNodes[1].ChildNodes[0].Attributes.Append(attrib);

    KeyInfoNode keyInfoNode = new KeyInfoNode();
    keyInfoNode.LoadXml(keyInfoDocument.DocumentElement);
    keyInfo.AddClause(keyInfoNode);

    // Add the KeyInfo object to the SignedXml object. 
    signedXml.KeyInfo = keyInfo;

    // Need to use External Canonicalization method. 
    signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";

    // Create a reference to be signed. 
    Reference reference = new Reference();
    reference.Uri = "#UsernameToken-1";

    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
    env.Algorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
    reference.AddTransform(env);
    reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
    signedXml.AddReference(reference);


    Reference reference2 = new Reference();
    reference2.Uri = "#token_reference";
    XmlDsigEnvelopedSignatureTransform env2 = new XmlDsigEnvelopedSignatureTransform();
    env2.Algorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
    reference2.AddTransform(env2);
    reference2.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
    signedXml.AddReference(reference2);

    // Add the Signature Id 
    signedXml.Signature.Id = "MYSIG_ID";

    // Compute the signature. 
    signedXml.ComputeSignature();

    XmlElement xmlDigitalSignature = signedXml.GetXml();



在XML变量是在用户名令牌XML字符串,MySignedXml类是一个子类SignedXml与GetIdElement方法重写(试图找到正确的refreence不存在SecurityTokenReference)

where the xml variable is the the UsernameToken xml string, and the MySignedXml class is a subclassed SignedXml with the GetIdElement method overridden (to try to find and correctly refreence the non-existant SecurityTokenReference)

我已经花几天研究,现在这个测试,不幸的是公司的供应链服务是不是任何帮助 - 但我需要使用他们的服务。

I've spend days researching and testing this now, and unfortunately the company supplying the service isn't any help - but I need to use their service.

展开工作SOAP消息(soapUI的项目)

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:XXXXX">
   <soapenv:Header xmlns:ebxml="http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/">
   <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    <wsse:BinarySecurityToken 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" wsu:Id="CertId-D05E596B5ABC341FEB13505090224061" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">MIIEnDCCBAWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBxDELMAkGA1UEBhMCTloxDTALBgNVBAgTBFdHVE4xEzARBgNVBAcTCldlbGxpbmd0b24xGDAWBgNVBAoTD0lSRFN0dWR5bGlua0IyQjEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxHjAcBgNVBAMTFWRldmNhLmIyYi5pcmQuZ292dC5uejEXMBUGA1UEKRMORGV2ZWxvcG1lbnQgQ0ExKDAmBgkqhkiG9w0BCQEWGWNocmlzLnNjaHVsdHpAaXJkLmdvdnQubnowHhcNMTEwOTE1MDIwNjIwWhcNMjEwOTEyMDIwNjIwWjCByTELMAkGA1UEBhMCTloxDTALBgNVBAgTBFdHVE4xEzARBgNVBAcTCldlbGxpbmd0b24xGDAWBgNVBAoTD0lSRFN0dWR5bGlua0IyQjEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxJTAjBgNVBAMTHHNpZ24tYW5kLWVuYy5kZXYuaXJkLmdvdnQubnoxFTATBgNVBCkTDHNpZ24tYW5kLWVuYzEoMCYGCSqGSIb3DQEJARYZY2hyaXMuc2NodWx0ekBpcmQuZ292dC5uejCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAykyZHVnXjsG220zB3kNOsGBeGP2rdNbLlIqW1D8yZO1fcj3/RhRiqsopbUrb8AU1ClpfhbH2K68kg7V91VAY0qrwNxP+pPPo1vYKMU6pT38qJGQzffr+iV2BCJshZvSk9E7QSWO5mFNstdg19xc+5ST1Lgb3fefuRG2KZVxPx0sCAwEAAaOCAZUwggGRMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDQGCWCGSAGG+EIBDQQnFiVFYXN5LVJTQSBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmljYXRlMB0GA1UdDgQWBBSczRKXKPe3Sin7eFrVXfI7MXckzzCB+QYDVR0jBIHxMIHugBSLWxPSZd9otEj16vhLyovMCI9OMaGByqSBxzCBxDELMAkGA1UEBhMCTloxDTALBgNVBAgTBFdHVE4xEzARBgNVBAcTCldlbGxpbmd0b24xGDAWBgNVBAoTD0lSRFN0dWR5bGlua0IyQjEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxHjAcBgNVBAMTFWRldmNhLmIyYi5pcmQuZ292dC5uejEXMBUGA1UEKRMORGV2ZWxvcG1lbnQgQ0ExKDAmBgkqhkiG9w0BCQEWGWNocmlzLnNjaHVsdHpAaXJkLmdvdnQubnqCCQDL/qDdlx2j6DATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADgYEAS4ZPIVVpgTOGN4XcIC3SiYlxF8wYg7qnUhH5wJsAD3VCKfj68j9FSJtdBWLlWvvRxEoDP2lZ0IbFl6Rjnl+2ibzFnyac2G1AVm5mwPrNKHBQJ9J5eDJi0iUVY7Wphz86tKnqj34GvlHPNXmrF7oGEcDhPwK0T8zRdE/pvKIUiJc=</wsse:BinarySecurityToken>
    <ds:Signature Id="Signature-2" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <ds:Reference URI="#CertId-D05E596B5ABC341FEB13505090224061">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>3iVAUEAt8vAb7Ku+jf2gwSkSm0Q=</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#UsernameToken-1">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>r4HLEAWJldJwmEmcAqV6Y8rnTPE=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
        YGh2I3VcukqjT0O7hKItiykWN5tlID18ZXRCwQjXriHmnVsO4wGcHjWfmhuNDecq+xRN+SjG8E7M
        2Rx/5/BbFKbVlNOkQOSbSxIs1YT9GaThK16pMrX5KRkkJme1W3R0pGIIQh6gGRSUf79RZUIYxyVl
        LqdIe561TXXDdtbt/6Q=
        </ds:SignatureValue>
        <ds:KeyInfo Id="KeyId-D05E596B5ABC341FEB13505090224372">
            <wsse:SecurityTokenReference wsu:Id="STRId-D05E596B5ABC341FEB13505090224373" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                <wsse:Reference URI="#CertId-D05E596B5ABC341FEB13505090224061" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/></wsse:SecurityTokenReference>
        </ds:KeyInfo>
    </ds:Signature>
    <wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:Username>XXXXXX</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">XXXXXXX</wsse:Password>
        </wsse:UsernameToken>
    </wsse:Security>
  <ebxml:Messaging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <ebxml:UserMessage>
        <ebxml:MessageInfo>
           <ebxml:Timestamp>2002-02-02T14:18:02.0Z</ebxml:Timestamp>
           <ebxml:MessageId>bf9433d9-c6e9-4c12-9c98-724008a09c21</ebxml:MessageId>
        </ebxml:MessageInfo>
        <ebxml:PartyInfo>
           <ebxml:From>
              <ebxml:PartyId type="identifier">Trading Partner X</ebxml:PartyId>
              <ebxml:Role>Provider</ebxml:Role>
           </ebxml:From>
           <ebxml:To>
              <ebxml:PartyId type="identifier">XXXXXXX</ebxml:PartyId>
              <ebxml:Role>Requestor</ebxml:Role>
           </ebxml:To>
        </ebxml:PartyInfo>
        <ebxml:CollaborationInfo>
           <ebxml:AgreementRef>urn:XXXXXXXXX</ebxml:AgreementRef>
           <ebxml:Service type="Web Service">urn:XXXXXXXX</ebxml:Service>
           <ebxml:Action>customerInformation</ebxml:Action>
           <ebxml:ConversationId>e302426a-b2d9-4ff1-a14b-fbbc2f40a017</ebxml:ConversationId>
        </ebxml:CollaborationInfo>
     </ebxml:UserMessage>
  </ebxml:Messaging>
   </soapenv:Header>
   <soapenv:Body>
  <urn:ConnectionTest>
     <Message>Bonjour</Message>
  </urn:ConnectionTest>
   </soapenv:Body>
</soapenv:Envelope>

我们与一些文档提供。保卫科被复制以下

We were supplied with some documentation. The security section is copied below

以下安全必须应用到每个请求按以下顺序:
一WSSE:用户名令牌必须包含与包含以下内容:

The following security must be applied to each request in the following order: A wsse:UsernameToken must be included and contain:


  1. 代理的门户网站用户名的WSSE的价值:用户名元素

  2. 代理的门户网站上的密码为WSSE的价值:在密码元素
    签名块PasswordText(明文):
    数字签名是使用X509证书创建的。每个软件供应商须持有和保护的有效证书并通过[待定]发行的私钥。对于每个服务请求的软件必须:

  1. The Agent‟s Portal Username for the value of the wsse:Username element
  2. The Agent‟s Portal Password for the value of the wsse:PasswordText (clear text) in the Password element A Signature block: Digital Signatures are created using x509 certificates. Each software provider is required to hold and protect a valid certificate and private key issued by [To Be Determined]. With each service request the software must:

包括用于签名作为WSSE私钥相匹配的证书:的BinarySecurityToken,并用它作为WSSE:SecurityTokenReference对于签名

Include the Certificate that matches the private key used for signing as a wsse:BinarySecurityToken and use it as the wsse:SecurityTokenReference for the Signature

soapUI的配置我的图像最初给

Update

Image of the SoapUI configuration I was initially given

推荐答案

今天终于排序的问题。术语来讲,这不是我需要签署SecurityTokenReference,但二进制安全令牌。

Finally sorted the problem today. In terms of terminology, it is not the SecurityTokenReference that I need to sign, but the Binary Security Token.

在为了做到这一点,我需要隐藏发起证书和收件人,并添加一个签名支持令牌。

In order to do this I needed to hide the certificates for Initiator and Recipient and add a signed supporting token.

我回去用配置来创建和签署的消息,而不是试图手动添加签名。

I went back to using configuration to create and sign the message, rather than trying to add the signature manually.

这会停止工作这另一个问题是,我有一个不正确的命名空间,我自定义的信息头,所以铭记的命名空间,我没想到他们会像因为它们是什么重要的。

Other problem that would have stopped this from working is that I had an incorrect namespace on my custom 'Messaging' header, so be mindful of namespaces, I didn't think they would be as important as what they are.

创建绑定的代码如下

    private System.ServiceModel.Channels.Binding GetCustomBinding()
    {
        System.ServiceModel.Channels.AsymmetricSecurityBindingElement asbe = new AsymmetricSecurityBindingElement();
        asbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;

        asbe.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };
        asbe.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };
        asbe.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;

        asbe.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
        asbe.EnableUnsecuredResponse = true;
        asbe.IncludeTimestamp = false;
        asbe.SetKeyDerivation(false);
        asbe.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
        asbe.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
        asbe.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());

        CustomBinding myBinding = new CustomBinding();
        myBinding.Elements.Add(asbe);
        myBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));

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

        return myBinding;
    }

在使用绑定,我设置了ClientCredentials用户名,ServiceCertificate和ClientCertificate和如预期的所有作品。

When using the binding, I set the ClientCredentials UserName, ServiceCertificate and ClientCertificate, and all works as expected.

使用代码如下:

using (CredentialingService.SOAPPortTypeClient client = GetCredentialingClient())
{
    client.Open();
    etc....
}

private static CredentialingService.SOAPPortTypeClient GetCredentialingClient()
{
    CredentialingService.SOAPPortTypeClient client = new CredentialingService.SOAPPortTypeClient(GetCustomBinding(), new EndpointAddress(new Uri(Settings.AppSettings.B2BUrl), new DnsEndpointIdentity(Settings.AppSettings.B2BDNSEndpoint), new AddressHeaderCollection()));
    client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
    SetClientCredentialsSecurity(client.ClientCredentials);

    return client;
}

其中GetCustomBinding在我的职位是指定

where GetCustomBinding is specified in my post

SetClientCredentialsSecurity就是证书来设定的,如下:

SetClientCredentialsSecurity is where the certificate is set, and is as follows

private static void SetClientCredentialsSecurity(ClientCredentials clientCredentials)
{
    clientCredentials.UserName.UserName = Settings.AppSettings.B2BUserName;
    clientCredentials.UserName.Password = Settings.AppSettings.B2BPassword;

    string directoryName = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
    clientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(Path.Combine(directoryName, Settings.AppSettings.B2BServerCertificateName));
    clientCredentials.ClientCertificate.Certificate = new X509Certificate2(Path.Combine(directoryName, Settings.AppSettings.B2BClientCertificateName), Settings.AppSettings.B2BClientCertificatePassword);
}



希望这使得它更清楚一点

Hopefully that makes it a bit clearer

这篇关于如何使WCF客户端符合特定的WS-Security - 注册用户名令牌和SecurityTokenReference的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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