The case of the missing ‘Dialect’ (part 5)

This is the fifth in a series of posts [part1, part2, part3, part4] where I describe some issues regarding the usage of claims requirements on the WCF platform.

In the last post, I described how to build a service that relies on the BizTalk Identity Services for the authorization decisions, and also how to build a client that uses this service. However, the execution of this client ended up on a “ID3037: The specified request failed.” fault returned by the BizTalk Identity Services STS.

Unfortunately this message error is not documented, so I went to analyze the message exchange between the client and the STS. For this, I used the message logging capability of WCF. I enabled the logging at service level and not at transport level, because at this level the messages are enciphered.

Here is the body of the Security Token Request message:

   1: <s:Body>
   2:    <t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
   3:       <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
   4:       <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
   5:          <EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
   6:             <Address>http://<servicehost>:8080/saac/ep1</Address>
   7:             <Identity xmlns="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity">
   8:                <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
   9:                   <X509Data>
  10:                      <X509Certificate><!--removed--></X509Certificate>
  11:                   </X509Data>
  12:                </KeyInfo>
  13:             </Identity>
  14:          </EndpointReference>
  15:       </wsp:AppliesTo>
  16:       <t:Entropy><!--Removed--></t:Entropy>
  17:       <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1</t:TokenType>
  18:       <t:KeyType>http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey</t:KeyType>
  19:       <t:KeySize>256</t:KeySize>
  20:       <t:EncryptWith>http://www.w3.org/2001/04/xmlenc#aes256-cbc</t:EncryptWith>
  21:       <t:SignWith>http://www.w3.org/2000/09/xmldsig#hmac-sha1</t:SignWith>
  22:       <t:CanonicalizationAlgorithm>http://www.w3.org/2001/10/xml-exc-c14n#</t:CanonicalizationAlgorithm>
  23:       <t:EncryptionAlgorithm>http://www.w3.org/2001/04/xmlenc#aes256-cbc</t:EncryptionAlgorithm>
  24:       <t:Claims>
  25:          <ClaimType Uri="http://schemas.xmlsoap.org/ws/2006/12/authorization/claims/action" xmlns="http://schemas.xmlsoap.org/ws/2006/12/authorization">
  26:             <Value></Value>
  27:          </ClaimType>
  28:       </t:Claims>
  29:       <t:ComputedKeyAlgorithm>http://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1</t:ComputedKeyAlgorithm>
  30:    </t:RequestSecurityToken>
  31: </s:Body>

The problems is not evident, but it is visible in the above message: the <t:Claims> element does not have the Dialect attribute.

Why wasn’t it there?

Before answering this question, let’s recall why it should be there?

Remember that the required claims are one of the service requisites expressed in the service’s policy. Namely, in the <RequestSecurityTokenTemplate>. According to the WS-SecurityPolicy spec:

This required element contains elements which MUST be copied into the request sent to the specified issuer. Note: the initiator is not required to understand the contents of this element.

So, the next step was to verify if the Dialect attribute was in the service policy. Remember, from last post, that the claims requirements were defined in an XML element inserted in the TokenRequestParameters collection.

As seen in the above fragment, the Dialect attribute is present in the service’s policy

   1: <sp:RequestSecurityTokenTemplate>
   2:    <t:TokenType xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1</t:TokenType>
   3:    <t:KeyType xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey</t:KeyType>
   4:    <t:KeySize xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">256</t:KeySize>
   5:    <t:EncryptWith xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">http://www.w3.org/2001/04/xmlenc#aes256-cbc</t:EncryptWith>
   6:    <t:SignWith xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">http://www.w3.org/2000/09/xmldsig#hmac-sha1</t:SignWith>
   7:    <t:CanonicalizationAlgorithm xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">http://www.w3.org/2001/10/xml-exc-c14n#</t:CanonicalizationAlgorithm>
   8:    <t:EncryptionAlgorithm xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">http://www.w3.org/2001/04/xmlenc#aes256-cbc</t:EncryptionAlgorithm>
   9:    <Claims Dialect="http://schemas.xmlsoap.org/ws/2006/12/authorization/authclaims" xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
  10:       <ClaimType Uri="http://schemas.xmlsoap.org/ws/2006/12/authorization/claims/action" xmlns="http://schemas.xmlsoap.org/ws/2006/12/authorization">
  11:          <Value/>
  12:       </ClaimType>
  13:    </Claims>
  14: </sp:RequestSecurityTokenTemplate>

Well, apparently this is a “bug” in WCF’s WSDL import process, which handles the <Claims> element differently.

What are the workarounds?

  1. One method is to intercept the token request at the client side, using a custom token provider and explicitly insert the correct claim requirements. This is what is done by some of the BizTalk services SDK samples.
  2. Another method is to change the clients’s binding (obtained via the the MetadataResolver) and insert the claims requirement. This is done in the following fragment
   1: XNamespace wst = "http://schemas.xmlsoap.org/ws/2005/02/trust";
   2: XNamespace wsf = "http://schemas.xmlsoap.org/ws/2006/12/authorization";
   3:  
   4: var claims = new XElement(wst + "Claims",
   5:     new XAttribute("Dialect", "http://schemas.xmlsoap.org/ws/2006/12/authorization/authclaims"),
   6:     new XElement(wsf + "ClaimType",
   7:         new XAttribute("Uri", "http://schemas.xmlsoap.org/ws/2006/12/authorization/claims/action"),
   8:         new XElement(wsf + "Value")
   9:     )
  10: );
  11: var xdoc = new XmlDocument();
  12: xdoc.Load(claims.CreateReader());
  13: clientBinding.Security.Message.TokenRequestParameters.Add(xdoc.DocumentElement);

In both workarounds, it is necessary to remove the original Claims element (the one imported without the Dialect attribute).

After this change everything runs well.

2 thoughts on “The case of the missing ‘Dialect’ (part 5)

  1. Pingback: The case of the missing ‘Dialect’ (epilogue) « Pedro Félix’s shared memory

  2. Matias Woloski

    Thanks for these articles Pedro!

    A small comment. The ClaimType element should have an Optional=”true” attribute. Otherwise Biztalk raise an exception. At least that happened to me.

    Thanks
    Matias

    Reply

Leave a comment