JACC condensed

It’s incredibly hard to understand the JACC specification (at least for me). Here it is in pragmatic, condensed terms. Clever insight is courtesy of Ron Monzillo; fumbling incompetence is mine alone.You write a JACC implementation when you want to…

It’s incredibly hard to understand the JACC specification (at least for me). Here it is in pragmatic, condensed terms. Clever insight is courtesy of Ron Monzillo; fumbling incompetence is mine alone.

You write a JACC implementation when you want to use a third-party authorization system. There are other reasons, too. JACC expresses Java EE role-based security mechanisms in terms of java.security.Policy and provides the means to carve the authorization rulebase up into subsets that pertain to individual Java EE modules. It also provides the means to determine that a Permission is explicitly excluded (java.security.Policy can only indicate that it is not granted, which could be because it is excluded or simply not handled).

A JACC implementation typically consists of a Policy subclass, a PolicyConfiguration implementation, and a PolicyConfigurationFactory subclass. It’s possible to write just the last two and to have them puke out policy files that the regular old com.sun.security.provider.PolicyFile class installed in every JVM by default can parse, but usually you write all three if you have cause to write a JACC implementation at all.

You write a PolicyConfiguration implementation to set up and produce your rulebase for a given Java EE module. (JACC calls your rulebase a “policy context”.) By “rulebase”, I mean (usually) the Permissions, granted and excluded, that define your authorization rules. Your rulebase might be a collection of files, a HashMap, a table in a database, etc. etc. The main thing is that your rulebase needs to be accessible by your java.security.Policy subclass (or more correctly by whatever Policy is installed in the system, reachable from the static Policy#getPolicy() method).

You write a PolicyConfigurationFactory subclass to produce instances of your PolicyConfiguration.

Your Policy subclass will be used in some fashion by the JVM to evaluate all permission checks, not just by your Java EE module, so it needs to be able to check things like AWTPermissions, RuntimePermissions, SecurityPermissions and the like (i.e. things you don’t usually think of when you think about Java EE). Typically you’ll delegate some of these calls to the Policy that’s installed already.

(For some reason, JACC refers to your Policy subclass as a “policy provider”. Every time you see “policy provider”, think java.security.Policy instead.)

Your PolicyConfiguration class needs to be thread-safe. It has a very well-defined lifecycle, but the salient points are that it is initially in a state where it is set up (“open”), then it is locked down via its commit() method (“in service”) which has the extremely important side effect of conceptually producing the rulebase (“policy context”) that was just configured and making it available for consultation. Only after its rulebase (policy context) is so produced (placed in service) may your Policy subclass consult it.

Once your rulebase has been created and placed in service by virtue of your PolicyConfiguration‘s having been committed, your Policy subclass will use it to render authorization decisions. All security calls will eventually flow through the Policy#implies(ProtectionDomain, Permission) method. Your implementation of this method must consult your rulebase, but only the proper subset of your rulebase. Which subset? The one that is in effect for the current Java EE module that’s making the current authorization check.

To determine which subset of your rulebase to consider, your Policy subclass calls PolicyContext#getContextID() to obtain a key. This key identifies effectively which Java EE module is making the security call, and hence which subset of your rulebase your Policy implementation needs to check during its implies(ProtectionDomain, Permission) call.

So your Policy subclass, armed with this key, looks up the appropriate rulebase subset (the appropriate policy context). Typically this is either a HashMap lookup, or a consultation of a file on disk, or the execution of a particular kind of SELECT query with an appropriate WHERE clause.

If the key is null, then no special rulebase subset is in effect, and only what the JACC specification calls the “default policy context” is in effect. Basically this means that no Java EE module has made this authorization call and you must consult the JVM-wide Policy for your authorization decision. (The default policy context is always in effect; more on that later.)

If the key is not null, then the rulebase subset—the current policy context, in JACC-speak—is now responsible for answering the authorization question. It may exclude the Permission, in which case no matter what else happens the Permission must not be granted, or it may grant it (provided that the default policy context does not exclude it). Again: if for any reason a given permission is found to be excluded, then java.security.Policy#implies(ProtectionDomain, Permission) must return false.

The default policy context, however it is implemented, forms a part of every authorization decision. That means if somehow it is possible to determine that the default policy context excludes a given Permission (not possible with the regular old java.security.Policy class) then that Permission must be excluded and Policy#implies(ProtectionDomain, Permission) must return false.