Swing JAAS - poor Dr Dee

I don't want to be too critical about Swing JAAS, because its is a nice idea. But...

Dr. Dee appears to be confusing the UI (Swing in this case) with Client applications. The two normally go together, but the former implies JAAS4Swing and the latter distributed JAAS. Reading the design notes it is obvious that this library tried to do both.

In a bit more detail:

  • Distibuted JAAS is very hard to achieve without going vendor specific, because there is little support for the concept in the standards.
    Having written two djaas implementations over the last few years I know the difficulties (sorry closed source). For example certain key components of the JAAS framework are not Serializable, and you always have the security issues associated with 'man in the middle' attacks. Once you have solved these problems Distributed JAAS is very cool, because you can break the single server notion. Using the EJB model is probably a bit limiting in this case because it is not as powerful as the JAAS mechanism (but a bit easier to get your head round).

  • Swing Authentication & Authorisation, is what I think Dr. Dee was originally trying to do here.
    The authentication part should be simple, provide a default callback handler that delegates to a Document and bean model that is used to power the app's login screen; you can also allow an app to register its own CallbackHandler if it needs to.
    With the current approach to authorisation you are likely to get problems, because of the 101 ways that swing lets you do things. Using actions is the right way to do things if you are going to take this approach, and developers should be using actions for all things they want 'authorizable'. But if you go further then you must be prepared to do the whole job, rather than leaving it ad hoc and inconsistent.

The way an EJB client security normally works is by using a Proxy object, that checks the authorization of the method call in progress. Exceptions are thrown to represent the various failure cases. Because all EJB components are produced from their Home interface, which does the Proxy magic, then all access is protected by this mechanism. Doing the same with Swing is a very difficult task because it is not all action based, nor would using Proxy objects to wrap the various Model interfaces work either because the interface is so inconsistent. You could require and impose good techniques on the developer, but unfortunately security is normally an afterthought, and so requiring major code adaption would make people look at other solutions.

The real world examples of UI authorisation that I have actually seen and built are all based around bespoke implementations of the AccessController concept, because it is quicker to do than wrap most of Swing. You can of course use AOP point cuts to augment the swing byte code or even use a decompiler to build checks into faux versions of the swing components (and you might get a visit from Sun's lawyers). Another idea is to use an XML driven UI that would be unique for each role.

The most plausibly workable, but still simple, solution I have come across is the 'permit on pack' paradigm. Most swing application UIs are fully formed when the window.pack() gets called, all the panels, text boxes and buttons are in the component tree. Typically you have also logged in at this point, just before the window.show() is called. So why not parse the component tree and try and match all optional elements to their authorisation settings? The code to do this would not be pretty, but at least it would be a 'one stop shop' for making panels in/visible and menus enabled etc. You could also find out what to authenticate for by analysing the tree at the same time; so if your ACL permits you to use features of another system then you could log into that one as well.

How do you do it? In your Swing implementation you make sure that you add your nested components to the parent containers in the constructor (which is fortunately what most people do by default). Then in the Applet.start() or JFrame.show() method your wrap the super call in a Subject.doAs() having obtained the Subject from a LoginContext. Inside the doAs call you should then call the code that does the turning on and off of the various parts of the UI before actually starting/showing the application. This 'one time' check works for most application types. Running the whole application as a particular Subject has the added advantage of providing support to remote security like samba drive access.

No comments: