Tuesday, July 14, 2009

Authorization Decisions - To Pre-Cache or Not to Pre-Cache, That is the Question

There is a common pattern of entitlements solutions which "require" authorization decisions to be pre-cached. What I mean by pre-cached is that at startup, all of the authorization decisions for all of the users for all of the resources are loaded into an in memory cache. This in-memory cache can be either local to the application or in a central location(s). There are a few reasons why to do this. The most obvious is performance - finding a entry in a HashMap should be very very fast (sub microsecond). The other reason I've heard is a high availability requirement. The in-memory cache is also backed-up onto disk (securely) so that in the case that the user can authenticate to the system but the systems that the PDP needed information from (PIPs) are not available, a decision can be returned.

To be fair, I'm not sure that this pattern is common across all customers, but I have seen it many times in Financial Services. This makes a lot of sense...very fast, very available authorization solution - fits well with things like front-office trading systems. So, what's the problem?

So there seems to be a couple of issues with this model.
  • Issue 1 - Update latency. If there is a change, how long does it take to get that change to be enforced in an application? Well, it depends on the scope of the change...for example, if a country changes the rules on what constitutes an adult or what constitutes legally married, then you may have to re-calculate the entire cache, and this can take a long time...hours, days? If its a more isolated change, like a privilege on an account, then the change is more isolated, but this touches on the second issue
  • Issue 2 - Cache consistency. Since this model is really for very fast, very available solutions, you're not going to have one instance of the cache. So, now you need to make sure that you've updated all the copies of these records, and probably need to make sure that its done transactionally...don't want different behavior based on which server in the cluster you hit. These first two issues can be solved with a really advanced distributed cache, but, the third issue and the one that seems to be the "killer" for pre-caching
  • Issue 3 - Context based authorization. Simply, "What if the authorization decision depends on some information I don't know until request time?"
Sorry, for the long preamble, but what I really wanted to talk about is this third issue of context based authorizations working in conjunction with pre-cached authorization data/entitlements. By definition, since it can be known before hand, the information is static - groups the user has, accounts the user has access to, organizations the user belongs etc. Maybe as an alternative to pre-caching, get this information once, at authentication time and store it....where?

The simple answer would be in the application session, but what I've done on a number of occasions, and has worked very nicely is stored it in side of the Subject as Principal objects. This approach covers most of the same HA use cases as pre-caching with disk back-up, except in this solution if those systems are down when you try to authenticate you won't be able to login - depending on how you set the JAAS control flags. Also, this lends itself very nicely, in the case of OES, to the creation of a custom authentication provider - basically a JAAS Login Module. Its purpose is to go fetch the static information and hold onto for the duration of the JAAS Subject. This is effectively the same as the session. This approach also adds "no time", since most authorization requirements don't include authentication. The business requirement is that transactions are processed quickly - sub ms - and they will be since all of the information is stored inside of the JAAS Subject, in memory. Also, the latency of change goes way down...the user gets new entitlements every time they log out.

Now that I've re-factored the static data into the JAAS Subject adding context based authorization is pretty straight forward. The new "policy combining algorithm" is in most cases allow if the static entitlements are granted and if there are context based authorization policies, those policies must evaluate to "grant". In OES, this can be done by:

DENY (//priv/all, //sgrp/foo/allusers, //app/foo) if not static_entitlements_granted()

In this model all of the logic is burried inside of the custom evaluation function, but I could have used attribute retrievers to parse the Principal objects in the Subject and exposed more of the logic into the policy.

DENY (//priv/all, //sgrp/foo/allusers, //app/foo) if not "ent1" in [user_entitlements]

So now that the existing rules are in place, just go add some new context based authorization

GRANT (//priv/read, //sgrp/foo/allusers, //app/foo/sensitive_materials) if authentication_method = "strong"

Context could include network, authentication method, user limits, historical patterns (OAAM), time of day etc.

In order for this type of model to be a true replacement for pre-caching, it assumes that the underlying authorization engine is fast...that it can do authorizations in the sub-ms range. I can't disclose any confidential information in this forum, so you'll have to draw your own conclusions about the performance of OES. I can say I've built solutions like this with a number of customers, and they've been very pleased with the result.

No comments: