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