Skip to main content

Employ the IBM WebSphere Web Services Gateway, Part 2

Route SOAP messages using a secure subscription token

Michael Ellis (msellis@ca.ibm.com), Solution Architect, IBM Software Services for WebSphere
Michael Ellis is a solution architect on the IBM Software Services for WebSphere team and lives in Ottawa, Canada. He specializes in Web services, XML, J2EE technology, and object-oriented architecture and design. You can contact him at msellis@ca.ibm.com.

Summary:  Learn how JAX-RPC Handlers deployed in the IBM Web Services Gateway can use X509 certificates as Web services subscription tokens that identify the service subscriber making a request and, subsequently, route requests based on the requestor's service-level entitlements.

Date:  14 Dec 2004
Level:  Advanced
Activity:  898 views
Comments:  

Introduction

In Part 1 of this series, I described how the Web Services Gateway can be used to route inbound Web services requests based on information that the requestor places in the header of a SOAP message. The example uses a simple character string to indicate the requestor’s subscription level for a service and showed how messages can be routed to service implementations with QoS characteristics that match the level indicated in the message. In this paper, I build on the example in my previous paper, adding the following requirements:

  1. The subscription token uniquely identifies the subscriber.
  2. The token format chosen exhibits the property that only the service providers can issue the tokens; in other words, non-subscribers cannot create tokens and masquerade as subscribers.

The approach has several practical applications. For example, imagine that a video-on-demand provider uses a Web service to accept content orders from customers where the amount of network bandwidth allocated to the video stream is dependant upon the customer’s subscription level. In such a circumstance, the provider could issue a to each subscriber a self-signed certificate which the subscriber would install in his viewing client (perhaps provided on a smartcard). The viewing client would then send the token to the provider with each content order, and the quality of the resultant video stream would depend on the QoS level that was purchased in the subscription.

Design the header element for the subscription token

You might recall from the first paper in this series that there are several aspects of SOAP headers that a JAX-RPC handler must consider when it is looking for headers that it should process. Here is a brief summary:

Table 1: Aspects of SOAP header processing

Header element aspect Significance
The role (Actor) to which the header element is assigned The handler should examine only those headers which have an actor value matching one of the JAX-RPC handler's roles.
The header element's qualified name Handlers look for header elements that they recognize and understand how to process by examining the qualified name of each header element assigned to their role.
The mustunderstand attribute's value The handler must recognize and understand any headers assigned to a role held by a JAX-RPC handler if this attribute is set to “1.” Otherwise the JAX-RPC handler must avoid any processing of the inbound message (including the processing of headers it does understand) and emit a SOAP Fault.

While the above illustrates that there are many things to consider when processing a SOAP message, the qualified name of a header element is the primary means of recognizing it and invoking the processing rules associated with it. Consider though that requirements are not static; as an application evolves it might be necessary to alter the format of a header in ways that are not compatible with earlier versions. The next section of this paper covers some techniques that you can use to allow for requirements change in the future.


Create SOAP headers that support versioning

Systems evolve, and it is prudent to assume that our subscription header token might evolve over time; so this brings you to the first design decision you must make -- what approach should I use to allow for the evolution of the subscription token?

Approach 1: Use a unique header name for each iteration of the subscription token

Since the qualified header name is the primary means of recognizing the header, you could use a unique qualified name to identify each version of the subscription token format as the token evolves. You can do this by introducing an iteration identifier in the namespace of the subscription header element. Here are some examples:

xmlns="http://com.videos-r-us/v1/membership"
xmlns="http://com.videos-r-us/2004-10-15/membership"

In the first example a simple sequence numbering scheme is employed; the second uses a date in a similar fashion to what is commonly seen for versions of important standards like XML Schema and WSDL.

The draw-back to using a unique namespace for headers is that a JAX-RPC handler might not recognize the header at all if it is not searching for that exact name. This means that deployment errors such as deploying the wrong version of a handler are more difficult to detect; the header might simply be ignored leaving the administrator to figure out why. Problem determination could be simplified if the mustunderstand attribute of the header is set to "1." Assuming that the Actor at which the header is targeted matches that of the handler, a well-behaved handler will emit a SOAP fault for an unrecognized header and draw attention to the problem. Unfortunately this also introduces processing semantics that might not be appropriate for all situations; for example, it might be desirable to make the header processing optional for some circumstances. In a nutshell, the mustunderstand attribute is not intended to support header versioning; it is intended to alter the processing semantics for a given message.

Approach 2: Use a version qualifier inside the header element

A second approach to header versioning uses a version value inside the header, Listing 1 shows:


Listing 1: Embedding a version element inside a SOAP header
<shns:subscriptionToken actor="router" xmlns:shns=
"http://com.videos-r-us/membership">
	<shns:headerVersion>1</shns:headerVersion>
</shns:subscriptionToken>

When using this approach, handlers always recognize the subscription token header because the qualified name does not change. They can also examine the version identifier and determine if they understand the header format. If they do not understand the format they can either:

  1. Do nothing if mustunderstand is set to "0" (the default) or
  2. Emit a SOAP fault containing an informative description of the problem if mustunderstand is set to "1."

The drawback with this approach is that the JAX-RPC handler must locate and examine the version identifier each time it sees a subscriptionToken header. It cannot assume that the header is understood simply because the qualified name was a match. So this represents extra processing overhead for each request.

The example in this paper uses a version element inside the header to allow for different header formats to evolve over time.


Select a subscription token

In the previous article, the subscribed QoS was self-evident when looking at the routing token; Gold subscribers inserted "GoldService" as the subscription token, Silver subscribers inserted "SilverService," and so on. With the addition of the requirement that each token uniquely identify the subscriber, some other means must be used to establish the target service implementation for the message. Essentially, the routing table must be modified to associate a subscriber’s identity with the subscription they have purchased and to handle requests accordingly. To satisfy the new requirements, provider-signed X509 certificatesare used as the subscription token. X509 certificates have several properties that make them attractive for this purpose:

  1. Signature verification, certificate revocation lists (CRLs), and certificate life-span can be used to validate the subscription (token).
  2. Provider-signed certificates eliminate the possibility that non-subscribers can create (forge) tokens.
  3. Changes in the subscription level can be made without impacting the token that is exchanged in the message. There are no client-side changes when the requestor negotiates a different subscription level. The token carries the requestor's identity; the provider manages the subscription level.

The approach taken in this paper assumes that the Web service provider has decided to act as a private Certifying Authority (CA) and will issue a certificate to each subscriber that has been signed with the provider's private key.

Since serialized X509 certificates are binary blobs of data, you can't embed them directly into the SOAP message header. They must be rendered in XML-compatible form. A common means of embedding binary information in a SOAP request is to apply BASE64 encoding to the information, rendering it XML compatible. For the example in this paper, the requestor’s handler applies BASE64 encoding to the token prior to inserting it into the routing header.

Listing 2 in this sidefile shows an example of a subscription header that meets the requirements identified.

The example does not identify that the token is a BASE64-encoded X509 certificate. That knowledge is implicit in the implementations of the JAX-RPC handlers deployed at the requestor and in the Web services Gateway. If there is a future requirement to support various token types, information about the type of token provided can be added to the header along with a related version change in the header format.


Routing criteria

Now that you know the format of the subscription header and the nature of the subscription token, the next step is to identify some property of the token that is unique among subscribers to use as the basis for the subscription mapping. Conveniently, the certificate subject's identity is represented as a distinguished name (DN). A DN is a set of attribute-value pairs that represent a path through an X.500 directory information tree. Here is an example:

CN=Michael S. Ellis, O=IBM Canada Ltd., OU=SWG, L=Ottawa, ST=Ontario, C=CA

RFC1485: A String Representation of Distinguished Names identifies a set of DN components (see Table 2). In order to reach a high degree of interoperability between X.500 and LDAP names, you should restrict yourself to these components when assigning DNs. This interoperability is desirable since many organizations use LDAP directories when managing user identities.

Table 2: Standardized DN Keywords

LDAP short name DN Attribute Description
CN commonName Individual’s name, Server name or IP address
O OrganizationName Company name
OU OrganizationalUnitName Business unit name, identifier
L LocalityName Name of the community in which the subject resides
ST StateOrProvinceName Name of the state or province where the subject resides within the country of origin
C countryName Name of the subjects’ country of origin

For the sake of simplicity, I use the CommonName attribute as the basis for subscription mapping in this article.

The processing flow for the X509 subscription token

The processing requirements are not that much different from the example in my previous paper. Here is a summary:

  1. The requestor inserts a BASE64-encoded X509 certificate into the header of his message and sends the message to the Gateway Service endpoint.
  2. The subscription token handler in the Gateway identifies the subscription header.
  3. The handler extracts and decodes the encoded token to recreate the X509Certificate instance.
  4. Standard X509 certificate processing occurs:
    1. The certificate is checked to confirm that the private CA signed it.
    2. The certificate is validated (the expiration is checked).
    3. A certificate revocation list is checked to ensure that the certificate has not been revoked.
  5. The CommonName component of the DN is extracted from the certificate and mapped to a service endpoint based on the subject’s membership level.
  6. The message is forwarded to the selected service endpoint.

The com.ibm.security.x509.X500Name class provides methods to access the certificate DN's common components. This class is included in the JCE implementation that the Security provider uses in the IBM® WebSphere® Application Server V5.1 (Application Server).

The BASE64 encoder/decoder

The classes for performing BASE64 encode/decode operations that are included with Application Server are not part of the public API supported by IBM. Since they are not supported, there is no guarantee that they will continue to be included or packaged in a consistent manner as Application Server evolves. Due to the lack of support, I recommend that you avoid using these BASE64 routines.

There are, however, several open source BASE64 encoder/decoder implementations available. I have chosen one, the MiGBase64 implementation, to provide the encode/decode operations for this example. This is not an endorsement of that implementation over others that are available, though I can say that I had no problems using the MigBase64 encoder.


Implement the requestor-side X509 certificate handler

Requestor handler initialization parameters

I built the client-side handler example with the following assumptions:

  1. The client's subscription certificate is located in a password-protected Java Keystore (.jks) file. Therefore, the handler must be provided with the keystore location and password.
  2. The keystore may contain several certificates, so it is necessary to identify the certificate by its alias within the keystore.

These specifics are provided to the handler as initialization parameters, replacing the explicit ServiceLevel parameter I used in the previous paper. Table 3 shows the new set of client handler configuration parameters:

Table 3: Client handler initialization parameters

Parameter Name Description
KeystorePath The filesystem path name of the keystore file
KeystorePswd The keystore password
CertAlias The certificate alias
ActorName The role name to assign to the subscription header
HeaderName The tag name to use for the header
HeaderNamespace The namespace to use for the header and its parts

Client-side handler handleRequest() method

Here is the handleRequest() method for the new client-side handler implementation. As you can see, the structure is similar to the previous one, with the exception that this one retrieves the client certificate and encodes it into a string which is then embedded in the message; whereas the previous handler just inserted the service level. The headerVersion element is also added here to reflect the updated header structure.

In Listing 3 the configuration parameter accessors (for example getActorName()) use the same technique described in the previous article.


Listing 3: Service client handler handleRequest() method
public boolean handleRequest(MessageContext mc) {
	boolean result = false;

	try {
		X509Certificate cert = getClientCertificate();

		// create the header element that will hold the membership token
		SOAPHeaderElement headerElement =
			HandlerUtil.addHeader(
				(SOAPMessageContext) mc,
				getHeaderTagName(),
				RoutingConstants.HEADER_PREFIX,
				getHeaderNamespace(),
				getActorName(),
				false);

		// insert the header-version child element into the header
		SOAPElement versionElement =
			headerElement.addChildElement(
				RoutingConstants.VERSION_ELEMENT_NAME, 
				RoutingConstants.HEADER_PREFIX);
		versionElement.addTextNode(RoutingConstants.HEADER_VERSION);

		// insert the membership token child element into the header
		SOAPElement tokenElement = 
			headerElement.addChildElement(
			RoutingConstants.TOKEN_ELEMENT_NAME, 
			RoutingConstants.HEADER_PREFIX);

		// place the certificate data into the tokenElement,
		// encoded in Base 64
		tokenElement.addTextNode(
			Base64.encodeToString(cert.getEncoded(), true));

		// header processing was successful
		result = true;
	}
	catch (Exception e) {
		throw new SOAPFaultException(
			new QName("Client"),
			"Client processing failure: " + e.getMessage(),
			"",
			null);
	}
	return result;
}

Access the client subscription certificate

Accessing the client certificate is a straightforward process using classes that Java security provides. This would get tricky if I didn’t make an assumption about the keystore file format. Fortunately, the Java Keystore format (.jks) is common and generally supported.


Listing 4: Load the subscription certificate from the keystore
	private X509Certificate getClientCertificate()
		throws
			KeyStoreException,
			IOException,
			NoSuchAlgorithmException,
			CertificateException,
			FileNotFoundException {

		// assume a jks keystore and get a jks keystore instance
		KeyStore ks = KeyStore.getInstance("jks");

		// load the keystore instance
		ks.load(
			new FileInputStream(getKeystorePath()),
			getKeystorePassword().toCharArray());

		// get the certificate described in the handler configuration
		X509Certificate cert =
			(X509Certificate) ks.getCertificate(getKeystoreAlias());
			
		// emit some info about the certificate
		printCertDetail(cert);

		return cert;
	}

There are several X509 certificate property accessors on the X509Certificate class. The printCertDetail() method uses these to display the certificate details in the console. Listing 5 shows a sample of the output.


Listing 5: X509 Certificate Details
Class = com.ibm.security.x509.X509CertImpl
Type = X.509
SigAlgName = SHA1withRSA
SigAlgOID = 1.2.840.113549.1.1.5
Version = 3
IssuerDN = CN=Int CA2, OU=TRL, O=IBM, ST=Kanagawa, C=JP
SubjectDN = CN=SOAPRequester, OU=TRL, O=IBM, ST=Kanagawa, C=JP
Principal class = com.ibm.security.x509.X500Name
IssuerUniqueID = null
NotAfter = Sat Oct 01 05:54:06 EDT 2011
NotBefore = Mon Oct 01 05:54:06 EDT 2001
Public key format = X.509

The detail for this particular certificate shows that it was signed by an issuer with the DN of CN=Int CA2, OU=TRL, O=IBM, ST=Kanagawa, C=JP. You will see shortly that this is the same DN that has been assigned to the SubjectDN value of the Certifying Authority (CA) certificate used to validate the requestor certificate.

This completes the necessary changes that must be made to the client handler for this subscription token scenario. The majority of the work for this scenario is in the provider-side handler, which must recover the certificate from the header, verify it, and validate it.


Implement the provider-side X509 certificate handler

Provider handler initialization parameters

To verify a client certificate, the provider-side handler must have access to the issuers’ public key. In the example provided, I make the assumption that the CAs’ serialized certificate, containing both the private and public keys, is available somewhere in the local file system. Therefore, the handler must be provided with that file system location in order to recover the certificate and make use of the public key.

The path name of the certificate is provided to the handler as an initialization parameter. In addition, the set of initialization parameters identified in the previous paper apply equally in this case. Table 4 shows the results to the set of initialization parameters for the provider side handler:

Table 4: Provider handler initialization parameters

Parameter name Description
CA_Path This is the file system path name of the file containing the CA certificate.
RoutingConfig The file system path name of the routing table containing key value pairs, where the "key" is an issued client certificate's subject CommonName (CN), and the "value" is the URL of the service endpoint that provides the QoS that the subscriber has purchased.
HeaderName This is the tag name to use for the header. This must match the value configured on the client handler.
HeaderNamespace The namespace to use for the header and its parts

The provider-side handleRequest() method

The main difference between the handleRequest() method used in the previous paper and this one are that this method must also do the following:

  1. Check the header version to ensure that the format is understood.
  2. Process the digital certificate.

The two additional steps are captured in two new methods:

  1. The isCompatibleHeaderFormat() method which checks the header version.
  2. The extractAndVerifyCert() method, which reconstitutes the client’s digital certificate from the encoded data in the header, verifies the signer, and confirms that the certificate has not expired.

The actual routing step is similar in that each implementation maps a character string to a service endpoint to determine the route of the SOAP message. In the first case, that string is an explicit service level, for example GoldService, and in this case it is the CN of a verified, valid certificate.

Listing 6 in this sidefile shows the strategy for header processing at the provider.

Verify that the subscription header format is correct for this handler implementation

The program code required to test the subscripion header's version is quite simple. All that is required is that the version element be located, and that it's value match the value expected by the receiving handler. A more elaborate approach might assume that each iteration of the handler can understand the version that was current when it was written and in all earlier versions; however, the example presented here takes the simpler approach of expecting a specific header version. Also, note that the absence of a header version child element results in a return value of "false."


Listing 7: Test the header version for compatibility with the receiving handler handleRequest() method
/**
 * This method examines the subscription header to see if the format
 * is compatible with this handler implementation
 * @param subscriptionHeader
 * @return boolean
 */
private boolean isCompatibleHeaderFormat(
		SOAPHeaderElement subscriptionHeader) {
	boolean isCompatible = false;
	SOAPElement elem =
		findChildElement(subscriptionHeader, getVersionElementName());
	if (elem != null)
		isCompatible = 
			SUPPORTED_HEADER_VERSION.equalsIgnoreCase(elem.getValue());
	return isCompatible;
}

Access the CA public key and test the client certificate

Since the code required to process the certificates is of primary interest in this paper, I include it here in its entirety.

This first method (see Listing 8) simply locates the subscription token element within the header, extracts its value, which is a string containing the encoded certificate, and delegates the certificate processing to another method.


Listing 8: Locate the subscription token element, extract the certificate data and have it verified
/**
 * This method locates the element that contains the encoded 
 * subscription token, extracts the encoded string and uses 
 * the extractAndVerifyCert(String encodedCert) method to 
 * establish the actual X509Certificate. If successful it 
 * returns a reference to the resulting X509Certificate 
 * instance.
 * 
 * @param subscriptionHeader
 * @return
 * @throws InvalidKeyException
 * @throws NoSuchProviderException
 * @throws SignatureException
 * @throws NoSuchAlgorithmException
 * @throws CertificateException
 * @throws FileNotFoundException
 * @throws UnrecoverableKeyException
 * @throws KeyStoreException
 * @throws IOException
 * @throws HandlerConfigurationException
 * @return java.security.cert.X509Certificate
*/
private X509Certificate extractAndVerifyCert(SOAPHeaderElement subscriptionHeader)
	throws
		InvalidKeyException,
		NoSuchProviderException,
		SignatureException,
		NoSuchAlgorithmException,
		CertificateException,
		FileNotFoundException,
		UnrecoverableKeyException,
		KeyStoreException,
		IOException,
		HandlerConfigurationException {

	X509Certificate result = null;
	SOAPElement elem =
		findChildElement(subscriptionHeader, getTokenElementName());

	if (elem != null)
		result = extractAndVerifyCert(elem.getValue());

	return result;
}

Generally, there are 3 steps that must be performed when verifiying and validating a certificate. The certificate must be tested to confirm that:

  1. It was signed (issued) by the appropriate certifying authority.
  2. It has not expired.
  3. It is not listed in a certificate revocation list (CRL), which ensures that past subscribers (in other words, those that are no longer customers but were at some time in the past) are denied service.

The code in Listing 9 does not check a CRL to see if the certificate has been revoked. That task is left as an exercise for the reader. I have inserted a comment at the location where you should perform that test.


Listing 9: Verify that the certificate data represents an X509 token that we issued and that it is still valid
/**
 * This method uses a BASE64 decoder to decode the String argument and 
 * create a X509Certificate instance from the resulting byte array. If
 * successful it returns a reference to the resulting X509Certificate 
 * instance. 
 * 
 * @param encodedCert
 * @return
 * @throws InvalidKeyException
 * @throws NoSuchProviderException
 * @throws SignatureException
 * @throws NoSuchAlgorithmException
 * @throws CertificateException
 * @throws FileNotFoundException
 * @throws UnrecoverableKeyException
 * @throws KeyStoreException
 * @throws IOException
 * @throws HandlerConfigurationException
 * @return java.security.cert.X509Certificate
*/
private X509Certificate extractAndVerifyCert(String encodedCert)
	throws
		InvalidKeyException,
		NoSuchProviderException,
		SignatureException,
		NoSuchAlgorithmException,
		CertificateException,
		FileNotFoundException,
		UnrecoverableKeyException,
		KeyStoreException,
		IOException,
		HandlerConfigurationException {

	byte[] ba = Base64.decode(encodedCert);

	// we're expecting an X509 cert
	CertificateFactory cf = CertificateFactory.getInstance("X509");
	X509Certificate cert =
	(X509Certificate) cf.generateCertificate(new ByteArrayInputStream(ba));

	// recover the public key of the CA
	PublicKey ca = getCAPublicKey();

	System.out.println("\n\nRequestor Certificate Details:\n");
	printCertDetail(cert);

	// verify that the cert was signed by the CA
	cert.verify(ca);

	// confirm that the certificate is valid, i.e. hasn't expired
	cert.checkValidity();
	
	// check for certificate revocation here...

	return cert;
}

As I mentioned earlier, this example assumes that the CA certificate has been serialized to a file somewhere in the filesystem. Specifically, the certificate must have been serialized into the file as a DER-encoded byte stream; the -export option of the Java keytool utility creates files in this format by default. The getCAPublicKey() method listed below recovers the public key from that certificate.

Issues with handler state

Handler instances are managed in a pool by the application server. This means that techniques like lazy initialization might not prevent the CA certificate from being read several times. All it guarantees is that each instance will read the certificate once.

The java.security.cert.X509Certificate is a standard Java interface that defines the operations on a certificate; most of the time your application will not care what implementation it is using since the construction of the instances is handled elsewhere. In this case you need to know the implementation class because you have to construct an instance of it from the information in the serialized certificate. The java.security.cert.X509Certificate implementation that Application Server uses is com.ibm.security.x509.X509CertImpl. It has a constructor that consumes a FileInputStream so that the task of recovering a certificate from a file is a straightforward one. The example uses a lazy initialization approach and caches a reference to the Public Key from the CA Certificate to avoid the need to reload it each time the handler is invoked.


Listing 10: Retrieve the CA certificate from the file system and extract the public key
/**
 * This method returns a reference to the PublicKey contained in the CA 
 * certificate. It uses a lazy initialization technique to delay the 
 * reading of the certificate until it is needed. N.B. this method
 * assumes that the CA_Path initialization parameter has been
 * configured with the full filesystem pathname of the certificate that 
 * will be used as the CA. The CA cert must be stored in the file as a
 * DER-encoded bytestream. A reference to the CA cert is held in the
 * handlers instance state to avoid reading it over and over.
 * @return java.security.PublicKey 
 */
private synchronized PublicKey getCAPublicKey()
	throws
		IOException,
		NoSuchAlgorithmException,
		CertificateException,
		FileNotFoundException,
		UnrecoverableKeyException,
		KeyStoreException,
		HandlerConfigurationException {
			
	FileInputStream fis = null;
	try {
		// recover the CA PublicKey on the first invocation
		if (CA == null) {
			fis = new FileInputStream(getCACertFileSystemPath());
			X509Certificate cacert = new X509CertImpl(fis);
			System.out.println("\n\nCA Certificate Details:\n");
			printCertDetail(cacert);
			setCAPublicKey((PublicKey) cacert.getPublicKey());
		}
	}
	finally {
		if (fis != null)
			fis.close();
	}
	
	return CA;
}

This brings you to the end of the coding details for this routing approach. All that remains now is to deploy the client and provider handlers to the appropriate handler chains.


Deploy the scenario

The deployment steps this articles' solution are very similar to the deployment steps described in the first part of this series. The only exceptions are that the initialization parameters are slightly different for each of the handlers and the names of the jar files and handler classes provided have been changed to reflect their focus on X509 certificates. Table 5 lists the project files that I have included with this paper. You can download them using by clicking on the code icon at the top of this paper.

Table 5: The sample code

Resource Name Description
EchoServiceEAR.ear EchoService Web service implementation. To be deployed in an instance of WebSphere Application Server.EchoService Web service implementation. To be deployed in an instance of WebSphere Application Server.
ServiceClientEAR.ear A test client for the EchoService.
WSGW_X509_RoutingHandlers.jar The JAX-RPC handlers used in this article. To be deployed in the <WAS_install>/lib/ext directory of the application server where <WAS_install> is the root directory of the application server installation. It also contains the MiGBase64 base 64 encoder/decoder used in this article. This jar is provided for deployment convenience as the same jar is included in each of the EAR files.

Software required to test this example

To test this example, you need to have the following software installed. Download links for trial versions of this software are available at the end of this article:

Applying fixes to the Web Services Gateway

The Web Services Gateway application is packaged with WebSphere Application Server Deployment Manager but may be installed in the standalone edition. To do this, however, you will have to install WebSphere Application Server Deployment Manager and apply the fixpack to it in order to get the updated EAR files, and so on, required to install WSGW in a standalone instance of Application Server.
WebSphere Application Server V5.1
  • Deployment Manager Edition and, optionally, the standalone edition
  • Runtime platform for the WSGW
  • Click here for Installation Instructions
WebSphere Application Server Deployment Manager V5.1 Fixpack 1 This fixpack is required for recent updates to the Web Services Gateway application; you will be using the Gateway ear files provided by this fixpack instead of those provided with the GA release.
WebSphere Application Server V5.1 Fixpack 1 Apply this fixpack to gain the benefit of recent product updates if you are using the standalone edition of WebSphere Application Server.
Web Services Gateway with an IBM SOAP over HTTP Channel installed (wsgwsoaphttp1.ear) Click here for Installation Instructions
WebSphere Studio Application Developer V5.1.2 Used to develop applications targeted at WebSphere Application Server V5.1.

Deploy the EchoService to Application Server

The EchoService Web application is contained in the EchoServiceEAR.ear file. Install this EAR file in the WebSphere Application Server instance you are using; it has no special configuration requirements. The endpoint for the EchoService Web service is:

http://<hostname>:<port>/EchoServiceWeb/services/EchoService

<hostname> is the name of the host running the application server and <port> is the port number of the http listener for the application server instance on which the service is installed.

To confirm that the application is installed properly, enter the following URL in a Web browser:

http://<hostname>:<port>/EchoServiceWeb/services/EchoService?wsdl

A successfully installed service responds with its WSDL.

Configure the Web services client deployment descriptor in WebSphere Studio Application Developer

A client application has been provided in the ServiceClientEAR.ear file. It contains:

J2EE Component Name Description
ServiceClientEAR J2EE client enterprise application
ServiceClient J2EE application client holding the web service requestor
WSGW_X509_RoutingHandlers.jar Utility JAR containing the client and service handlers

Application Server provides sample X509 certificates. The deployment configuration described here uses those certificates. You may use your own certificate if you wish.

Import the EAR into WebSphere Studio Application Developer (Application Developer); do not create a utility project for the WSGW_X509_RoutingHandlers JAR file.

Open the Project Navigator view in the J2EE perspective and expand the ServiceClient project as shown in Figure 1. Open the webservicesclient.xml file in the Web services client editor and select the Handlers tab (see Figure 2.


Figure 1: Open the Web services client deployment descriptor
Open the Web services client deployment descriptor

Figure 2: Web services client editor: Handler tab
Web services client editor: Handler tab

Add a handler to the client configuration. The client handler class for this example is called com.ibm.jaxrpc.certrouting.ClientX509CertHandler. Click the Add button and select this class from the list provided. Configure the initial parameters for this handler as follows:

Using your own certificate

If you wish to use your own certificate you need to provide custom values for: KeystorePath, KeystorePswd, and CertAlias.

Parameter name Value
KeystorePath <WAS Install>etc\ws-security\samples\dsig-sender.ks
KeystorePswd client
CertAlias soaprequester
HeaderName subscription
HeaderNamespace http://com.videos-r-us/membership
ActorName MessageRouter

When you are done, the handler configuration should look like the one in Figure 3. Save the changes and close the editor.


Figure 3: Completed client handler configuration
Completed client handler configuration

At this point the client is configured to provide the proper header information to the proxy service. Now it’s time to set up the gateway proxy service.

Set up the proxy mode service in the Web Services Gateway

The administration of the Web Services Gateway is performed using the Gateway Admin Web application. Assume that the Application Server instance is running the HTTP listener on port 9080 (the default). The admin application can be accessed through the URL: http://<hostname>:9080/wsgw/admin/index.html, where you are presented with the page shown in Figure 4.


Figure 4: The Web Services Gateway admin application
The Web Services Gateway admin application

Select the Services:Deploy link in the left-hand menu and fill in the following information:

Selective SOAP parsing

Selective SOAP parsing is a performance option that instructs the Gateway to avoid parsing the body of the message unless it is explicitly touched by a handler.
Gateway Service Name EchoProxyService
Selective SOAP Parsing/Generic Classes selected
Act as a proxy service selected
Channels SOAPHTTPChannel1 selected

Since this is a proxy mode service, there is no requirement to provide information about the target service. It is assumed that a handler will be added to the service with the responsibility to set the target endpoint on a per-message basis. So, with this information entered, you have provided all the necessary deployment information, and your deployment configuration should resemble the one shown in Figure 5. Complete the deployment step by clicking Ok at the bottom of the form. You should see a message box reminding you that you are required to deploy a JAX-RPC handler whose job it is to set the transport.url property for each message to this service.


Figure 5: Completed gateway service deployment
Completed gateway service deployment

The remaining steps take care of deploying and configuring the routing handler; a task which breaks down as follows:

  1. Install the handler class and dependencies in the application server that is hosting the gateway.
  2. Deploy the handler class in the gateway.
  3. Add the handler to the proxy mode service handler chain.

Install the handler class and dependencies in the gateway application server

Before the routing handler can be associated with the proxy mode service, the handler class and its dependencies must be visible to the gateway and channel class loaders. The deployment options available are dependent upon the application server's classloader mode.

If the application server instance running the gateway is configured in single classloader mode, the handler class can be in any EAR installed in the application server. If the application server is configured in multiple classloader mode (the default), the handler must be placed in one of the following locations:

  1. Use a JAR file placed in <WAS_install>/lib or <WAS_install>/lib/ext directories, where <WAS_install> refers to the directory where Application Server is installed.
  2. Deploy the handler classes to the <WAS_install>/classes directory.
  3. Use a JAR file placed in a WebSphere shared library associated with the channel and gateway enterprise applications.

I use the first approachfor this example. Place the WSGW_X509_RoutingHandlers.jar file into the <WAS_install>/lib/ext directory.

Deploy the handler in the gateway

The significance of the handler name

When deploying a handler in the gateway, the handler deployment carries the parameters that will be used each time that handler occurs in a handler chain. If several instances of the same handler class are required, each with different configuration parameters, the handler class may be deployed several times with different names.

Select the Deploy link under the Handlers heading of the Gateway admin Web Application. You will be prompted for the details of the handler you wish to deploy. The parameters to use for this example are as follows:

Handler Name ServiceRoutingHandler
Handler Class com.ibm.jaxrpc.certrouting.X509CertRoutingHandler
Init Parameter name:value RoutingConfig:/routing.properties
Init Parameter name:value HeaderName:subscription
Init Parameter name:value HeaderNamespace:http://com.videos-r-us/membership
SOAP header QName {http://com.videos-r-us/membership}subscription
SOAP Role MessageRouter

When you have entered this information your deployment screen should resemble the one shown in Figure 6. Click Ok to complete the deployment and proceed to the next step.


Figure 6: Completed gateway handler configuration
Completed gateway handler configuration

Add the handler to the proxy mode service handler chain

Now that the handler is deployed to the Gateway, it is available to be added to the handler chains of any deployed gateway services. Select the List link under the Services sub-menu of the Gateway admin application; you should see EchoProxyService in the list of available services. Click the EchoProxyService link and scroll down to locate the Channels list for the service (see Figure 7. Select Edit JAX-RPC handler configuration for the SOAPHTTPChannel1 channel.


Figure 7: EchoProxyService channels list
EchoProxyService channels list

Find the ServiceRoutingHandler in the Add JAX-RPC Handler list and add it to the handler configuration. At this point the configuration page should appear similar to Figure 8.


Figure 8: Completed proxy service handler chain
Completed proxy service handler chain

Complete the configuration

The routing handler uses a properties file to map subscriber common names to target service endpoints. In the configuration instructions provided above, the RoutingConfig property was assigned the value /routing.properties. With this configuration, place a properties file called routing.properties in the <WAS_install>/properties directory containing information similar that shown in Listing 11.


Listing 11: Sample routing properties file
   #sample Service Level routing table
   SOAPRequester=http://localhost:9082/EchoServiceWeb/services/EchoService
   SOAPRequester2=http://localhost:9083/EchoServiceWeb/services/EchoService

In this case, the two entries cause requests from the subscribers with the CNs SOAPRequester and SOAPRequester2 to be mapped to ports 9082 and 9083 on the server hosting the Gateway instance. You should make sure that the URLs are adjusted to reflect the particulars of the service(s) you have deployed.

Please note that the sample certificates provided with Application Server do not include a certificate with a CN of SOAPRequester2; it is used here for illustration purposes only. However, the client has been configured to use a certificate with a CN of SOAPRequester so that the first entry in this file will be used.

Test the gateway proxy service

Once the properties file is created and the foregoing configuration is completed, you can test the service using the ServiceClient project you imported into Application Developer earlier in this exercise.

The main client class is called test.EchoServiceClient. As provided, this class targets its request at the following endpoint:

http://localhost:9081/wsgwsoaphttp1/soaphttpengine/urn%3Aibmwsgw%23EchoProxyService

This URL assumes that the client is running on the same machine as the server, and that the application server HTTP listener is listening on port 9081. If your application server HTTP listener is running on a different port or machine, edit this URL to point to the appropriate location.


Figure 9: Sample client application
Sample client application

Once the URL points to your Gateway instance, select the application client class in the Project Navigator of the WebSphere Studio J2EE Perspective (see Figure 9), and select the Run > Run As > WebSphere V5.1 Application Client menu item. This will launch the client and send a request to your proxy service, which resembles Listings 12 and 13 in this sidefile.

The sample messages were captured using the TCPMonitor feature of Application Developer to display the message traffic between the client application and the Web Services Gateway.


Summary

This paper showed you how you can use X509 certificates to provide routing criteria for proxy mode services in the IBM WebSphere Web Services Gateway. X509 certificates provide the following features that are desireable for some routing applications:

  • They are non-forgeable.
  • They are revocable.
  • They carry the issuer's signature.
  • They contain information in the subject's distinguished name, which can be used as a key into a routing table.

To be effective, this approach requires that the network link between the requestor and provider be secure and that the subscriber not provide third party access to their certificate. If either of these conditions is not met, there is a chance that the certificate of one subscriber might be used by a party that is not the subject of the certificate. The use of transport-level security, such as SSL, prevents the certificate from being stolen from a message, but the subscriber must not make his keystore's content accessible to others.

Combining the techniques presented here with a distributed resource such as an RDBMS to hold mapping information turns the mapping example presented here into a very scalable and robust Web services routing solution.



Download

DescriptionNameSizeDownload method
Sample codews-routing2code.zip83 KB HTTP

Information about download methods


Resources

Web Services Gateway

JAX-RPC Handlers

Download IBM WebSphere Free Trial Products / Fixpacks

Web Services Specifications

X509 Certificates

Other resources

  • Browse for books on these and other technical topics.

  • Want more? The developerWorks SOA and Web services zone hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications.

About the author

Michael Ellis is a solution architect on the IBM Software Services for WebSphere team and lives in Ottawa, Canada. He specializes in Web services, XML, J2EE technology, and object-oriented architecture and design. You can contact him at msellis@ca.ibm.com.

Comments



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=32184
ArticleTitle=Employ the IBM WebSphere Web Services Gateway, Part 2
publish-date=12142004
author1-email=msellis@ca.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers