getNonce() – a C# routine to generate the Nonce code for WS-Security

I created this code to generate a unique Nonce code. This relates back to this post about BizTalk calling a webservice with Basic Authenticiation.

Message Assignment is prior blog was updated to call C# business component:

<pre>
xmlDocSoapHeader.LoadXml(
   "<headers>" + 
   "<wsse:Security mustUnderstand=\"1\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + 
   "<wsse:UsernameToken wsu:Id=\"UsernameToken-E4E3CB1F68472DCF2914369675811859\">" +   
   "  <wsse:Username>" + strServiceBenchUserID + "</wsse:Username>" + 
   "  <wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">" + strServiceBenchPasswordFromSSO + "</wsse:Password>" + 
   "  <wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + Asurion.BusinessCompnents.getNonce() + "</wsse:Nonce>" +
   "  <wsu:Created>" + System.DateTime.UtcNow.ToString("s") + "Z" + "</wsu:Created>" + 
   "</wsse:UsernameToken>" +
   "</wsse:Security>" + 
   "</headers>"  
);

msgListNewCallRequest(WCF.OutboundCustomHeaders) = xmlDocSoapHeader.OuterXml;
</pre>

<pre>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Threading;

namespace Asurion
{
public static class BusinessCompnents
{

public static string getNonce()
{
// http://stackoverflow.com/questions/896901/wcf-adding-nonce-to-usernametoken
// Nonce explained here: http://weblog.west-wind.com/posts/2012/Nov/24/WCF-WSSecurity-and-WSE-Nonce-Authentication
// quote: Why is there a nonce? My first thought here was WTF? The username and password are there in clear text, what does the Nonce accomplish?
// The Nonce and created keys are are part of WSE Security specification and are meant to allow the server to detect and prevent replay attacks.
// The hashed nonce should be unique per request which the server can store and check for before running another request thus ensuring that
// a request is not replayed with exactly the same values.
//Random r = new Random();
Random r = RandomProvider.GetThreadRandom(); // better to get unique random number if called mulitple times
DateTime created = DateTime.Now;
string nonce = Convert.ToBase64String(Encoding.ASCII.GetBytes(SHA1Encrypt(created + r.Next().ToString())));
return nonce;
}

public static String SHA1Encrypt(String phrase)
{
UTF8Encoding encoder = new UTF8Encoding();
SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
byte[] hashedDataBytes = sha1Hasher.ComputeHash(encoder.GetBytes(phrase));
return ByteArrayToString(hashedDataBytes);
}

public static 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();
}

} // end class

public static class RandomProvider
{
// http://csharpindepth.com/Articles/Chapter12/Random.aspx
private static int seed = Environment.TickCount;

private static ThreadLocal randomWrapper = new ThreadLocal(() =>
new Random(Interlocked.Increment(ref seed))
);

public static Random GetThreadRandom()
{
return randomWrapper.Value;
}

} // end class
}

Uncategorized  

Leave a Reply