Wednesday, September 16, 2015

How to JUnit test post-login code in Websphere Application Server 7+

Quite recently I wrote a WAS 7 utility that needed to access the JEE security Subject (read more on JEE Security) and its private credentials. The project, an auditing tool, accesses the Subject via IBM's WSSubject feature and uses some of its methods.


While trying to unit test it I ran into several problems, especially around trying to mock container-provided classes like Subject or LoginModules, and especially getting WSSubject to work.

Solving post-login unit test nightmares

When dealing with container-provided services like JAAS and the security model it can be very hard to write unit tests that exercise the code out-of-container, aka automated-build-tool-friendly tests. You can most probably start up an embedded container, but even so, setting up security to the point where it will populate your Subject can be tricky.

After a lot of research and trial-and-error, I created a test utility that allows you to:
  1. Let WSSubject return correct values for getRunAsSubject(), getCallerSubject() and getCallerPrincipal();
  2. Allow a unit test to add test private credentials to the Subject before testing a code unit that uses it;
  3. Allow a unit test to add a custom LoginModule and/or test custom LoginModules without the need of a container (not even a lightweight one);
  4. Allow the whole lot to run nicely from e.g. Jenkins in an automated build process.

Get to the code already

The samples contain 3x java classes:
  • A LoggedinTestContext with helpers to facilitate the login in out-of-container unit testing scenarios;
  • A MockLoginModule to show how to test JAAS Modules and/or add stuff to a Subject;
  • Sample unit test (LoggedinSubjectTest) to illustrate the LoggedinTestContext's usage and what it can provide.
The example code is not a full project as it depends on your own setup and is specific to your IBM WAS installation. The test data is also samples added as private credentials, but you can add anything your unit of code requires out of the Subject.

Dependencies needed

The code samples require you to (either in maven dependencies or elsewhere) have the following libraries available.

 WAS (7+) dependencies

All the jars below are relative to your WAS install root (e.g. IBM/Websphere/AppServer).
  • /lib/bootstrap.jar
  • /plugins/com.ibm.ws.runtime.jar
  • /runtimes/com.ibm.ws.admin.client_<version>.jar
  • /lib/j2ee.jar
  • /plugins/com.ibm.ws.emf.jar
  • /plugins/org.eclipse.emf.ecore.jar
  • /plugins/org.eclipse.emf.common.jar
  • /java/jre/lib/ibmcfw.jar
Where  <version> is your WAS version, e.g. 7.

JUnit dependencies

For the rest of the dependencies, the test code sample uses normal junit dependencies (junit mockito etc).

Code

I've added comments in the code so you should be able to follow along. I included the Gist listing in the blog, but you can it also get it from here.

Happy hunting!

1 comment: