We have a multi-tiered application where all of the business rules and implemented behind EJBs (session or message-driven). We wrote our own support for single sign-on across roughly 15 applications and that security context is used in a few places:
- The Application Coordination tier for both authentication and authorization
- Business tier for some field-level validation
- Integration tier to track who’s doing what
As a result, we end up passing along session keys and security credentials everywhere.
We wanted to minimize passing around these parameters everywhere. We considered the Wormhole pattern but ruled it out as a bit too much for most people to follow (although, in defense of the pattern, I think it’s not too bad and it follows a form, so it’s repeatable). Instead, we stole from the Wormhole pattern, which makes use of the fact that certain information is stored on ThreadLocal variables, and instead wrapped most of our EJB entry methods to make this information available.
Below you’ll find two classes. The first, Context Recorder, does 3 things.
- Upon the first entry into an EJB Session method, it records the security key and security credentials into a ThreadLocal variable.
- It executes the underlying method.
- It clears out the ThreadLocal variables.
It does not directly interact with ThreadLocal variables. Instead, it uses a class called Thread Context to both record and clear the thread local variables.
Thread Context simply creates a thread local variable that is a map. Any code can add to the thread local map and remove from the thread local map.
So if some piece of code needs access to the security credentials or session key, it can simply execute one of the following lines:
The ThreadContext class resides in a utility project that does not have direct access to the types ISessionKey or ISecurityCredentials. That’s why there’s no convenience methods to access those specific types on the interface to ThreadContext.
Instead, we created another utility class that simply wrapped ThreadContext and performed the cast for us and put this in the same project where ISessionKey and ISecurityCredentials reside.
ContextRecorder.java
Interesting Lines
Line | Description |
19 | The pointcut ejbMethod matches all methods on SessionBeans or its subclasses. |
20 - 24 | There are a few EJBs that support security. We never want these to be part of this aspect. |
26 | Define the man ponintcut for this aspect. |
27 | The target(receiver of the message) must be a SessionBean or a subclass. |
28 | The first parameter to the method must be ISessionKey, there can be zero or more additional parameters. |
29 | It must be an ejbMethod(). |
30 | It must not be in the control flow of the call of ejbMethod. That is, if I’m already executing an ejbMethod() and that calls another ejbMethod, do not do wrap that call as well. It only needs to happen once at the “top” of the EJB call stack. |
31 | Skip the security-related EJB’s. |
45 - 46 | Record first the session key and then the security credentials. Note that getting the security credentials might cause a TimedOut exception to be thrown. If this happens, the finally block will remove the already-recorded session key. |
48 | Run the underlying EJB method. |
52 | Regardless of how you are leaving this code, make sure to clean up the ThreadLocal variables. The container probably maintains a thread pool and we don’t want to leave trash in our threads. |
Comments