Как подписать сообщение SOAP (тело и элемент заголовка) маркером подтверждения SAML?

Ситуация такая:

  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 с теми же результатами: я могу получить токен в запросе, но не подпись.

Приветствуются любые идеи/подсказки по этому поводу.


person Marcel N.    schedule 08.09.2014    source источник


Ответы (1)


Как бы то ни было, я реализовал клиент на Java с помощью JAX-WS. Это работало гладко, поскольку JAX-WS API хорошо сопоставляется (иногда даже 1:1) с элементами SOAP WS-Security (wsse:Security).

По сути, я реализовал пользовательский SOAPHandler<SOAPMessageContext>, который вызывает STS, а затем создает элемент wsse:Security с использованием токена SAML, а также подписывает отметку времени и тело исходящего запроса с помощью токена.

Не буду отмечать это как ответ, так как на самом деле это не так. Просто альтернатива. Также получил значок Tumbleweed за этот вопрос (ура).

person Marcel N.    schedule 17.09.2014