WCF: Adding Nonce to UsernameToken

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);
}

Leave a Comment