Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF: Adding Nonce to UsernameToken

I'm trying to connect to a web service, written in Java, but there's something I can't figure out.

Using WCF and a customBinding, almost everything seems to be fine, except one part of the SOAP message, as it's missing the Nonce and Created part nodes. Obviously I'm missing something, so if you could point me into the right direction, it'd be much appreciated.

Here's the custom binding:

<binding name="CustomHTTPBinding">     <security includeTimestamp="false" authenticationMode="UserNameOverTransport" defaultAlgorithmSuite="Basic256" requireDerivedKeys="True"               messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">     </security>     <textMessageEncoding maxReadPoolSize="211" maxWritePoolSize="2132" messageVersion="Soap11"                          writeEncoding="utf-8"/>     <httpsTransport /> </binding> 

And here's the relevant part of the message:

<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">     <o:UsernameToken u:Id="uuid-c306efd1-e84c-410e-a2ad-1046b368582e-1">         <o:Username>             <!-- Removed-->         </o:Username>         <o:Password>             <!-- Removed-->         </o:Password>     </o:UsernameToken> </o:Security> 

And this's how it should look:

<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">  <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-25763165">     <wsse:Username>..</wsse:Username>     <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">..</wsse:Password>     <wsse:Nonce>6ApOnLn5Aq9KSH46pzzcZA==</wsse:Nonce>     <wsu:Created>2009-05-13T18:59:23.309Z</wsu:Created>  </wsse:UsernameToken> </wsse:Security> 

So the question is: How could I introduce the Nonce and Created elements inside the security part?

like image 312
Adam Vigh Avatar asked May 22 '09 08:05

Adam Vigh


2 Answers

To create the nonce, I had to change a few things

First, added a custom binding in my config

<system.serviceModel>     <bindings>       <customBinding>         <binding name="myCustomBindingConfig">           <security includeTimestamp="false"                      authenticationMode="UserNameOverTransport"                      defaultAlgorithmSuite="Basic256"                      requireDerivedKeys="true"                     messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">           </security>           <textMessageEncoding messageVersion="Soap11"></textMessageEncoding>           <httpsTransport maxReceivedMessageSize="2000000000" />         </binding>       </customBinding>     </bindings> </system.serviceModel>  <client>     <endpoint address="https://..." [other tags]          binding="customBinding" bindingConfiguration="OrangeLeapCustomBindingConfig"/> </client> 

Then, take this code found here: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/4df3354f-0627-42d9-b5fb-6e880b60f8ee and modify it to create the nonce (just a random hash, base-64 encoded)

protected override void WriteTokenCore(System.Xml.XmlWriter writer, System.IdentityModel.Tokens.SecurityToken token) {     Random r = new Random();     string tokennamespace = "o";     DateTime created = DateTime.Now;     string createdStr = created.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");     string nonce = Convert.ToBase64String(Encoding.ASCII.GetBytes(SHA1Encrypt(created + r.Next().ToString())));     System.IdentityModel.Tokens.UserNameSecurityToken unToken = (System.IdentityModel.Tokens.UserNameSecurityToken)token;     writer.WriteRaw(String.Format(     "<{0}:UsernameToken u:Id=\"" + token.Id + "\" xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +     "<{0}:Username>" + unToken.UserName + "</{0}:Username>" +     "<{0}:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">" +     unToken.Password + "</{0}:Password>" +     "<{0}:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" +     nonce + "</{0}:Nonce>" +     "<u:Created>" + createdStr + "</u:Created></{0}:UsernameToken>", tokennamespace)); }  protected String ByteArrayToString(byte[] inputArray) {     StringBuilder output = new StringBuilder("");     for (int i = 0; i < inputArray.Length; i++)     {     output.Append(inputArray[i].ToString("X2"));     }     return output.ToString(); } protected String SHA1Encrypt(String phrase) {     UTF8Encoding encoder = new UTF8Encoding();     SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();     byte[] hashedDataBytes = sha1Hasher.ComputeHash(encoder.GetBytes(phrase));     return ByteArrayToString(hashedDataBytes); } 
like image 93
Bron Davies Avatar answered Sep 21 '22 09:09

Bron Davies


I had the same problem. Instead of the custom token serializer I used a MessageInspector to add the correct UsernameToken in the BeforeSendRequest method. I then used a custom behavior to apply the fix.

The entire process is documented (with a demo project) in my blog post Supporting the WS-I Basic Profile Password Digest in a WCF client proxy. Alternatively, you can just read the PDF.

If you want to follow my progress through to the solution, you'll find it on StackOverflow titled, "Error in WCF client consuming Axis 2 web service with WS-Security UsernameToken PasswordDigest authentication scheme":

like image 34
Rebecca Avatar answered Sep 22 '22 09:09

Rebecca