# 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))
            Console.WriteLine("Grant");
       else
            Console.WriteLine("Deny");
}

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
Tuesday, 17 April 2007 15:44:12 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  | 

This is a weird one...

A while back I changed our serializers from a reflection based model, to one that uses run-time code generation via the CodeDOM.  Performance is two orders of magnitude better, so happy happy.  However (there's always a however) a weird problem cropped up yesterday that I'm not quite sure what to do with. 

One of our applications has a case where they need to touch web.config for their ASP.NET applications while under load.  When they do that, they start getting InvalidCastExceptions from one or more of the cached, code generated serializers.  Strange.  Internally, after we generate the new serializer, we cache a delegate to the Serialize method for later retrieval.  It looks like that cache is getting boogered, so that the type cast exceptions ensue.  This is caused by serializers that are compiled against an assembly in one loader context, getting called by code that's running against the same assembly in a different loader context, hence the type case failure. 

I had assumed (probably a bad idea) that when you touch web.config, that the whole AppDomain running that application goes away.  It looks like that's not the case here.  If the AppDomain really went away, then the cache (a static Hashtable) would be cleared, and there wouldn't be a problem. 

To test the behavior, I wrapped the call to the cached serializer to catch InvalidCastExceptions, and in the catch block, clear the serializer cache so that they get regenerated.  That works fine, the serializers get rebuilt, and all is well.  However, I also put in a cap, so that if there was a problem, we wouldn't just keep recycling the cache over and over again.  On the 4th time the cache gets cleared, we give up, and just start throwing the InvalidCastExceptions.

The behavior that was reported back by the application team was that said fix worked fine until the 4th time they touch web.config, then it starts throwing exceptions.  Ah ha!  That means the AppDomain couldn't be going away, because the counter is stored in a static, and so should be resetting to 0 every time the application restarts. 

Unfortunately, just because I can characterize the problem doesn't mean I know what to do about it. :-)

Tuesday, 17 April 2007 12:45:10 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 

Thanks to some comments from Keith, I not only have the online version of Rhapsody working on Windows 2003 Server, but the desktop version as well. Yay! 

I installed 2K3 sp 2, then reinstalled the Rhapsody desktop player.  That still didn't work, until I set the compatibility mode on the shortcut to the desktop player to XP, and now it's shiny.

As good as the online player is, the desktop one is still more feature rich, so I'm excited to have it working again.

Tuesday, 17 April 2007 12:43:53 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, 13 April 2007

We've been building around WCF duplex contracts for a while now, as a way of limiting the number of threads active on our server.  The idea being since a duplex contract is really just a loosely coupled set of one-way operations, there's no thread blocking on the server side waiting for a response to be generated. 

It's been working well, but I'm starting to find that there are an awful lot of limitations engendered by using duplex contracts, mostly around the binding options you have.  It was very difficult to set up duplex contracts using issued token security, and in the end it turned out we couldn't set up such a binding through configuration, but were forced to resort to building the bindings in code.  Just recently, I discovered that you can't use transport level security with duplex contracts.  This makes sense, because a duplex contract involves an independent connection from the "server" back to the "client".  If you are using SSL for transport security, you would need certificates set up on the client, etc.  I'm not surprised that it doesn't work, but it's limiting.  Plus we have constant battles with the fact that processes tend to hold open the client side port that gets opened for the return calls back to the client.  Every time we run our integration tests, we have to remember to kill TestDriven.NET's hosting process, or on our next test run we get a failure because the client side port is in use already. 

All this has lead me to think that maybe we should go with standard request-response contracts until the server-side threading really shows itself to be a problem.  That's what I get for prematurely optimizing...

Indigo | Work
Friday, 13 April 2007 12:53:50 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 

Once again, Rhapsody has failed me.  Just this morning, I was happily listening away.  I closed my browser for a while, and just now came back to start up Rhapsody Online, since the desktop player totally doesn't work on Windows 2003 Server (at least on my box).  Now the online player tells me I'm running an incompatible operating system.  It's been working fine for months, but now it's incompatible.  Curses!  I supposed I'm going to have to start using a different box to play Rhapsody than the one I usually work on. 

I'm a big fan of Rhapsody's service, and have been steadily subscribing for years.  Unfortunately, their software (again and again) proves to be crap.

Friday, 13 April 2007 12:43:15 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  | 
# Tuesday, 10 April 2007

Orlando, here I come.  Not speaking this year, just basking in the goodness that is .NET 3.0, and learning as much as I can cram in my rapidly aging brain in a week.  There's still time, so register now if you haven't already...

 
Tuesday, 10 April 2007 16:54:33 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 
# Thursday, 05 April 2007

Donovan posted a link to the latest Channel 9 screencast on AzMan, in which Keith Brown talks about some of the new features coming up in the Longhorn Server version of AzMan.  It's a good video, and very encouraging to me, because it looks like the things the AzMan team has added for Longhorn are exactly the things I would have wanted. 

The programmatic interface is much simplified (thank you) and there's a new plugin model for the admin tool which allows you to work with custom principles such as ADAM principals from within the AzMan MMC snapin. 

Another interesting feature calls BizRule groups allows you to define ad hoc groups defined by script, which can then be associated with roles at runtime.  The example in the video created a group consisting of the current user's direct manager, and then assigning that group with an expense approver group.  This is a cool idea, but I'm reluctant to go back to defining application logic in VB script.  The one thing I really wish the team had done for Longhorn would be to create a managed interface for AzMan, and let us get away from COM (finally).  Since I'm writing the rest of my application in C#, I don't really want to have to maintain and deploy a bunch of COM based scripting files.  I'm not too concerned about the "COM overhead" involved with calling AzMan interfaces, but the scripting part is lame.

I'm looking forward to testing some of the new features, and trying out the performance improvements.

Thursday, 05 April 2007 10:32:08 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, 04 April 2007

Scott posted today about "Mindful Coding" or "Coding Mindfully", meaning "paying full attention to what you are doing while coding".  It's an easy thing to say, and a very hard thing to do.  We are so habitualized, as a society, to not pay full attention to much of anything that it's hard to really focus on what's happening right now.  I know that between email, questions, lunch, etc. it's difficult for me to focus on the code I'm writing at any given moment.  If nothing else, it's tempting to think about how the code you are writing now will interact with or influence the code you right tomorrow or next week, or the code your neighbor is writing that you have to integrate with.  Before you know it, you aren't really paying full attention to what you are writing.  Personally, this is where I get a lot of value out of refactoring. 

Refactoring allows you to fix the problems caused by wandering attention, if it's done often enough.  Several of the commenters on Scott's post also note that pair programming is a good remedy, and I agree.  When you are collaborating with someone else, you have to focus on the collaboration, which leads to mindfulness about what you are doing right now. 

Go forth and be mindful...

Wednesday, 04 April 2007 14:48:33 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  | 

Since there's not way to manage an explicit "Deny" in AzMan like there is with ACL's, that has some influence on the way in which we will have to define roles.  Let's say I have a group hierarchy like this...

  • Ray's Bakery
    • Admins
    • Bill Payers
    • Corporate Headquarters
      • Finance
      • Payroll

If we have the ability to deny, we might give rights to all operations to the top level "Ray's Bakery", and then deny rights to "Payroll" for example that we don't want that group to have, but are OK for "Finance".  It's relatively easy to understand, and has the advantage of being not very much work. 

Because of the way AzMan works, however, we have to work from the top of the hierarchy down, going from most restrictive to least restrictive.  In other words, we can only assign rights to the "Ray's Bakery" group that we want ALL users to have, then grant additional rights as we go down the tree.  We might want everyone in Finance and Payroll to be able to see balances, so those rights could be assigned at the "Corporate HQ" level, while rights to transfer money from one corporate account to another might be granted only to Finance, and rights to wire transfers only to Payroll.  This should also be pretty easy to understand, but it does require a bit more thinking about.  I think a good test tool will help make it clear to users who has what rights, so it shouldn't be too hard to follow. 

For the sake of clearing up any implementation details, what I'm really describing are hierarchical groups in ADAM, which are associated with AzMan roles, so when I say "assign rights at the Finance level", I mean that the group SID for the Finance group in ADAM will be associated with an AzMan role called something like RaysBakeryFinance, which is in turn associated with the operations or tasks that comprise wire transfers. 

Wednesday, 04 April 2007 13:51:28 (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  | 
# Monday, 26 March 2007

A very common banking scenario is one in which Customer Service Reps (CSRs) need to act on behalf of a given user to help them through problems.  This usually occurs when a customer calls a bank, and the CSR needs to essentially log into the online banking system "as" that customer, but without knowing that user's password. 

Once they are logged in, there are some things you'd like them NOT to be able to do, like create a new bill payment payee and send bill payments to it.  'Cause that's bad.

I'm trying to figure out how that would be modeled in AzMan, since as near as I can figure there's not such thing as an explicit "deny" in AzMan.  All rights are essentially additive, and if any of a user's roles includes a grant, access is granted.  At least that's the way it seems to behave, I could be wrong. 

In a perfect world, we'd like to be able to simply model "the CSR can do everything the user can, except...". 

The only way I can figure to make this work in AzMan right now is to create the CSR role with access to all operations except those on the deny list, then when the CSR logs in, do restrict the AccessCheck against AzMan to only the CSR role, by setting the IAzClientContext's RoleForAccessCheck property.  That way, only the CSR's rights are evaluated, even if they are assigned to other roles as well. 

Not ideal, but at least it's easy to understand...

Monday, 26 March 2007 14:40:32 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  |