Signed SOAP header has two BinarySecurityTokens (when in fact it could and should have one)

情到浓时终转凉″ 提交于 2019-12-13 20:24:16

问题


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.

The resulting request SOAP message looks almost identical to a sample request I have. It's only that there are two BinarySecurityToken elements added with identical values, while the proper request contains only one token.

The SOAP message looks like this:

<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">
  <s:Header>
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <u:Timestamp u:Id="uuid-4db59a59-9180-4efe-92d0-14aefcbf68d5-1">
        <u:Created>2014-08-22T07:51:45.763Z</u:Created>
        <u:Expires>2014-08-22T08:51:45.763Z</u:Expires>
      </u:Timestamp>
      <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">...</o:BinarySecurityToken>
      <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">...</o:BinarySecurityToken>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <Reference URI="#_1">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <DigestValue>...</DigestValue>
          </Reference>
          <Reference URI="#uuid-4db59a59-9180-4efe-92d0-14aefcbf68d5-1">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <DigestValue>...</DigestValue>
          </Reference>
          <Reference URI="#uuid-54e35db8-29dc-4d3c-bba2-c6eacb7cf4e9-2">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <DigestValue>...</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>.../SignatureValue>
        <KeyInfo>
          <o:SecurityTokenReference>
            <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"/>
          </o:SecurityTokenReference>
        </KeyInfo>
      </Signature>
    </o:Security>
  </s:Header>
  <s:Body u:Id="_1">
    <trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
      <trust:Claims Dialect="http://docs.oasis-open.org/wsfed/authorization/200706/authclaims" xmlns:auth="http://docs.oasis-open.org/wsfed/authorization/200706">
        <auth:ClaimType Uri="custom claim" Optional="true">
          <auth:Value>...</auth:Value>
        </auth:ClaimType>
      </trust:Claims>
      <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey</trust:KeyType>
      <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
      <trust:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1</trust:TokenType>
    </trust:RequestSecurityToken>
  </s:Body>
</s:Envelope>

The security binding element as well as the binding are configured like this:

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;

I also have specifically configured the WSTrustChannelFactory to only sign messages (not sign & encrypt):

var factory = new WSTrustChannelFactory(binding, endpoint);
factory.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;

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.

For reference, the WS-Security policy is:

<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
    xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> 
        <sp:AsymmetricBinding>
        <wsp:Policy> 
            <sp:InitiatorToken>
                <wsp:Policy>
                    <sp:SamlToken
                    sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> 
                        <wsp:Policy>
                            <sp:WssSamlV11Token10/>
                        </wsp:Policy>
                    </sp:SamlToken>
                </wsp:Policy>
            </sp:InitiatorToken>
        <sp:RecipientToken>
            <wsp:Policy>
                <sp:X509Token
                sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
            <wsp:Policy>
                <sp:WssX509V3Token10/>
            </wsp:Policy>
                </sp:X509Token>
            </wsp:Policy>
        </sp:RecipientToken>
        <sp:AlgorithmSuite>
            <wsp:Policy>
                <sp:Basic256/>
            </wsp:Policy>
        </sp:AlgorithmSuite>
        <sp:Layout>
            <wsp:Policy>
                <sp:Lax/>
            </wsp:Policy>
        </sp:Layout>
        <sp:IncludeTimestamp/>
        <sp:ProtectTokens/>
        <sp:OnlySignEntireHeadersAndBody/>
        </wsp:Policy>
    </sp:AsymmetricBinding>
    <sp:Wss10>
        <wsp:Policy>
            <sp:MustSupportRefKeyIdentifier/>
            <sp:MustSupportRefIssuerSerial/>
        </wsp:Policy>
    </sp:Wss10>
    <sp:SignedParts>
        <sp:Body/>
    </sp:SignedParts>
</wsp:Policy>

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.


回答1:


I have successfully managed to get a token back from the STS service by using the following code for creating the binding.

It appears that the extra token was being added when X509SecurityTokenParameters.InclusionMode was set to anything else than SecurityTokenInclusionMode.Never on the either of InitiatorTokenParameters, RecipientTokenParameters or EndpointSupportingTokenParameters.Signed.

The code for creating the binding is below, in case anyone else needs it:

var messageSecurity = new AsymmetricSecurityBindingElement
{
    MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10,
    InitiatorTokenParameters = new X509SecurityTokenParameters
    {
        InclusionMode = SecurityTokenInclusionMode.Never,
        ReferenceStyle = SecurityTokenReferenceStyle.Internal,
    },
    RecipientTokenParameters = new X509SecurityTokenParameters
    {
        InclusionMode = SecurityTokenInclusionMode.Never,
        ReferenceStyle = SecurityTokenReferenceStyle.Internal
    },
    MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt,
    SecurityHeaderLayout = SecurityHeaderLayout.Lax,
    EnableUnsecuredResponse = true,
    IncludeTimestamp = true
};
messageSecurity.SetKeyDerivation(false);
messageSecurity.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
messageSecurity.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
messageSecurity.LocalClientSettings.TimestampValidityDuration = TimeSpan.FromHours(1);
messageSecurity.RequireSignatureConfirmation = true;
messageSecurity.AllowSerializedSigningTokenOnReply = true;

HttpsTransportBindingElement elem = new HttpsTransportBindingElement { RequireClientCertificate = true };
CustomBinding binding = new CustomBinding(messageSecurity, new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8), elem);

I also had an issue with the RequestSecurityToken serialization in the SOAP body. WCF was using a different namespace here:

<auth:ClaimType Uri="..." xmlns:auth="http://schemas.xmlsoap.org/ws/2006/12/authorization">

I solved this with a client message inspector, where I adjust the namespaces right before they are being signed and sent.



来源:https://stackoverflow.com/questions/25442354/signed-soap-header-has-two-binarysecuritytokens-when-in-fact-it-could-and-shoul

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