Posts Tagged ‘JAX-WS’

Contract-driven web services with JAX-WS

Monday, July 28th, 2008

Attentive readers will notice that I have previously advocated both contract-first web services and JAX-WS. Although these might seem like contradictory concepts at first glance, I believe I can make a case for the use of these two approaches together. Although many “Hello World” web service examples with JAX-WS simply use the @WebService annotation, a much more sophisticated web service can be developed by digging in to the optional attributes of the javax.jws.WebService annotation. One in particular that jumps out:

-wsdlLocation: allows the specification of a URL of an existing WSDL file. This file can be stored on the web or referenced with a local URL. The WSDL and an external JAX-WS XML bindings file can be used to specify the service operations and the Java type mapping respectively.

Maybe you are not interested in creating your own WSDL or XML bindings file, and you instead want to use Java as your language to express your service contract. Although you lose some power in this arrangement (mainly in the area of XSD data constraints), this may be a more natural approach for most Java developers.

One important consideration in maintaining the contract of a web service is versioning capabilities. If you need to provide backwards-compatibility when you make service operation signature or semantic changes, consider the use of version-based namespaces. Again, the @WebService annotation provides for this with another optional attribute, targetNamespace. It is good practice to embed a version number in both the service endpoint URL and the service namespace to protect against future changes that break backward compatibility.

Having a mechanism for versioning is only half the battle. Having a minimally invasive way to continue to separate your web service endpoint from refactoring and change in your Java code is the key. The approach that I rely on is to inject business services into my service endpoint class rather than directly annotating business services with the JAX-WS annotations. These classes can be a simple 1-to-1 delegate at first, but can adopt more complex mapping and adapting behavior over time if needed for backward compatibility. This allows business services (Java) and web services (JAX-WS/SOAP) to have different refactoring and backward compatibility restrictions (if desired).

The most simple example:

@WebService
public class HelloWorldWebService {
private HelloWorldService service;

public void setHelloWorldService(HelloWorldService service) {
this.service = service; //service delegate injection point
}

@WebMethod
public String helloWorld() {
return service.helloWorld();
}
}

It is tempting to take the easy way out and simply annotate a concrete service class with web service functionality. My preferred breakdown is to have a business service interface, a business service implementation, and a concrete web service endpoint class with annotations. This makes your business services completely unaware of remoting considerations, which is good insulation against future adoptions/un-adoptions of technologies. If the REST advocates have their way and take over the world, you can always rip out your JAX-WS service endpoint class and replace it with the remoting strategy du jour.

You can create a contract-driven SOAP web service with varying degrees of rigor easily with JAX-WS. Understanding your constraints and how closely you want to adhere to contract-driven approaches should allow you to find a happy place where you can leverage the JAX-WS toolset and still build robust and stable web services.

Software development methodologies can easily be adopted with religious zeal, but it is important to remember that our ultimate goal is to build software that delivers on business needs!

Propagating web application credentials through JAX-WS and Spring Security

Thursday, July 3rd, 2008

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!