Monthly Archives: July 2011

Javadocs

One thing I believe very strongly in is good Javadocs.

It's one of the first places that I go when I need to understand how to use a library.?? I don't attempt to understand how to use the library through my IDE's autocomplete statements or the source code.?? I often end up in the source code, but that's usually because the API has not been well-designed or well-documented.

Good Javadocs are very hard to put together because at the same time you begin to put them together you run face-to-face with the weaknesses in your API.?? So you change the API to correct the problem, and now your Javadocs need to be torn up.?? Many developers stop there and throw the Javadocs out, or turn up their nose at them because they're not a very agile thing to do.?? But to me, they're absolutely essential–with them and unit testing, you can put together some decent APIs pretty quickly–or, I guess, more accurately, as quickly as you should be putting them together.?? :-)?? Good APIs take time, and the best ones explain themselves.

Here are some of the things that I do when writing Javadocs:

  • For any class name, I wrap it with the {@link tag}, whenever and wherever it appears.?? Think about that.?? This helps keep the reader in the flow: they can always turn down the styles in their browser or take other measures to get rid of blue underlines–I don't worry about too many links–but having the ability to quickly link to the class under discussion is invaluable.
  • For any identifier, or keyword, I wrap it with the {@code} tag.?? This is just following good typographical style.
  • For every parameter, I document whether null is permitted or not.?? This forces me to figure out what to do with nulls in every situation.?? Sometimes I will realize that accepting nulls is a perfectly reasonable thing to do (more often than not–but this is a stylistic question that every developer has a strong opinion on).
  • For every @return tag, I document whether the method can return null or not.?? Every single one.
  • For personal software, I use the @since tag and supply the month, year and date.?? That helps keep me honest and shows what order I've developed things in.
  • I always try to use the @author tag with my hyperlinked email address.
  • I try to use (and wish I were better at using) the @see tag to establish a rough trail through the API.
  • I try to hyperlink portions of explanatory documentation to methods and fields that the documentation refers to {@linkplain Object#equals(Object) as I do here in this example about the <tt>Object#equals(Object)</tt> method}.?? Note the use of the {@linkplain} tag and the nested <tt>s.
  • I have a standard boilerplate Subversion-friendly Javascript hairball that I use for the @version tag (I use keyword expansion of $Revision$):

@version <script type="text/javascript"><!–
document.write("$Revision: 0.0 $".match(/d+.d+/)[0]);
–></script><noscript>$Revision: 0.0 $</noscript>

Hope this helps you think about how you document your own code.

Towards a composable Policy delegation framework

The first step in putting together a Java Policy-based security system of any kind is to figure out what you're going to do when you have to delegate.

You will have to delegate certain permission checks in certain situations–there's just no pragmatic way around it.

Different security systems require different algorithms for checking permissions.?? Sometimes you might have several subsystems that all have to effectively vote on a permission check, and there will need to be an algorithm in place for such collaborative efforts that can resolve conflicts.

When a security system is asked whether a permission to do something is granted or not, it can respond in one of several ways.?? It can:

  • Grant the permission.?? This might not be the final word.
  • Deny the permission.?? This might not be the final word either.
  • Mandate the permission.?? For whatever reason, this security system's answer should be treated as the final word.
  • Prohibit the permission.?? For whatever reason, this security system's answer should be treated as the final word.
  • Not support the permission.?? The security system might not be equipped to render an answer at all for this kind of permission check.
  • Waffle.?? Perhaps the security system supports the permission, but cannot render a decision because of, say, conflicting information.

Ultimately, the caller is almost always interested at some level in a boolean response.

This sounds like an enum:

public enum PermissionEvaluation {

?? UNSUPPORTED,
?? INDETERMINATE,
?? DENIED,
?? PROHIBITED,
?? GRANTED,
?? MANDATED;

?? public boolean isAuthoritative() {
?????? return this == PROHIBITED || this == MANDATED;
?? }

?? public boolean toBoolean() {
?????? switch (this) {
?????? case GRANTED:
?????? case MANDATED:
?????????? return true;
?????? default:
?????????? return false;
?????? }
?? }
}

This enum captures the kinds of permission evaluations that are possible, the boolean values to which they reduce, and an indication of how "strong" or authoritative they are (in the absence of a higher authority).

From there, we might be able to extrapolate a PermissionEvaluator interface:

public interface PermissionEvaluator {

?? public PermissionEvaluation evaluate(final ProtectionDomain protectionDomain, final Permission permission);

}

Implementations of this interface would be able to answer the question–much like a java.security.Policy–"Is the supplied Permission granted, excluded, etc. in the context of the supplied ProtectionDomain?"

Picture, now, a whole chain of these returning various PermissionEvaluations for the same Permission and ProtectionDomain parameters.?? Now something will need to exist to combine the results and render a final boolean decision:

public interface PermissionEvaluationCombiner {

?? public boolean isAuthoritative(final ProtectionDomain protectionDomain, final Permission permission, final PermissionEvaluation evaluation);

?? public boolean combine(final ProtectionDomain protectionDomain, final Permission permission, final PermissionEvaluation… evaluations);

}

That would handle the true-or-false authorization questions and would help put together the building blocks of a composable delegating Policy-based authorization framework.?? Next up: handling the java.security.Policy#getPermissions(ProtectionDomain) method.

Policy delegation and combining

(See my previous post for a broad-brush, ruthless condensation of the JACC specification.)

One thing I found while going through the specification and writing a JACC implementation is that most of the effort involved has to do with Policy delegation.?? I've run into this in the past, too, in a non-JACC scenario.?? Briefly: in any non-trivial authorization system, you're going to ultimately have to combine the results from various Policy implementations in some kind of chained delegation model.

As I said, I've had to write such a thing several times now which means it's time to abstract it out.?? :-)?? Watch this space for a general-purpose Policy delegation and combining framework.

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 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.