# Tuesday, 17 April 2007

I've been wrestling for a while with how to deal with the fact that AzMan doesn't natively have a concept of denials.  I'd convinced myself that you could structure a hierarchy of grants such that you wouldn't really need an explicit denial, but I got a use case last week that proved that it really is necessary (without doing something REALLY horrible). 
I started with some suggesting from Cam, and modified it a bit into something that I think will work going forward.
The basic idea is that for every operation we want to add grants for, e.g. "GetAccounts", we also add a hidden operation called "!GetAccounts".  To keep them separated, we also offset their AzMan operation IDs by some arbitrary constant, say 100,000.  They when we do access checks, we actually have to call IAzClientContext.AccessCheck twice, once for the grant operations and once for the deny operations.  The results get evaluated such that we only grant access for an operation if the access check succeeds for the "grant" operation, AND doesn't succeed for the "deny" operation. 
WindowsIdentity identity = WindowsIdentity.GetCurrent();
IAzClientContext client = app.InitializeClientContextFromToken((ulong)identity.Token.ToInt64(), null);
object[] scopes = new object[] { (object)"" };
object[] grantOps = new object[] { (object)1, (object)2, (object)3, (object)4};
object[] denyOps = new object[] { (object)100001, (object)100002, 
     (object)100003, (object)100004 };
object[] grantResults = (object[])client.AccessCheck("check for grant", 
     scopes, grantOps, null, null, null, null, null);
object[] denyResults = (object[])client.AccessCheck("check for deny", 
     scopes, denyOps, null, null, null, null, null);
for (int i = 0; i < grantResults.Length; i++)
       if(((int)grantResults[i] == 0) && ((int)denyResults[i] != 0))

We'll hide all the details in the administration tool, so that all the user will see is radio buttons for Grant and Deny for each operations.

I'm pretty happy with this for a number of reasons

  • it gives us the functionality we need
  • it's easy to understand (no coder should have a hard time figuring out what "!GetAccounts" means)
  • all of the logic is localized into the admin tool and the CheckAccess method, so the interface to the client doesn't change
  • it's not too much additional semantics layered on top of AzMan, and we take full advantage of AzMan's performance this way