Securing Spring Web Services: Chapter 3

Creating Bindings and Providers for Web Service


1.       Bind the contract defined by bookstore.xsd to java classes using JAXB’s xjc command.
Run the xjc command from bookstore-web-service\src\main directory

xjc –d java webapp\WEB-INF\bookstore.xsd

This command will result in creation of following java classes

com\bookstore\schema\AddBookRequest.java
com\bookstore\schema\AddBookResponse.java
com\bookstore\schema\Book.java
com\bookstore\schema\DeleteBookRequest.java
com\bookstore\schema\DeleteBookResponse.java
com\bookstore\schema\GetBookRequest.java
com\bookstore\schema\GetBookResponse.java
com\bookstore\schema\ObjectFactory.java
com\bookstore\schema\package-info.java

Now build the project using mvn clean package and check that bookstore-web-service.war is created successfully.

2.     Add a provider class BookStoreServiceProvider in a new com.bookstore.core package for servicing add, get and delete book requests. The requests don’t directly come to the provider instead the endpoints forward the request to this provider.
package com.bookstore.core;

import java.util.Hashtable;
import org.springframework.stereotype.Service;
import com.bookstore.schema.Book;

@Service
public class BookStoreServiceProvider {
       Hashtable<String, Object> store = new Hashtable<String, Object>();
      
       public void addBook(Book book) {
              store.put(book.getName(), book);
       }
      
       public void delete(String bookName) {
              store.remove(bookName);
       }
      
       public Book getByName(String name) {
              return (Book) store.get(name);
       }
}

3.       Create endpoints to handle add, get and delete book requests. Here all the endpoints are implemented in a single BookStoreEndpoints class
package com.bookstore.endpoints;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;

import com.bookstore.core.BookStoreServiceProvider;
import com.bookstore.schema.AddBookRequest;
import com.bookstore.schema.AddBookResponse;
import com.bookstore.schema.Book;
import com.bookstore.schema.DeleteBookRequest;
import com.bookstore.schema.DeleteBookResponse;
import com.bookstore.schema.GetBookRequest;
import com.bookstore.schema.GetBookResponse;
import com.bookstore.schema.ObjectFactory;

@Endpoint
public class BookStoreEndpoints {
      
       @Autowired
       BookStoreServiceProvider bookStoreServiceProvider;
      
       ObjectFactory factory = new ObjectFactory();

       @SoapAction("http://www.bookstore.com/schema/Add")
       @ResponsePayload
       public AddBookResponse addBook(@RequestPayload AddBookRequest request) {
              Book book = request.getBook();
              bookStoreServiceProvider.addBook(book);
              AddBookResponse response = factory.createAddBookResponse();
              response.setMessage("Book Added Successfully");
              return response;
       }
      
       @SoapAction("http://www.bookstore.com/schema/Delete")
       @ResponsePayload
       public DeleteBookResponse deleteBook(@RequestPayload DeleteBookRequest request) {
              String bookName = request.getName();
              bookStoreServiceProvider.delete(bookName);
              DeleteBookResponse response = factory.createDeleteBookResponse();
              response.setMessage("Book Deleted Successfully");
              return response;
       }

       @SoapAction("http://www.bookstore.com/schema/Get")
       @ResponsePayload
       public GetBookResponse getBook(@RequestPayload GetBookRequest request) {
              String bookName = request.getName();
              Book book = bookStoreServiceProvider.getByName(bookName);
              GetBookResponse response = factory.createGetBookResponse();
              response.setBook(book);
              return response;
       }
}

4.       Update spring-ws-servlet.xml to include component-scan of com.bookstore.core and com.bookstore.endpoints packages
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sws="http://www.springframework.org/schema/web-services"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd      
       http://www.springframework.org/schema/web-services
       http://www.springframework.org/schema/web-services/web-services-2.0.xsd">

    <sws:annotation-driven/>
    <context:component-scan base-package="com.bookstore.core,com.bookstore.endpoints"/>
    <sws:dynamic-wsdl id="bookstore" portTypeName="BookStoreInterface"
              locationUri="http://localhost:8080/bookstore-web-service/services"
              targetNamespace="http://www.bookstore.com/schema">
       <sws:xsd location="WEB-INF/bookstore.xsd"/>
    </sws:dynamic-wsdl>

</beans>

5.  Create java key store file bookstore-server-keystore.jks in WEB-INF directory using java’s keytool command. You can run this command from E:\bookstore-web-service\src\main\webapp\WEB-INF directory. Key store is a password protected file which stores the keys and certificates.
keytool -genkey -alias bookstore-server -keyalg RSA -keypass server12345 -storepass server12345 -keystore bookstore-server-keystore.jks

This will generate a pair of public-private key. The server’s public key has to be shared with all the clients who want to use the web services. The clients will use the server’s public key to encrypt the request message and send it to the server.  The server will decrypt the request message using its own private key and will then service the request.

Similarly, the server before sending the response back to the client will use the client’s public key for encrypting the response message. For this the client has to generate its own public-private key pair and share the public key with the server.

Use the following command to export the server’s public key into a certificate file. Run this command from WEB-INF directory

keytool -export -rfc -alias bookstore-server -file bookstore-ws-server-public.cer -keystore bookstore-server-keystore.jks -storepass server12345

The server’s public key certificate will be created and stored in file bookstore-ws-server-public.cer
This certificate file can be shared to all the clients.

The next step to import client’s public key certificate has to be done only after client side key store is created and client’s public key certificate is generated.

Assuming that you have received client’s public key certificate and copied it in E: drive, import client’s public key certificate using the following command. Run this command from WEB-INF directory

keytool -import -alias bookstore-client-import -file e:\bookstore-ws-client-public.cer -keystore bookstore-server-keystore.jks -storepass server12345

Certificate will be added to server’s key store. You can list the content of bookstore-server-keystore using the following command to verify if the client’s public key certificate is successfully imported.

keytool -list -keystore bookstore-server-keystore.jks -storepass server12345

No comments :

Post a Comment