A View Inside My Head

Jason's Random Thoughts of Interest

NAVIGATION - SEARCH

Namespacing in JavaScript

Consider this code:

var Configuration = function (model) { 
   this.name = ko.observable(model.Name); 
   this.description = ko.observable(model.Description); 
   this.enabled = ko.observable(model.Enabled || false); 
}; 

Because this was defined outside of the scope of a function, that “Configuration” variable gets promoted to the global object.  In web browsers, that means that it gets appended to the window object as a property (window.Configuration = function(model)…). 

That’s just the nature of global objects in JavaScript.  But, instead of creating a bunch of new custom properties on window, it’s common to wrap all of your app’s global objects in a namespace so that window only gets polluted by one new property (especially when creating a reusable library of objects).

var MyNS = MyNS || {};         

///        
/// Configuration        
///        
MyNS.Configuration = function (model) {            
   this.name = ko.observable(model.Name);            
   this.description = ko.observable(model.Description);            
   this.enabled = ko.observable(model.Enabled || false);        
};

Now, in reality, there’s no such thing as a namespace in JavaScript.  What this is actually doing is creating a new global object called “MyNS” if it doesn’t already exist, and then adding the new objects as properties of MyNS.

If you need a sub-namespace, just create another empty object in MyNS:

var MyNS = MyNS || {};        
MyNS.Entities = MyNS.Entities || {};

Now the namespace and its members can be extracted into their own .js file(s) and included when needed.

But, thinking about a shared usage, someone may want to instantiate a Configuration object without having a model to pass in.  In that case, the code above will blow up because there are no properties on undefined (i.e., undefined.Name would result in an error).  This can be fixed by initializing model itself to an empty object if it comes in undefined:

MyNS.Configuration = function (model) {            
   model = model || {};            
   this.name = ko.observable(model.Name);            
   this.description = ko.observable(model.Description);            
   this.enabled = ko.observable(model.Enabled || false);        
};

But, wait – there’s no .Name property of an empty object.  How does this work if model = {} ?

All object in JavaScript are actually associative arrays (think dictionary, property bag, etc).  So, model.Name is exactly the same as model["Name"].  If that named element doesn’t exist in the collection, then the value will be returned as undefined, which is fine for initializing a ko.observable.

Additional Suggestion

Jason Karns (@jasonkarns) writes:

I like to use a micro-library, extend.js, to make the namespace initialization a bit cleaner. https://github.com/searls/extend.js It's a tiny library that does, admittedly, very little.

When breaking components across multiple files, ensuring that the namespace (and sub-namespace) is already created becomes annoying. You either end up declaring a very specific file load order, or copying boilerplate namespace code at the top of every file.

extend.js let's you define the namespace you want as a string (to any depth) and it will create it if it doesn't exist, or merge if it does exist. Small utility, but much cleaner than boilerplate code.

Knave 21 (Blackjack): The Fairness of Random Cards

Blackjack is one of my favorite games in the casino.  I'm a casual player, and certainly not an advantage player by any means.  To help me drill basic strategy, especially for things like soft hands and splits, I decided to write a version of Blackjack for Windows 8 and make it a game that *I* would like to play.  Since I'm not a high-roller, I also wanted to simulate the bankroll that casual players might use in an actual casino: $500 buy in at a $10 minimum table.

Thus, Knave 21 (soon to be renamed Knave Blackjack) was born after a couple of hundred hours of work in the evenings and weekends (the version in the Windows Store represents the third rewrite, and a version currently in development has undergone major refactoring recently as I prepare to add more features in the near future).  It's been a labor of love, and I hope that the attention to detail reveals that.  I've received a lot of positive feedback, and, recently, some negative feedback as well (which prompted this blog post).

One thing that every card game author likely struggles with is how to randomize the card selection so that it's fair to the player.  Knave 21 has the concept of a shoe, which is 2-6 decks of cards that are shuffled together.  It penetrates much deeper than a real casino (the reshuffle automatically occurs when 12 cards remain in the shoe), but the randomness of the deck is very dependent on whatever pseudo-random number generator can be coded in JavaScript.

Instead of relying on JavaScript's Math.random() function, Knave 21 utilizes the Alea library by Johannes Baagøe to provide a better distribution of random numbers.  And, since the shoe is serialized and saved to roaming storage (so you can resume a game on another computer), I didn't want to pre-shuffle the shoe.  Instead, a random card is selected and removed from the shoe upon demand.  If someone were to view the roaming state data, they could see what cards were left in the shoe, but not what the next card would be.  

More importantly (and in response to some recent negative feedback), the game doesn't care what cards have been played or how much you are betting when determining the next card - it simply picks a random number and that's the card that is drawn.  

I'm very concerned about Knave 21's reputation, especially since I have paying customers now that the app is listed in the Windows Store.  In the interest of openness, the code for the shoe implementation follows.  Note the "nextCard" function for the RNG implementation.

Knave.Shoe = (function (Alea, undefined) {

    var shoe = function (decks) {
        this.cards = [];

        for (var d = 0; d < decks; d++) {
            for (var s = 0; s < 4; s++) {
                for (var r = 0; r < 13; r++) {
                    this.cards.push(new Knave.Card("A23456789TJQK".charAt(r), "HDCS".charAt(s), true));
                }
            }
        }
    };

    shoe.prototype = {
        nextCard: function (facedown) {
            var random = new Alea();
            var index = random.uint32() % this.cards.length;
            
            var c = this.cards.splice(index, 1);

            if (c.length === 0)
                return undefined;

            var ret = c[0];

            if (facedown !== undefined)
                ret.facedown(facedown);

            return ret;
        },
        remaining: function () {
            return this.cards.length;
        }
    }

    return shoe;
})(Alea);

 

A View Inside My Head | Windows Azure platform AppFabric Access Control: Obtaining Tokens

A View Inside My Head

Jason's Random Thoughts of Interest

NAVIGATION - SEARCH

Windows Azure platform AppFabric Access Control: Obtaining Tokens

In this, the third part of a series of articles examining Windows Azure platform AppFabric Access Control (Part 1, Part2), I will continue developing the [somewhat contrived] nightclub web service scenario and demonstrate how to obtain a token from ACS that can be used to call into a Bartender web service.

A Quick Review

Our distributed nightclub system has four major components: A Customer application coupled with some external identity management system, a Bartender web service, and ACS, which acts as our nightclub’s Bouncer.

A Customer application ultimately represents a user that wishes to order a drink from the Bartender web service.  The Bartender web service must not serve drinks to underage patrons, so it needs to know the user’s age (this is known as a “claim”).  The nightclub has no interest in maintaining a comprehensive list of customers and their ages, so instead, a Bouncer ensures that the user’s claimed age comes from a trusted source (this is known as an “issuer”).  If the claim’s source can be verified, the Bouncer will give the customer a token containing its own set of claims that the Bartender web service will recognize.  In the end, the Bartender doesn’t have to concern itself with all of the possible issuers – it only needs to recognize a single token generated by the Bouncer (ACS).

separateservice_issuer

 

Anatomy of a Token Request

ACS uses a subset of the OAuth Web Resource Authorization Protocol (WRAP) to request tokens.  The tokens themselves use the Simple Web Token (SWT) format.  The latest specification documents for both WRAP and SWT can be found in the Files section of the “OAuth WRAP WG” Google Group: http://groups.google.com/group/oauth-wrap-wg/files

The power of ACS derives from the simplicity of WRAP/SWT.  All of the token requests are performed as regular HTTP POSTs, and the response is a URL Encoded string of name/value pairs (one of those being the token itself).  Even if your Issuer (Identity Management System) does not natively know how to request a token from ACS, which is very likely, then it is easy to either build this into the application itself, or write a small service to perform this work. 

At the HTTP protocol level, a token request may resemble:

REQUEST:

POST https://jasondemo.accesscontrol.windows.net/WRAPv0.9/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: jasondemo.accesscontrol.windows.net
Content-Length: 155
Expect: 100-continue

wrap_name=Ohio&wrap_password=LVMjImkJjIBDrJHbTzyrioeajIFpV27tW2uTuCCOYFY%3d
&wrap_scope=http%3a%2f%2fmyserver.domain%2fBartender&DOB=1979-05-25T00%3a00%3a00

 

RESPONSE:

HTTP/1.1 200 OK
Content-Length: 315
Content-Type: application/x-www-form-urlencoded
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: ca165b72-5d9f-4196-9272-1b80c8c3e02a
Date: Mon, 22 Mar 2010 13:26:44 GMT

wrap_access_token=Birthdate%3d1979-05-25T00%253a00%253a00%26Issuer%3dhttps%253a%252f%252f
jasondemo.accesscontrol.windows.net%252f%26Audience%3dhttp%253a%252f%252fmyserver.domain%
252fBartender%26ExpiresOn%3d1269307605%26HMACSHA256%3deSgT1Gwx3H6owK8hBR82ixG0DRTgM2osI3v
7NdJLQwY%253d&wrap_access_token_expires_in=43200

 

The response displayed here contains two name/value pairs: wrap_access_token and wrap_access_token_expires_in.  If the token request was invalid, then a HTTP 401 status would have been returned instead of a 200.

Notice that “wrap_access_token_expires_in” contains the value 43200, which is the number of seconds that we defined in the Token Lifetime field of the “BouncerPolicy” token policy (in Part 2).  This value is provided as a convenience to indicate how long the token will be valid.  Taking a cue from systems that use lease lifetimes, like DHCP, it might be a good practice to acquire another token at 50% of the Token Lifetime (21600 seconds in this case, or 6 hours). 

As the name suggests, “wrap_access_token” contains the SWT token itself.  This is a URL Encoded set of name/value pairs that also includes a HMACSHA256 signature to prevent the token from being tampered with.  This token does not need to be parsed by the client application; it can be treated as a magic string.  However, there is nothing special about its contents:

Birthdate=1979-05-25T00%3a00%3a00 &Issuer=https%3a%2f%2fjasondemo.accesscontrol.windows.net%2f &Audience=http%3a%2f%2fmyserver.domain%2fBartender &ExpiresOn=1269309326 &HMACSHA256=NLmcGYITc8aWvhNp6Ge54TGJxhJCVX4Q67DDLBKoIy4%3d

 

“Birthdate” is the result of the Passthrough Claim Mapping (Part 2) that took the inbound claim called “DOB” and mapped it to this outbound claim called “Birthdate”.  ACS has no idea that this is a date – it just knows that it’s a string of characters that will be understood by the destination.  The other claims that are present in this SWT token (Issuer, Audience, ExpiresOn, and HMACSHA256) are all system claim types that are reserved for use by SWT. 

Note the value of “Issuer” in this token.  In our Request, the stated Issuer was “Ohio”, which was a trusted Issuer that we defined when configuring the Service Namespace using AcmBrowser.  The Issuer of this SWT token is now the Service Namespace.  Our Bartender web service has no direct trust with the Ohio Issuer, but it will trust tokens signed by the Service Namespace (which trusts the Ohio Issuer).  Just as ACS can trust multiple Issuers, it’s also possible that the Bartender web service could trust multiple ACS Issuers (maintaining a symmetric key for each one to verify the HMACSHA256 signature).  There is a lot of flexibility in how ACS can be incorporated into your own system’s architecture.

Implementation

Because the “Ohio” issuer was created in ACS using a Symmetric 256-bit key, we have two choices for how to use this key in order to request a token from ACS.  We could send the key itself in plaintext, sort of like a password (in fact, this uses a WRAP profile that is intended for username/password authentication).  Alternatively, we could create a SWT of our own, using the key to sign it, and then send that token to ACS as part of the token request.

A simple WRAP request that provides the Issuer’s name and password (symmetric key) in plaintext would contain the following name/value pairs:

  • wrap_name (Issuer Name, as defined in the Issuer definition in ACS)
  • wrap_password (Current Key, as defined in the Issuer definition in ACS)
  • wrap_scope (Applies To, as defined in the Scope definition)
  • additional claims (will be processed by the defined Scope Rules for claim mapping)

private static string RequestTokenFromACS_usingPassword(DateTime dob) { var values = new NameValueCollection(); values.Add("wrap_name", "Ohio"); values.Add("wrap_password", "LVMjImkJjIBDrJHbTzyrioeajIFpV27tW2uTuCCOYFY="); values.Add("wrap_scope", "http://myserver.domain/Bartender"); values.Add("DOB", dob.ToString("s")); var client = new WebClient { BaseAddress = "https://jasondemo.accesscontrol.windows.net" }; return Encoding.UTF8.GetString(client.UploadValues("WRAPv0.9", "POST", values)); }


Using a SWT within a WRAP request is just as simple, but the difficulty is in creating the SWT itself.  The WRAP request would contain the following name/value pairs:

  • wrap_assertion_format (SWT in this case)
  • wrap_assertion (the SWT token that we generate and sign using the Current Key)
  • wrap_scope (Applies To, as defined in the Scope definition)

The SWT token itself would contain the following name/value pairs:

  • Issuer (Issuer Name, as defined in the Issuer definition in ACS)
  • Audience (STS Endpoint, as listed on the Service Namespace overview page)
  • ExpiresOn (integer containing the number of seconds after the Epoch date of January 1, 1970 00:00 UTC that the token will expire)
  • additional claims (will be processed by the defined Scope Rules for claim mapping)
  • HMACSHA256 (URL Encoded Base64 signature of the unsigned token)

private static string RequestTokenFromACS_usingSWT(DateTime dob) { string requestToken = GetRequestToken(dob); var values = new NameValueCollection(); values.Add("wrap_assertion_format", "SWT"); values.Add("wrap_assertion", requestToken); values.Add("wrap_scope", "http://myserver.domain/Bartender"); var client = new WebClient { BaseAddress = "https://jasondemo.accesscontrol.windows.net" }; return Encoding.UTF8.GetString(client.UploadValues("WRAPv0.9", "POST", values)); } private static string GetRequestToken(DateTime dob) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("DOB={0}&", dob.ToString("s")); sb.Append("Issuer=Ohio&"); sb.Append("Audience=https://jasondemo.accesscontrol.windows.net/WRAPv0.9&"); sb.AppendFormat("ExpiresOn={0:0}", (DateTime.UtcNow.AddMinutes(10) - new DateTime(1970, 1, 1)).TotalSeconds); return AddSignature(sb.ToString()); } private static string AddSignature(string unsignedToken) { HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String("LVMjImkJjIBDrJHbTzyrioeajIFpV27tW2uTuCCOYFY=")); var sig = hmac.ComputeHash(Encoding.ASCII.GetBytes(unsignedToken)); string signedToken = String.Format("{0}&HMACSHA256={1}",  unsignedToken,  HttpUtility.UrlEncode(Convert.ToBase64String(sig))); return signedToken; }

Where to Execute this Code

The code to request a token can easily be implemented within an application that uses that token to call into a protected resource.  In the nightclub example, this code could be incorporated right into the Customer application.  However, this would mean that the claim (Birthdate) would originate from the application itself.  It also means that the application would need to have access to the Issuer key, making it possible for a nefarious user to obtain the key and bypass the application to directly access the protected resource.  These may not be concerns for your specific system, though.

A better solution for the nightclub example, which tries to mimic the real-life State ID system, would be to create a service for each Issuer that their Customer applications call into.  This service would then be able to obtain claim information from a source of authority (such as a LDAP directory), obtain a token from ACS, and then return that token to the Customer application.  The Customer application would never communicate with ACS directly, so there would be no reason for the application to have the Issuer key (making it harder for that nefarious user to discover the key).

From Here

This article demonstrated how to obtain a token from ACS.  In the next article, I will show how to use this token in order to access a protected resource (such as our Bartender web service) and how to validate a token when a protected resource receives one. 

(Continued in Part 4)

Further Reading: