如何使用SAML断言令牌对SOAP消息(主体和标头元素)进行签名



情况如下:

  1. 我有一个来自STS的安全令牌,其形式为GenericXmlSecurityToken(我还有SAML Assertion元素)
  2. 我需要使用这个安全令牌来调用第三方服务,该服务除了WS2007FederationHttpBinding可以做的事情之外,还需要在请求中添加一些额外的东西
  3. 除了SOAP安全标头中的SAML断言元素外,实际的SOAP请求还必须包含签名元素(来自命名空间http://www.w3.org/2000/09/xmldsig#),该签名元素使用SAML断言对时间戳元素和主体元素进行签名
  4. WS2007FederationHttpBinding以及许多自定义绑定变体无法在值类型为http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID的签名中包含密钥引用元素(因此,SAML断言)
  5. 我能从中得到的最多的东西(通过ProtectTokens=true)是一个签名的SAML断言元素,但不是更多

基本上,我需要在请求中得到的是:

<soapenv:Header>
  <wsse:Security>
    <saml:Assertion=""  AssertionID = "ID_56eecf2a-a143-4ec9-ab85-479d8602122f">
      ...
    </saml:Assertion>
    <WSU:Timestamp>
      ...
    </WSU:Timestamp>
    <ds:Signature>
      <ds:SignedInfo>
        <ds:CanonicalizationMethod Algorithm="xml-exc-c14n#"/>
        <ds:SignatureMethod Algorithm="#rsa-sha1"/>
        <!--Body signature-->
        <ds:Reference URI="#id">
          <ds:Transforms>
            < ds: Transform  Algorithm = "xml-exc-c14n #" />
          </ds:Transforms>
          <ds:DigestMethod Algorithm="#sha1"/>
          <ds:DigestValue >
            di3JiPJM90D3P62ChO1d4Sy12 + 4 =
          </ds:DigestValue DigestValue>
        </ds:Reference>
        <!--Timestamp element signature-->
        <ds:Reference  URI = "#Timestamp" >
          <ds:Transforms>
            <ds:Transform  Algorithm = "xml-exc-c14n #" />
          </ds:Transforms>
          <ds:DigestMethod Algorithm="#sha1"/>
          < ds:DigestValue>C+GkwwH5RuXocsD0iphwUvmQpj0=</ds:DigestValue>
        </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>kq+FG6qqdx...==</ds:SignatureValue>
      <!--Key reference, pointing back to the SAML assertion element-->
      <!--This is the actual problem. Didn't manage to add this at all.-->
      <ds:KeyInfo>
        <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0 #SAMLAssertionID">
            ID_56eecf2a-a143-4ec9-ab85-479d8602122f</wsse:KeyIdentifier>
        </wsse:SecurityTokenReference>
      </ds:KeyInfo>
    </ds:Signature>
  </wsse:Security>
</soapenv:Header>
<soapenv:Body wsu:Id="id">
  ...
</soapenv:Body>

然而,我不知道如何配置WS2007FederationHttpBinding(或自定义绑定)来添加签名。

我现在使用的是:

/**
 * 
 * Federation binding stuff
 * 
 */
var federationBinding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
federationBinding.Security.Message.EstablishSecurityContext = false;
federationBinding.Security.Message.IssuedKeyType = SecurityKeyType.AsymmetricKey;
federationBinding.Security.Message.NegotiateServiceCredential = false;
federationBinding.Security.Message.IssuedTokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID";
federationBinding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.Basic256;
/**
 * 
 * Custom binding, the one actually used by the channel
 * 
 */
var binding = new CustomBinding(federationBinding.CreateBindingElements());
binding.Elements.Remove(binding.Elements.FirstOrDefault(i => i is TextMessageEncodingBindingElement));
var messageSecurity = (TransportSecurityBindingElement)binding.Elements.FirstOrDefault(i => i is TransportSecurityBindingElement);
//Remove it, I add another one later
binding.Elements.Remove(messageSecurity);
//Security element configuration
var secBinding = new AsymmetricSecurityBindingElement()
{
    MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10,
    ProtectTokens = true,
    SecurityHeaderLayout = SecurityHeaderLayout.Lax,
    IncludeTimestamp = true,
    EnableUnsecuredResponse = true,
    DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256
};
secBinding.InitiatorTokenParameters = new IssuedSecurityTokenParameters(
        "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID");
secBinding.RecipientTokenParameters = new IssuedSecurityTokenParameters(
        "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID");
secBinding.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;

除此之外,我还尝试使用TransportSecurityBindingElement,结果相同:我可以在请求中获得令牌,但不能获得签名。

欢迎对此有任何想法/提示。

值得一提的是,我最终用Java和JAX-WS实现了客户端。这很顺利,因为JAX-WS API很好地映射(有时甚至是1:1)到WS-Security SOAP元素(wsse:Security)。

基本上,我实现了一个自定义的SOAPHandler<SOAPMessageContext>,它调用STS,然后使用SAML令牌构建wsse:Security元素,并使用该令牌对时间戳和传出请求的主体进行签名。

我不会把它标记为一个答案,因为它真的不是。只是一种选择。还因为这个问题获得了汤草徽章(万岁)。

相关内容

  • 没有找到相关文章

最新更新