Requesting a Token from Access Control Service in C#
The AppFabric SDK V1.0 July Update SDK has a number of Access Control Service examples demonstrating the requesting of a token from the Access Control Service; however I find myself needing a small snippet to insert into other samples (e.g. Service Bus) just to craft a request token and get a token to Auth with SB. As such, I’m posting this “TokenFactory” code that I’ve been re-using. This is fundamentally the same functionality I’ve demonstrated in previous posts in PHP, Java, and Python.
namespace Microsoft.AccessControl.Client
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Net;
using System.Collections.Specialized;
public class TokenFactory
{
private static string acsHost = "accesscontrol.windows.net";
string serviceNamespace;
string issuerName;
string signingKey;
public TokenFactory(string serviceNamespace, string issuerName, string signingKey)
{
this.serviceNamespace = serviceNamespace;
this.issuerName = issuerName;
this.signingKey = signingKey;
}
public string CreateRequestToken()
{
return this.CreatRequestToken(new Dictionary<string, string>());
}
public string CreatRequestToken(Dictionary<string, string> claims)
{
// build the claims string
StringBuilder builder = new StringBuilder();
foreach (KeyValuePair<string, string> entry in claims)
{
builder.Append(entry.Key);
builder.Append('=');
builder.Append(entry.Value);
builder.Append('&');
}
// add the issuer name
builder.Append("Issuer=");
builder.Append(this.issuerName);
builder.Append('&');
// add the Audience
builder.Append("Audience=");
builder.Append(string.Format("https://{0}.{1}/WRAPv0.9/&", this.serviceNamespace, acsHost));
// add the expires on date
builder.Append("ExpiresOn=");
builder.Append(GetExpiresOn(20));
string signature = this.GenerateSignature(builder.ToString(), this.signingKey);
builder.Append("&HMACSHA256=");
builder.Append(signature);
return builder.ToString();
}
private string GenerateSignature(string unsignedToken, string signingKey)
{
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(signingKey));
byte[] locallyGeneratedSignatureInBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(unsignedToken));
string locallyGeneratedSignature = HttpUtility.UrlEncode(Convert.ToBase64String(locallyGeneratedSignatureInBytes));
return locallyGeneratedSignature;
}
private static ulong GetExpiresOn(double minutesFromNow)
{
TimeSpan expiresOnTimeSpan = TimeSpan.FromMinutes(minutesFromNow);
DateTime expiresDate = DateTime.UtcNow + expiresOnTimeSpan;
TimeSpan ts = expiresDate - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToUInt64(ts.TotalSeconds);
}
public string GetACSToken(string swt, string appliesTo)
{
// request a token from ACS
WebClient client = new WebClient();
client.BaseAddress = string.Format(@"https://{0}.{1}/", serviceNamespace, acsHost);
NameValueCollection values = new NameValueCollection();
values.Add("wrap_assertion_format", "SWT");
values.Add("wrap_assertion", swt);
values.Add("wrap_scope", appliesTo);
string response = null;
byte[] responseBytes = client.UploadValues("WRAPv0.9/", values);
response = Encoding.UTF8.GetString(responseBytes);
return HttpUtility.UrlDecode(response
.Split('&')
.Single(value => value.StartsWith("wrap_access_token=", StringComparison.OrdinalIgnoreCase))
.Split('=')[1]);
}
}
}
Here is a sample that uses the above to get a token from ACS. In this example I am using it specifically for Service Bus (hence “-sb” in the service namespace).
string serviceNamespace = "-"; string issuerName = "-"; string issuerKey = "-"; string baseAddress= string.Format("https://{0}.servicebus.windows.net/",serviceNamespace); string serviceAddress = string.Format("https://{0}.servicebus.windows.net/Text/GetText", serviceNamespace); TokenFactory tf = new TokenFactory(string.Format("{0}-sb",serviceNamespace), issuerName, issuerKey); string requestToken = tf.CreateRequestToken(); string returnToken = tf.GetACSToken(requestToken, baseAddress); Console.WriteLine(requestToken); Console.WriteLine(returnToken); Console.ReadLine();
Comments
- Anonymous
July 15, 2015
Is there a limit for the expireon value? Would it be possible to set the expireon value to 1 year or even non-expire? Thanks