Binding producing 2 security tags , soap xml with 2 X509's+ usernmaetoken with nonce

帅比萌擦擦* 提交于 2019-12-08 05:43:44

问题


I am using this blog to implement nonce, password text. http://benpowell.org/supporting-the-ws-i-basic-profile-password-digest-in-a-wcf-client-proxy/ I've seen many other blogs with do but i would like to try this out.

This is what I have done so far Let me first say, I have no control over the service. I am just the consumer.

passwordtextmessaginspector implements IClientMessageInspector which lets us modify the outgoing message. In this case, I would like to add usernametoken to the message including nonce. So Ben uses WSE in the BeforeRequestSent. using System;

    public class PasswordTextMessageInspector : IClientMessageInspector
    {
        public string Username { get; set; }
        public string Password { get; set; }

        public PasswordTextMessageInspector(string username, string password)
        {
            this.Username = username;
            this.Password = password;
        }

        #region IClientMessageInspector Members

        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            throw new NotImplementedException();
        }

        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
        {
            // Use the WSE 3.0 security token class
            UsernameToken token = new UsernameToken(this.Username, this.Password, PasswordOption.SendPlainText);

            // Serialize the token to XML
            XmlElement securityToken = token.GetXml(new XmlDocument());

            //
            MessageHeader securityHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityToken, false);
            request.Headers.Add(securityHeader);

            // complete
            return Convert.DBNull;
        }

This is the custom behavior

    public class PasswordTextBehavior : IEndpointBehavior
    {

        public string Username { get; set; }
        public string Password { get; set; }

        public PasswordTextBehavior(string username, string password)
        {
            this.Username = username;
            this.Password = password;
        }

        #region IEndpointBehavior Members

        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            throw new NotImplementedException();


        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new PasswordTextMessageInspector(this.Username, this.Password));
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            throw new NotImplementedException();
        }

        public void Validate(ServiceEndpoint endpoint)
        {
           throw new NotImplementedException();
        }

        #endregion
    }
}

My soap request already has 2 x509certificates. I am just adding this usernametoken with nonce before sending it. This is how my proxyclient looks like

   private ProxyGeneration.MHSClient GetProxy()
        {

            ProxyGeneration.MHSClient proxy = new ProxyGeneration.MHSClient(GetCustomBinding(), new EndpointAddress(new Uri("https://service100.emedny.org:9047/MHService"), EndpointIdentity.CreateDnsIdentity("SEREVR"), new AddressHeaderCollection()));

    var vs = proxy.Endpoint.Behaviors.Where((i) => i.GetType().Namespace.Contains("VisualStudio"));
    proxy.Endpoint.Behaviors.Remove((System.ServiceModel.Description.IEndpointBehavior)vs.Single());
    proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName,"USER");
    proxy.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "SERVER");
    PasswordTextBehavior behavior = new PasswordTextBehavior("USER", "PWD");
    proxy.Endpoint.Behaviors.Add(behavior);

   proxy.ClientCredentials.UserName.UserName = "USER";
   proxy.ClientCredentials.UserName.Password = "PWD";

    return proxy;
        }

private CustomBinding GetCustomBinding()
{


    AsymmetricSecurityBindingElement secBE = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement
        (
        MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10
        );
    secBE.ProtectTokens = false;
    X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();
    x509ProtectionParameters.RequireDerivedKeys = false;
    x509ProtectionParameters.X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier;
    x509ProtectionParameters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;

    //x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
    secBE.MessageSecurityVersion = System.ServiceModel.MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
    secBE.InitiatorTokenParameters = x509ProtectionParameters;
    secBE.RecipientTokenParameters = x509ProtectionParameters;
    secBE.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;

    secBE.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
    secBE.EnableUnsecuredResponse = true;
    secBE.SetKeyDerivation(false);
    secBE.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.TripleDesRsa15;
    secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
    secBE.ProtectTokens = true;
    //  secBE.in = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false );
    secBE.EnableUnsecuredResponse = true;
    secBE.IncludeTimestamp = false;

    TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressing10, System.Text.Encoding.UTF8);
    HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement();
    httpsBE.RequireClientCertificate = true;

    CustomBinding myBinding = new CustomBinding();
    myBinding.Elements.Add(secBE);
    myBinding.Elements.Add(textEncBE);
    myBinding.Elements.Add(httpsBE);
    return myBinding;
}

So I am adding a new Behavior PasswordTextBehavior proxy.endpoint.behavior.add(passwordtextbehavior).

Is this a valid way to do this. I am getting two security sections.

My header

  <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
 <wsse:UsernameToken wsu:Id="SecurityToken-ec50def9-1c3b-476a-9bcc-2af556e5e0e7" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
 xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsse:Username><!--Removed--></wsse:Username><wsse:Password><!--Removed-->
 </wsse:Password><wsse:Nonce><!--Removed--></wsse:Nonce><wsu:Created>2013-05-28T14:56:46Z</wsu:Created></wsse:UsernameToken>
 </Security>
<a:To s:mustUnderstand="1" u:Id="_6">https://service100.emedny.org:9047/MHService</a:To>
     <o:Security s:mustUnderstand="1" 
     xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
     <o:BinarySecurityToken><!--Removed--></o:BinarySecurityToken>
     <o:BinarySecurityToken><!--Removed--></o:BinarySecurityToken>
     <e:EncryptedKey Id="_0" xmlns:e="http://www.w3.org/2001/04/xmlenc#">

There should be only one security tag and one mustunderstand.

Vendor sample

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mhs="http://org/TEST/mhs/" xmlns:urn="urn:hl7-org:v3">
<soapenv:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-e00c8062-83d2-4f04-88fc-996218e7bb3d">MIICeDCC....(signed user MLS cert).......</wsse:BinarySecurityToken>
<wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-c0cc2cd4-cb77-4fa5-abfa-bd485afd1685">MIIDFj.....( MLS web-service end-point public cert)........</wsse:BinarySecurityToken>
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-970e9a80-00cc-4c86-8ec4-3ba16e029a5b">
<wsse:Username>....your_username.....</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">.....your_plaintext_password....</wsse:Password>
<wsse:Nonce>KNyu6MsXCkTg4DDyvwvEiw==</wsse:Nonce>
<wsu:Created>2010-09-15T18:00:30Z</wsu:Created>
</wsse:UsernameToken>
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference>
<wsse:Reference URI="#SecurityToken-c0cc2cd4-cb77-4fa5-abfa-bd485afd1685" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>
</KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>gpBAWt91pdwhKva............</xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#Enc-0641b860-b16d-4941-91c0-d60bece67794"/>
</xenc:ReferenceList>
</xenc:EncryptedKey>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>

<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#Id-f10674fd-b999-47c9-9568-c11fa5e5405b">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>wRUq.........</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>tBSsaZi........</SignatureValue>
<KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#SecurityToken-e00c8062-83d2-4f04-88fc-996218e7bb3d" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
</wsse:Security>
</soapenv:Header>
<soapenv:Body wsu:Id="Id-f10674fd-b999-47c9-9568-c11fa5e5405b" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<xenc:EncryptedData Id="Enc-0641b860-b16d-4941-91c0-d60bece67794" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<xenc:CipherData>
<xenc:CipherValue>SQsTCAK6ZaVhojB8+Y.........</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</soapenv:Body>
</soapenv:Envelope>

回答1:


You obviously have WCF tracing up and running, which is the bext way to track down problems like this.

You now need an example of the expected message output. From that you can start to work methodically backwards.

You need to build up the signature then using the certificate. If you want, you could use the WSE classes to shortcut your development, in the same I did to support the basic profile.

You might have to create a custom BinarySecurityToken. The standard BinarySecurityToken class extends SecurityToken.

With regards to BinarySecuritytoken support in WCF, there are a number of StackOverflow questions that might help:

  1. Accepting both UsernameToken and BinarySecurityToken in WCF customBinding
  2. How do i sign a BinarySecurityToken in soap message
  3. http://threeisit.com/post/WCF2c-Interop2c-and-the-elusive-BinarySecurityToken.aspx


来源:https://stackoverflow.com/questions/16781439/binding-producing-2-security-tags-soap-xml-with-2-x509s-usernmaetoken-with-n

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!