title: Signed SOAP header has two BinarySecurityTokens (when in fact it could and should have one)
body: <p>I'm trying to requests a security token from a STS service. The service is 3rd party, so I can't modify it, check logs, etc.</p>
  
  <p>The resulting request SOAP message looks almost identical to a sample request I have. It's only that there are two <code>BinarySecurityToken</code> elements added <strong>with identical values</strong>, while the proper request contains only one token. </p>
  
  <p>The SOAP message looks like this:</p>
  
  <pre><code>&lt;s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&gt;
    &lt;s:Header&gt;
      &lt;o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"&gt;
        &lt;u:Timestamp u:Id="uuid-4db59a59-9180-4efe-92d0-14aefcbf68d5-1"&gt;
          &lt;u:Created&gt;2014-08-22T07:51:45.763Z&lt;/u:Created&gt;
          &lt;u:Expires&gt;2014-08-22T08:51:45.763Z&lt;/u:Expires&gt;
        &lt;/u:Timestamp&gt;
        &lt;o:BinarySecurityToken u:Id="uuid-54e35db8-29dc-4d3c-bba2-c6eacb7cf4e9-4" 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"&gt;...&lt;/o:BinarySecurityToken&gt;
        &lt;o:BinarySecurityToken u:Id="uuid-54e35db8-29dc-4d3c-bba2-c6eacb7cf4e9-2" 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"&gt;...&lt;/o:BinarySecurityToken&gt;
        &lt;Signature xmlns="http://www.w3.org/2000/09/xmldsig#"&gt;
          &lt;SignedInfo&gt;
            &lt;CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
            &lt;SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/&gt;
            &lt;Reference URI="#_1"&gt;
              &lt;Transforms&gt;
                &lt;Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
              &lt;/Transforms&gt;
              &lt;DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
              &lt;DigestValue&gt;...&lt;/DigestValue&gt;
            &lt;/Reference&gt;
            &lt;Reference URI="#uuid-4db59a59-9180-4efe-92d0-14aefcbf68d5-1"&gt;
              &lt;Transforms&gt;
                &lt;Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
              &lt;/Transforms&gt;
              &lt;DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
              &lt;DigestValue&gt;...&lt;/DigestValue&gt;
            &lt;/Reference&gt;
            &lt;Reference URI="#uuid-54e35db8-29dc-4d3c-bba2-c6eacb7cf4e9-2"&gt;
              &lt;Transforms&gt;
                &lt;Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
              &lt;/Transforms&gt;
              &lt;DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
              &lt;DigestValue&gt;...&lt;/DigestValue&gt;
            &lt;/Reference&gt;
          &lt;/SignedInfo&gt;
          &lt;SignatureValue&gt;.../SignatureValue&gt;
          &lt;KeyInfo&gt;
            &lt;o:SecurityTokenReference&gt;
              &lt;o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-54e35db8-29dc-4d3c-bba2-c6eacb7cf4e9-4"/&gt;
            &lt;/o:SecurityTokenReference&gt;
          &lt;/KeyInfo&gt;
        &lt;/Signature&gt;
      &lt;/o:Security&gt;
    &lt;/s:Header&gt;
    &lt;s:Body u:Id="_1"&gt;
      &lt;trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512"&gt;
        &lt;trust:Claims Dialect="http://docs.oasis-open.org/wsfed/authorization/200706/authclaims" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706"&gt;
          &lt;auth:ClaimType Uri="custom claim" Optional="true"&gt;
            &lt;auth:Value&gt;...&lt;/auth:Value&gt;
          &lt;/auth:ClaimType&gt;
        &lt;/trust:Claims&gt;
        &lt;trust:KeyType&gt;http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey&lt;/trust:KeyType&gt;
        &lt;trust:RequestType&gt;http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue&lt;/trust:RequestType&gt;
        &lt;trust:TokenType&gt;http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1&lt;/trust:TokenType&gt;
      &lt;/trust:RequestSecurityToken&gt;
    &lt;/s:Body&gt;
  &lt;/s:Envelope&gt;
  </code></pre>
  
  <p>The security binding element as well as the binding are configured like this:</p>
  
  <pre><code>AsymmetricSecurityBindingElement messageSecurity = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(
      MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10
  );
  
  messageSecurity.IncludeTimestamp = true;
  messageSecurity.LocalClientSettings.TimestampValidityDuration = TimeSpan.FromHours(1);
  messageSecurity.ProtectTokens = true;
  messageSecurity.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
  messageSecurity.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
  messageSecurity.EnableUnsecuredResponse = true;
  
  X509SecurityTokenParameters initiatorParams = new X509SecurityTokenParameters
  {
      InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient,
      ReferenceStyle = SecurityTokenReferenceStyle.Internal,
      RequireDerivedKeys = false,
      X509ReferenceStyle = X509KeyIdentifierClauseType.IssuerSerial
  };
  
  X509SecurityTokenParameters recipientParams = new X509SecurityTokenParameters
  {
      InclusionMode = SecurityTokenInclusionMode.Never,
      ReferenceStyle = SecurityTokenReferenceStyle.Internal,
      RequireDerivedKeys = false,
      X509ReferenceStyle = X509KeyIdentifierClauseType.IssuerSerial
  };
  
  X509SecurityTokenParameters endpointParams = new X509SecurityTokenParameters
  {
      InclusionMode = SecurityTokenInclusionMode.Once,
      ReferenceStyle = SecurityTokenReferenceStyle.Internal,
      RequireDerivedKeys = false,
      X509ReferenceStyle = X509KeyIdentifierClauseType.IssuerSerial
  };
  
  messageSecurity.InitiatorTokenParameters = initiatorParams;
  messageSecurity.RecipientTokenParameters = recipientParams;
  messageSecurity.EndpointSupportingTokenParameters.Signed.Add(endpointParams);
  
  HttpsTransportBindingElement elem = new HttpsTransportBindingElement();
  CustomBinding binding = new CustomBinding(messageSecurity, new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8), elem);
  
  return binding;
  </code></pre>
  
  <p>I also have specifically configured the <code>WSTrustChannelFactory</code> to only sign messages (not sign &amp; encrypt):</p>
  
  <pre><code>var factory = new WSTrustChannelFactory(binding, endpoint);
  factory.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
  </code></pre>
  
  <p>The only thing is that the service's security policy mentions that the initiator token should be a SAML token, while I'm using an X509SecurityTokenParameters. This is mostly because I have no idea how to add a SAML token, but I'm not sure what difference this would make.</p>
  
  <p>For reference, the WS-Security policy is:</p>
  
  <pre><code>&lt;wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
      xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"&gt; 
          &lt;sp:AsymmetricBinding&gt;
          &lt;wsp:Policy&gt; 
              &lt;sp:InitiatorToken&gt;
                  &lt;wsp:Policy&gt;
                      &lt;sp:SamlToken
                      sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"&gt; 
                          &lt;wsp:Policy&gt;
                              &lt;sp:WssSamlV11Token10/&gt;
                          &lt;/wsp:Policy&gt;
                      &lt;/sp:SamlToken&gt;
                  &lt;/wsp:Policy&gt;
              &lt;/sp:InitiatorToken&gt;
          &lt;sp:RecipientToken&gt;
              &lt;wsp:Policy&gt;
                  &lt;sp:X509Token
                  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"&gt;
              &lt;wsp:Policy&gt;
                  &lt;sp:WssX509V3Token10/&gt;
              &lt;/wsp:Policy&gt;
                  &lt;/sp:X509Token&gt;
              &lt;/wsp:Policy&gt;
          &lt;/sp:RecipientToken&gt;
          &lt;sp:AlgorithmSuite&gt;
              &lt;wsp:Policy&gt;
                  &lt;sp:Basic256/&gt;
              &lt;/wsp:Policy&gt;
          &lt;/sp:AlgorithmSuite&gt;
          &lt;sp:Layout&gt;
              &lt;wsp:Policy&gt;
                  &lt;sp:Lax/&gt;
              &lt;/wsp:Policy&gt;
          &lt;/sp:Layout&gt;
          &lt;sp:IncludeTimestamp/&gt;
          &lt;sp:ProtectTokens/&gt;
          &lt;sp:OnlySignEntireHeadersAndBody/&gt;
          &lt;/wsp:Policy&gt;
      &lt;/sp:AsymmetricBinding&gt;
      &lt;sp:Wss10&gt;
          &lt;wsp:Policy&gt;
              &lt;sp:MustSupportRefKeyIdentifier/&gt;
              &lt;sp:MustSupportRefIssuerSerial/&gt;
          &lt;/wsp:Policy&gt;
      &lt;/sp:Wss10&gt;
      &lt;sp:SignedParts&gt;
          &lt;sp:Body/&gt;
      &lt;/sp:SignedParts&gt;
  &lt;/wsp:Policy&gt;
  </code></pre>
  
  <p>Ultimately, I'm after a way to have the message contain only one binary token. If the only way is to manually alter the SOAP XML just before it is being sent, then so be it. </p>