# Thursday, 15 February 2007

I just finished a couple of pretty interesting books...


The Devil's Teeth: A True Story of Obsession and Survival Among America's Great White Sharks

The Devil's Teeth is all about a journalist who gets involved with the biologists studying great white sharks in the Farallones, islands about 20 miles due West of San Francisco.  It's an interesting portrait, not only of the harsh reality of life for a shark, but of the harsh reality of the people who live to study them.  Not an easy job.  Unfortunately, the author's obsession with the sharks leads to her violation of the rules of the study, which ultimately result in the lead biologist losing his job.  I notice that part gets downplayed significantly.  Other than that, it's a very well written account.


Adrift: Seventy-six Days Lost at Sea

 Adrift is about the truly remarkable adventure of Steven Callahan, who survived in an inflatable life raft for 76 days in the North Atlantic.  Only one other man is recorded as having survived at see that long solo.  Callahan's sailboat was sunk (he thinks by running into a whale) while only a few days out from the Canary Islands, headed for the Caribbean.  Using only the tools in his raft and survival kit, he manages to provide himself with enough food and water to make it all the way to Guadeloupe, where he was rescued by some fishermen.  Callahan showed some pretty amazing competence and ingenuity, which makes this a very interesting read.

Thursday, 15 February 2007 10:30:00 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, 13 February 2007

One obvious thing you might want to do with an authorization system is to get a list of all the operations a given user is granted access to.  This is particularly useful for building up UI elements such as navigation menus.  Nobody likes navigation links that result in Access Denied errors, so it's best to only include in your navigation hierarchy those pages a user can actually execute successfully. 

Here's an example of how to do this with ADAM and AzMan.  It's a little weird, since you have to switch back and forth between an operation's string name, and its integer ID, hence the lookup dictionaries. 


   1:  public string[] AvailableOperations(string userId)
   2:  {
   3:      IAuthenticationStore authenticate = AuthenticationStoreFactory.Create();
   4:      UserInfo userInfo = authenticate.LookupUser(userId);
   5:      IAzClientContext2 client = setupClientContext(userId, userInfo);
   7:      try
   8:      {
   9:          Dictionary<string, int> opToId = 
  10:      new Dictionary<string, int>(azApp.Operations.Count);
  11:          Dictionary<int, string> idToOp =
  12:      new Dictionary<int, string>(azApp.Operations.Count);
  13:          foreach (IAzOperation op in azApp.Operations)
  14:          {
  15:              opToId.Add(op.Name, op.OperationID);
  16:              idToOp.Add(op.OperationID, op.Name);
  17:              Marshal.ReleaseComObject(op);
  18:          }
  20:          List<string> availableOps = new List<string>();
  22:          object[] scope = new object[] { (object)"" };
  24:          object[] operations = new object[idToOp.Count];
  25:          int i = 0;
  26:          try
  27:          {
  28:              foreach (int opId in idToOp.Keys)
  29:              {
  30:                  operations[i] = (object)opId;
  31:                  i++;
  32:              }
  33:          }
  34:          catch (COMException ex)
  35:          {
  36:              throw new InvalidOperationException("Failed", ex);
  37:          }
  38:          object[] results = (object[])client.AccessCheck("User authentication", scope,
  39:               operations, null, null, null, null, null);
  41:          for (int j = 0; j < results.Length; j++)
  42:          {
  43:              if ((int)results[j] == 0)
  44:              {
  45:                  availableOps.Add(idToOp[(int)operations[j]]);
  46:              }
  47:          }
  48:          return availableOps.ToArray();            
  49:      }
  50:      finally
  51:      {
  52:          Marshal.ReleaseComObject(client);
  53:      }
  55:  }

I talked about the LookupUser and setupClientContext methods yesterday.  This method returns a handy list of all the operations that the given user can access.  In practice, you probably want to cache the results, although so far it seems to perform very well.  It might prove particularly valuable to cache the ID->Name and Name->ID lookup tables, as they aren't likely to change very often.

Tuesday, 13 February 2007 09:34:22 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, 12 February 2007

I'm working on an authentication and authorization solution using ADAM and AzMan, and starting to write the code to integrate the two.  For those who might be looking to do such a thing, here's an example.  This method takes two pieces of information, a user's ID (which in this case corresponds to a userPrincipalName in ADAM), and the name of the operation to check access to...


   1:  public bool CheckAccess(string operation, string userId)
   2:  {
   3:      log.Verbose("Starting CheckAccess");
   4:      bool result = false;
   5:      IAuthenticationStore authenticate = AuthenticationStoreFactory.Create();
   6:      UserInfo userInfo = authenticate.LookupUser(userId);
   7:      log.Verbose("LookupUser {0} succeeded", userId);
   8:      IAzClientContext2 client = setupClientContext(userId, userInfo);
  10:      object[] scope = new object[] {(object)""};
  12:      object[] operations = null;
  13:      try
  14:      {
  15:          IAzOperation op = azApp.OpenOperation(operation, null);
  16:          operations = new object[] { (Int32)op.OperationID };
  17:          Marshal.ReleaseComObject(op);
  18:      }
  19:      catch (COMException ex)
  20:      {
  21:          log.Error("No such operation: {0}", operation);
  22:          if (ex.ErrorCode == AzManConstants.INT_NO_SUCH_OBJECT)
  23:              throw new UnknownOperationException(operation);
  24:          else
  25:              throw;
  26:      }
  27:      object[] results = (object[])client.AccessCheck("User authentication", scope, 
  28:                      operations, null, null, null, null, null);
  29:      if ((int)results[0] == 0)
  30:      {
  31:          result = true;
  32:          log.Verbose("Access granted to {0} for user {1}", operation, userId);
  33:      }
  34:      else
  35:      {
  36:          log.Verbose("Access denied to {0} for user {1}", operation, userId);
  37:      }
  38:      Marshal.ReleaseComObject(client);
  39:      log.Verbose("Leaving CheckAccess");
  40:      return result;
  41:  }

There are a couple things here that need explaining.  The LookupUser method finds the specified user in ADAM by searching for the userPrincipalName using the DirectorySearcher class.  It returns a structure containing the user's SID, all of the SIDs for groups they belong to, and some other stuff specific to our application.  There's a great example of how to retrieve this info in the paper Developing Applications Using Windows Authorization Manager, available on MSDN. 

The other method of interest here is the setupClientContext method, which looks like this...


   1:  private IAzClientContext2 setupClientContext(string userId, UserInfo userInfo)
   2:  {
   3:      log.Verbose("Setting up client context");
   4:      IAzClientContext2 client = azApp.InitializeClientContext2(userId, null);
   5:      log.Verbose("User sid = {0}", userInfo.SecurityId);
   6:      object[] userSids = null;
   7:      if (userInfo.GroupIds != null)
   8:      {
   9:          userSids = new object[userInfo.GroupIds.Count + 1];
  10:          userSids[0] = userInfo.SecurityId;
  11:          int i = 1;
  12:          foreach (string sid in userInfo.GroupIds)
  13:          {
  14:              log.Verbose("Adding group sid {0}", sid);
  15:              userSids[i] = sid;
  16:              i++;
  17:          }
  18:      }
  19:      else
  20:      {
  21:          log.Verbose("No group IDs returned, using only user SID");
  22:          userSids = new object[1];
  23:          userSids[0] = (object)userInfo.SecurityId;
  24:      }
  25:      client.AddStringSids(userSids);
  26:      log.Verbose("Finished setting up client context");
  27:      return client;
  28:  }

This is the part that only works on Windows 2003 Server or Vista. On XP, the IAzClientContext2 interface is not available, and so you can't add the additional group SIDs to make this work.

The end result is that the user's role membership will be used by AzMan to determine whether or not the specified user can access the specified operation, and return a boolean value back to the caller.  Easy to use by the client, and as far as I can tell, pretty performant.

Monday, 12 February 2007 11:21:02 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, 31 January 2007

If you are working with AzMan at all, the best resource I've found so far that you'll want to check out is Developing Applications Using Windows Authorization Manager from MSDN.  It includes a very comprehensive set of info on working with AzMan using Windows, ADAM, or custom principals, on using AzMan from ASP.NET, and general info on authorization strategy and policy.

There are lots of code samples included in the document, including code for doing access checks using ADAM principals, and some for writing AzMan "BizRules" in managed code.

Good stuff.

AzMan | Work
Wednesday, 31 January 2007 15:05:23 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, 29 January 2007

Yesterday we had a party for the 10th Anniversary of the CERT program here in Hillsboro.  We had many more people than I had expected show up, to whom we provided free spiffs, literature on disaster preparedness, and lot's of nifty door prizes including tools, hats, etc.  Plus safety related games for the kids.  And there was cake.

A good time was had by all.  Here's to 10 more...

Monday, 29 January 2007 15:08:44 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, 25 January 2007

Not so good. 

Update:  I did get WMP to work, after installing the "Media Services" for 2003 server from the "Add Windows Components" dialog.  Still no go with Rhapsody.  Interestingly enough, QuickTime doesn't work either...

I've recently had to upgrade my development box to Windows 2003 Server, because some of the work I'm doing with ADAM and AzMan requires 2003 or Vista (and I'm not quite ready to go there, not is our IT department).  I can't get the Rhapsody client to install at all on 2003 server.  I suspect it has something to do with the fact that there's no Windows Media Player installed.  There doesn't seem to be a Windows Media Player for 2003 Server, which probably isn't unreasonable.  The Rhapsody client install fails while trying to set up some DRM stuff, which is what makes me suspect WMP. 

Despite that, the new web based Rhapsody client works just fine in FireFox, so I'll have to limp along with that once again.


Thursday, 25 January 2007 10:04:20 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [6]  | 
# Wednesday, 24 January 2007

I'll post some code later on, but I wanted to make some quick points about integrating ADAM and AzMan.  I'm in the midst of building an authentication/authorization system using the two technologies together, and have some across some stumbling blocks.  There's not much documentation, particularly around AzMan, and the COM interfaces for AzMan can be a bit cumbersome.

  • Storing users in ADAM and authorizing them using ADAM requires Windows 2003 Server or Vista.  There's no decent way to make this work on Windows XP.  The necessary AzMan interface, IAzClientContext2, doesn't exist on XP.  It's required for using a collection of user and group SIDs from ADAM to do access checks against AzMan.  I'll post some code later...
    • IAzClientContext2 is also available on Vista, so Vista is also a viable dev platform.
  • There are some confusing interactions between the AzMan UI and the programmatic API.  If you create a Role in the AzMan UI, but don't create a RoleAssignment, the programmatic call to IAzApplication2.OpenRole will fail.  If you create the role assignment, but don't actually assign any users or groups to it, OpenRole succeeds.  Conversely, if you call the programmatic IAzApplication2.CreateRole method and assign operations and users to the role in code, the RoleAssignment shows up in the UI, but not the Role itself. 
  • If you assign an ADAM user to be a member of an AzMan group, it won't show up in the AzMan UI, but if you assign them directly to a Role, the ADAM user's SID will show up (as "unknown SID") under the RoleAssignment.  Either way, the call to AccessCheck works correctly.
  • You must pass the complete list of group SIDs from ADAM, but fetching the user's "tokenGroups" property.  Don't use "memberOf" because it doesn't take into account groups which belong to other groups.

More detail to come...

Wednesday, 24 January 2007 10:08:12 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  | 
# Thursday, 04 January 2007

I've read a bunch of these over the last few weeks, and thought perhaps I could duck, but Scott tagged me today, so I guess I should come clean.  Most of these arne't exactly secret, but you may not have heard me hold forth on them before :-)

  • My degree (a B.A.) is in East Asian Studies.  I spent my 4 years studying up on Buddhism, Japanese Art, and Chinese Communism.  My work study job was retrieving term papers off of floppies that had beer spilled on them, one precious sector at a time.  The first Computer Science class I ever took was at PCC after working at Intel for several years.  C++ I think it was.  Or possibly data structures.  I dropped out of a class on assembler, 'cause it was boring. 
  • I love trashy food.  I was raised on 70's hippy vegetarian food, and to this day I have a deep and abiding love of chicken fried steak, chipped beef on toast, and fried SPAM. 
  • I have a "simian crease" on my right hand.  Most people have two or three lines running horizontally across their palm (heart line, life line, etc).  I only have one the runs all the way across.  Common among chimpanzees and people with Down syndrome, less so among others.
  • On weekends, I tend to dress like a Viking.  My whole family are long-term participants in the Society for Creative Anochronism.  I used to dress up in armor and hit people with (actually mostly be hit with) wooden swords.  I gave that part up since I'm not 18 anymore, and it hurts.
  • My very first job was as an apprentice house painter.  I mostly dug ditches and drove ladders around Seattle for $6/hr.  I started the job by lowering the bottom of the boss' dirt floored basement by about 6 feet.  8 hour days of digging dirt into 5 gallon buckets, and hauling them two at a time up a flight of stairs.  I gained about 10 pounds of pure biceps. 

Not exactly shocking revalations, I admit.  Not compared to Scott's fashion obsession anyway.  I knew he was a snappy dresser, but...

I can't think of too many people I know have haven't already been tagged, so I'm not sure I'll make 5.  I nominate Jason, Stuart Celarier, John Batdorf,  Jeff B., and Don Smith.

Thursday, 04 January 2007 15:04:31 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, 18 December 2006

Late last week, Rhapsody finally released a new desktop client that doesn't crash in the presence of IE7.  Hurray!  I've been gimping along with the web-based client, which is cool, but not nearly as full-featured as the desktop version.  I've been running it for several days now, and not one crash, so I'm hopeful at this point.  Just in time to listen to all that Christmas music that I'd never shell out to buy full time...

Update: I may have spoken too soon.  It works fine on my desktop at work, but crashes constantly on my laptop at home.  Sigh.

Monday, 18 December 2006 12:41:57 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 

Since time immemorial (or since Marconi, anyhow) those wishing to be licensed as Radio Amateurs in the US have had to pass a Morse code test.  Relatively recently, there has been an entry level license class (Technician) that doesn't require passing the code test, but which (therefore) comes with no privileges on the HF bands (for long-distance communications). 

The code requirement has long been a hotly contested issue among amateurs.  Many have maintained that learning Morse code meant that you were "serious" about amateur radio, and would therefore be a skilled and considerate radio operator.  The problem is, since so few people actually use Morse code on the radio anymore, it has become (in my opinion, and that of many others) an artificial hoop that had to be jumped through before you could get into the high priesthood of amateur radio.  Most of the General or Extra class licensees I've talked to have never ditted or dahed once since passing the test. 

What this means for me personally is that I can finally hope to upgrade to a General class license.  I've studied all the material, and am pretty sure that I could pass the exam, but given the way the rest of my life works, I've been unable (or unwilling) to devote the time it would take to learn Morse code, so I've never taken the test. 

Of course, if I did pass the test, I'd want to get an HF-capable radio, but that's a whole different problem. :-)

CERT | Radio
Monday, 18 December 2006 12:38:55 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  |