In our current assignment we are building a messaging based integration solution using Spring Integration and deploying it on WebLogic. In general, this has been quite a good experience as Spring Integration is a pleasant framework to work with from a developer’s perspective and the customer is happy that it will be rolled out on WebLogic as this is their strategic platform.
When it was time to implement the requirement for secure JMS (meaning authentication and authorization) we were sure that this would be easy. After all, even if security is not part of the JMS standard, Spring usually provides support for integrating with the application server in a consistent way.
A simple configuration change?
Since we retrieve connections from the connection factory it should be as simple as adding some properties to the JNDI-lookup like this:
Not so simple after all…
Unfortunately when we tested this we were greeted with: “JMSSecurityException: Access Denied To Resource”. This was discouraging but since using secure JMS with Spring and WebLogic should be quite a common use case we were still confident that there would be an accepted solution available.
Indeed, we were not alone. There were at least three JIRA-issues opened for this problem and a number of forum threads:
- Support secure JMS queue access on WebLogic – SPR-2941
- DefaultMessageListenerContainer failover to work with Weblogic JMS and security credentials – SPR-4720
- exposeAccessContext doesn’t resolve the issues with secure JMS and WebLogic. – SPR-5869
It was evident that this was not going to be so easy after all. Basically, the root of the problem seems to be that WebLogic does not allow the InitialContext created in one thread to be used in another thread which is what happens when Spring does the lookup on the connection factory in one thread and then tries to retrieve a connection in another. Although the problem has been known for at least five years, there is still no real solution.
A solution, sort of…
The accepted way (and the only one we found in the forums that would work for us) of getting around this if you are determined to use WebLogic JMS together with Spring is to use a decorator on the connection factory to create the InitialContext with the required security credentials for each call to “createConnection()”. This way, the credentials will be bound to the thread that is executing and WebLogic will not complain. The details of the implementation are here.
While the above solution worked well (thanks Honeybunny!) we were not really happy with it. Introducing a decorator felt invasive. Furthermore there is a potential performance issue in creating an InitialContext for every call to “createConnection()” which could of course be solved by introducing a threadlocal cache to avoid unnecessary calls but the real problem lies in the way that users are associated with threads which, as the WebLogic documentation makes quite clear, needs to be handled carefully:
“When you create a JNDI Context with a username and password, you associate a user with a thread. When the Context is created, the user is pushed onto the context stack associated with the thread. Before starting a new Context on the thread, you must close the first Context so that the first user is no longer associated with the thread. Otherwise, users are pushed down in the stack each time a new context created. This is not an efficient use of resources and may result in the incorrect user being returned by ctx.lookup() calls. “
Making sure the context is closed is certainly possible but it seemed to us that we were going in the wrong direction in writing custom code to get around something that should basically “just work” as we wanted to deliver a maintainable solution.
A one-click solution
After trying the different proposed solutions in the JIRA and forum threads we decided to check if there wasn’t some way to solve this by configuring WebLogic as it seems to have configuration alternatives for just about everything. In the admin console we noticed something promising. If you click on one of your deployed applications to get to the “Overview”-tab there is a field called “Deployment Principal Name” where you can specify the principal (user) that should be used during startup and shutdown if you need something else than the anonymous principal. This looked like it was worth a try so we set the principal to a user with the privileges for connecting to the JMS destination, restarted the server and – it worked!
Of course there are other ways of doing this configuration and since operations tend not to like the “point and click” deployment model the best way is to incorporate it in your deployment scripts with WLST.
Some caveats are in order. We are aware that this is still only a workaround and certainly not the final solution to the problem.
- First of all, this was what worked in our case and your mileage may vary. For one thing we are using the commonj.WorkManager API and not a thread pool managed by the Spring container.
- Obviously, this will only work for applications that are deployed in the application server. If you have a JMS-client that uses Spring JMS that is not deployed in WebLogic, you will need some other workaround.
- In our case, we have a simple deployment setup where we are not using a cluster and distributed JMS destinations so we haven’t tested if that will work but we think it’s likely that there will be issues.
Anyway, we hope that at least someone will find this solution helpful. Personally, we would have appreciated not having to spend nearly a week reading old forum threads figuring out what would work or not.
And as a final note; if all else fails you can always switch to Active MQ :-)