I am a big fan of EJB3, but I think certain integration realities in an enterprise environment can limit its relevance. While recently working with EJB3 stateless session beans exposed as JAX-WS web services, I ran into some issues propagating security credentials. I know that this is a fairly seamless process in a traditional Java -> EJB invocation. I had hoped that there was some magic that would provide the analagous solution of security credential propagation from a Java web application to a JAX-WS web service secured with HTTP basic auth (and SSL for the transport mechanism).
I could not dig up any details on this topic, so I came up with my own solution by assembling standard and quasi-standard components.
The end result looked like this:
1. The web application, which used form security, was adapted to use the Spring Security form-based authentication. Although this was a somewhat painful process in the Acegi Security days of configuration hell yore, the Spring Security domain-specific namespace has made it a quite simpler activity. You need a couple of filters and a very simple Spring XML file. Reference docs are here. Anyway, I set up the authentication in the web app to authenticate against the same JAAS realm I had previously used with straight container-managed security.
2. Next, I used the Spring JaxWsPortProxyFactoryBean to wire up my remote web service to appear as a simple business service interface to the web application code. This is pretty cool, because it lets you code your view and controller code completely ignorant of the fact that the model lives somewhere in the SOAP world. I leveraged the new basic authentication functionality of Spring 2.5.5’s JaxWsPortProxyFactory bean and created session-scoped instances. So, I could have an instance of the client bean for each user of the web application, and that client would have its username and password properties initialized from the Spring Security SecurityContext object in scope.
3. Next, I set up my web service (JAX-WS servlet endpoint with injected EJB resource) with Spring Security settings of its own, to include basic authentication against the same realm as the web application (if on different containers, would be different realms but the same underlying authentication store) and HTTPS transport. Then, voila, I had credentials that were equally valid in the web application and the web services.
To be fair, this was a lot of work, but code samples aren’t really necessary as most of the work was in figuring out a valid approach
However, I believe the benefits will be immense in the long run.
I can always add rules later to enable anonymous callers of certain web service operations, but more often than not, I want to know who the caller is and have their experience (returned data) take that into account. That way I can take advantage of all the neat things that Spring Security offers to create fine-grained security in my services. I can do method-level security, collection-filtering security, and audit logging with ease! At the most primitive level of functionality, I can do a thumbs-up, thumbs-down decision on whether a user is even authenticated and allowed to use a web service.
I have seen some pretty primitive attitudes toward web service security–things like non-SSL transports combined with a simple authentication token that never changes. This is exactly the kind of recklessness I wanted to avoid in my services. SOA is a powerful mechanism when employed properly. One of the premises of SOA is that systems can be easily built by aggregating services. However, that is no reason for the web services to be a free-for-all for anyone who can find a “Hello, this is Axis” servlet and associated WSDL.
Stand with me and build a better web service!