Saturday, July 28, 2007

How to REST?! - Authentication Client

We are using a simple java application as our client.The client is using the JAX-WS API to communicate with the web service.It first generates an XML message which contains information need to be authenticated.

info += "<?xml version=\"1.0\"?>";
info += "<auth xmlns=\"http://www.javadev.org/auth\" xmlns:xsi=\"
http://www.w3.org/2001/XMLSchema-instance\
"+
xsi:schemaLocation=\"
http://www.javadev.org/auth
\"+
http://www.javadev.org/rest/auth/auth.xsd >";
info += "<username>foo</username>";
info += "<password>foo</password>";
info += "</auth>";

As you can see, we are generating an XML message with the Username and Password which must be authenticated in the web service.

In the client, Service is used to create an instance of javax.xml.ws.Dispatch, which enables XML message-level interaction with the target Web service. Dispatch is the low-level JAX-WS 2.0 API that requires clients to construct messages by working directly with the XML, rather than with a higher- level binding such as JAXB 2.0 schema derived program elements. For many REST proponents, however, this is exactly the programming paradigm they want—direct access to the XML request and response messages.
The client uses the Service.addPort() method to create a port within the Service instance that can be used to access the RESTful web service.
Next, the Service.createDispatch() method is invoked to create an instance of Dispatch—a Dispatch instance that enables you to work with XML request/response messages as instances of javax.xml.transform.Source.
The Dispatch.invoke() method then packages the XML request—per the JAX-WS 2.0 HTTP Binding—and sends it to the RESTful service. The invoke() method waits for the response before returning.The service processes the HTTP GET and sends an HTTP response that includes the XML.The invoke() method returns the response XML message as an instance of Source.

// Create an InputStream with the authentication info
ByteArrayInputStream bais = new ByteArrayInputStream(info.getBytes());

QName svcQName = new QName("http://rest", "svc");
QName portQName = new QName("http://rest", "port");
Service svc = Service.create(svcQName);
svc.addPort(portQName, HTTPBinding.HTTP_BINDING, url);
Dispatch dis =
svc.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
StreamSource result = (StreamSource) dis.invoke(new StreamSource(bais));

Notice that you have to create QName instances for the Service instance and the “port” that corresponds to the RESTful Web service. In a SOAP scenario, these qualified names would correspond to the WSDL definitions for the wsdl:service and wsdl:port. Since there is no WSDL when invoking a RESTful service, these QName instances are gratuitous. They are required by the API, but not used to invoke the RESTful service.
The URL used in the addPort method is the URL of your web service for example we used http://localhost:8080/auth/authService which:
localhost is the name/IP of your running application server.
8080 is the port port of your application server.
auth is the context path of your web service which in our example is defined.
authService is the value of serviceName attribute of the @WebServiceProvider annotation in the web service.As you can see the authentication result is returned as an Source object. So we should parse it and extract the message as we did in the web service.

No comments: