Web Services Enhancements 1.0 and Java Interoperability, Part 2


Simon Guest
Microsoft Corporation

Christopher St. John
The Mind Electric

May 2003

Applies to:
   Microsoft&174; Windows&174; XP Professional, Windows 2000 Professional, Windows 2000 Server, Windows 2000 Advanced Server, or Windows Server 2003
   Microsoft .NET Framework 1.0
   Web Services Enhancements (WSE) 1.0 for Microsoft .NET
   WS-Security specification
   Compliant Java 2 Standard Edition (J2SE) SDK 1.3
   GLUE Professional 4.0.1 from The Mind Electric
   SOAP Toolkit 3.0
   X.509 Certificates

Summary: Covers interoperability between Web Services Enhancements 1.0 for Microsoft .NET and Java and shows how the WS-Security specification and implementation can be used to securely sign a Web service call from Microsoft .NET to Java and vice versa. GLUE Professional 4.0.1 from The Mind Electric enables WS-Security functionality for Java. Part 1 of this series showed the same sample using IBM Web Services Toolkit (WSTK) 3.2.2. Includes downloadable code samples. (17 printed pages)

Download the WSEJavaInteropP2.msi code sample.


Required Software and Skills to Run the Code Samples
Installing the Sample Code
Preparing the Environment
Using WS-Security with GLUE Professional 4.0.1
Using the SOAP Trace Utility to Examine the Results

Required Software and Skills to Run the Code Samples

The following software and skills are required to run the samples in this article.

  • Microsoft. NET Framework 1.0 or higher

    A basic working knowledge of the .NET Framework and J2SE SDK 1.3 or higher is required. It is assumed that you understand the principles behind writing and compiling an application for both platforms, and that you have a good understanding of the language syntax for both C# and Java.

  • Web Services Enhancements (WSE) 1.0 for Microsoft .NET

    For the WSE 1.0 sample applications, the following configuration is assumed: Microsoft&174; Windows&174; XP Professional, Windows 2000 Professional, Windows 2000 Server, Windows 2000 Advanced Server or Windows Server 2003 RC2 installed with v1.0 or higher of the .NET Framework and the Microsoft Web Services Enhancements 1.0 download. You should be relatively familiar with the WS-Security samples that are shipped with WSE, as they provide the bases for the samples here.

  • Compliant Java 2 Standard Edition (J2SE) SDK, version 1.3.1 or higher
  • GLUE Professional 4.0.1 from The Mind Electric

    GLUE Professional 4.0.1 should be installed to the default C:\TME\GLUE directory in order for the samples to work.

By default, all of the sample code has been designed to run on a single machine with the following port settings for each sample:

  • Microsoft IIS / Microsoft ASP.NET – localhost:80
  • GLUE Professional 4.0.1 – localhost:8004

This article demonstrates how the code itself runs without having two or more tiers set up for installation. Taking the sample code and running across multiple machines requires replacing the references to 'localhost' within the configuration and sample code. Many of these can be found in the final section of this article, where we use the SOAP Trace Utility to monitor the calls between the two.


This article shows a working example of using the WS-Security specification and implementation to sign a Web service request with X.509 certificates between Microsoft .NET (using WSE) and Java (using GLUE Professional). This article does not show encryption, which will be featured in a later article.

So, what is the requirement behind using WS-Security for signing Web service requests between .NET and Java? The ability to sign a Web service request guarantees that the message contents have not been altered during transit. Using a digital certificate, it is possible to sign a Web service request with a private key, so that it can be validated with the corresponding public key.

Until now, there have been two options for securing Web services: one at the transport level (using SSL), and another at the application level, using a custom security mechanism. Both of these options, while technically effective, have some limitations or drawbacks for adoption.

Security at the transport level using SSL can guarantee the integrity of a Web service request by securing the underlying transport layer (HTTP). SSL is used both to encrypt the link and to validate the client and server using certificates.

One of the main problems in using SSL to secure Web services is that the security is only effective from a single point to another. As the SSL communication is based on the transport, once the end point has been reached, this method of securing the message is no longer applicable. For example, if I send a message from Client A to Server B, I can use SSL to secure the link. If, however, I send a message from Client A to Server C—and it has to go via Server B—there is no easy way to ensure the security of the message using SSL through this intermediary.

It is also possible to develop a custom security mechanism where the contents of the message and headers were signed at the client and checked at the server. This would overcome the transport security issue, but in the end this would be a custom solution. Organizations that wish to secure Web services made public to other organizations would have to ensure that the same technology is used at each of the end points.

WS-Security solves both of these problems by providing an application-based way of signing the Web service (to avoid issues that can arise when securing at the transport layer) using an openly published standard that can be referenced and adopted by customers, system integrators, and vendors.

To help promote this standard, this article shows a series of Web signing samples between two implementations of WS-Security: one based on Microsoft Web Services Enhancements 1.0 for Microsoft .NET and the other based on GLUE Professional 4.0.1.

The setup that we will be showing is similar to the following:

Figure 1. Microsoft .NET client using WSE 1.0 to call .NET-connected and Java Web services

As in Figure 1, with each of the toolkits, we will show two sets of examples: first, a .NET client calling the WSE Web service and a GLUE Professional Web Service, and second, a Java client calling the WSE Web service and the GLUE Professional Web service, as shown in Figure 2.

Figure 2. Java client using GLUE Professional to call .NET-connected and Java Web services

This article is not intended to be a comparison of any of the toolkits (given the early stages of the specifications, this would not be fair), and is instead intended to show interoperability with Web services between Microsoft .NET and Java.

The samples shown here are designed to replicate the 'Add Integer' sample that ships with the WSE 1.0 release. You may wish to go through the WSE 1.0 sample code before trying out any of the code samples used here.

Installing the Sample Code

All of the samples are contained in a downloadable .msi file. By default, the samples install to a C:\wse-interop directory. For the purposes of running the sample code and following this article, I recommend that you do not change the directory name.

Note   The samples provided in Part 2 are cumulative, and also include the sample code from Part 1 (IBM WSTK 3.3.2 Samples). Therefore, you will be prompted to uninstall the Part 1 sample code before installing this Part 2 sample code.

After you have installed the sample code, the \wse-interop sample directory contains a number of subdirectories:

  • dotNETWebService: This contains the .NET-connected Web service that will be called by the WSE and Java clients.
  • JKS: This directory contains the Java Key Store that will be used for signing the Web service requests.
  • GLUE: This directory contains the sample code for GLUE Professional 4.0.1.

Preparing the Environment

Before we can run the sample code, we need to set up the environment on which the Web services are going to run. This includes creating the .NET-connected Web service, configuring GLUE Professional, and setting up certificates that are going to be used for the samples.

Setting Up the .NET-Connected Web Service

Following installation, the .NET-connected Web service can be found in the C:\wse-interop\dotNETWebService directory. In order for the Web service to be able to process requests, we must first build the solution and create a virtual directory within Microsoft Internet Information Services (IIS).

In order to build the solution, run the Build.bat script from the C:\wse-interop\dotNETWebService directory. This build script compiles the Web service. The Build.bat script uses the command line C# compiler (Csc.exe). You may want to ensure that this file is in your path. For version 1.0 of the .NET Framework, Csc.exe can be found in the C:\Windows\Microsoft.NET\Framework\v1.0.3705 directory.

Alternatively, you may also take the entire contents of this directory into Microsoft® Visual Studio® .NET and compile from there.

To create the IIS virtual directory

  1. To run the Internet Information Services administrative tool, on the Administrative Tools menu, click Internet Information Services (or click Start, click Run, and then type Inetmgr.exe). The Internet Information Services Manager dialog box opens, as shown in Figure 3.

    Figure 3. The Internet Information Services console

  2. In the left pane of the Internet Information Services Manager dialog box, right-click Default Web Site. On the shortcut menu, click New..., and then click Virtual Directory. The Virtual Directory Creation Wizard opens. In the wizard, click Next.
  3. Under Alias: type WSEX509Interop as shown in Figure 4. The exact name and case for this alias is important, as it is referenced in the sample code. Although you can change it later, it is recommended that you use this name in order to get the samples working.

    Figure 4. Entering the alias for the virtual directory

  4. Click Next to display the directory location, and type C:\wse-interop\dotNETWebService as shown in Figure 5. This is the location of the sample files.

    Figure 5. Setting the location for the .NET-connected Web service

  5. Click Next and accept of the other defaults until the wizard is completed.

The .NET-connected Web service is now configured. Use Microsoft Internet Explorer to browse to http://localhost/WSEX509Interop/Service1.asmx and test the publication. The Web service publishes an AddInt WebMethod. This WebMethod cannot be called from Internet Explorer, however, as it requires a call via a SOAP request.

Building the Sample Code for GLUE Professional 4.0.1

The C:\wse-interop\GLUE\X509Signing directory contains the sample code for GLUE Professional 4.0.1. Within this directory are three subdirectories: dotNETClient, JavaClient, and JavaWebService.

To install the sample code, do the following:

  1. Navigate to the C:\wse-interop\GLUE\X509Signing\GlueWebService directory and run the Build.bat file to compile the sample code. For ease of compilation, I have included a Setenv.bat file which sets the correct CLASSPATH as required—you may want to adjust this to reflect some of your own settings.
  2. Navigate to the C:\wse-interop\GLUE\X509Signing\GlueClient directory and run the Build.bat file to compile the client-side sample code.

The configuration for GLUE Professional is now complete.

Configuring the Certificate Stores

In order to sign SOAP messages being sent to or received from a Web service hosted on either .NET or through GLUE Professional using these samples, we need a process to create X.509 certificates.

We will be dealing with two different certificate infrastructures. The .NET Framework and WSE code uses the built-in Windows certificate infrastructure and the client will access certificates from the current user's certificate store. The Java code uses a Java Key Store to hold certificates and corresponding key information.

Requesting and importing a certificate into Windows

In order to request a certificate for the Windows store, you must have access to a Certificate Authority (CA). This may be a public CA that you have access to, or you can also use Certificate Services that ship with Windows 2000 Server.

For more information about requesting a certificate via Certificate Services, refer to the Microsoft Platform SDK.

To check the presence of a valid certificate

  1. To run the Microsoft Management Console, on the Start menu, click Run, and type Mmc.exe.
  2. On the File menu, click Add/Remove Snap-In, and then click Add.
  3. Select Certificates, click Add, and then select My User Account. Click Close twice to return to the console.
  4. Expand the Certificates/Personal Certificates/Certificates tree. Here you should see a list of certificates specific to the user account of the logged-in user. If you do not see a certificate in this store that can be used for signing, you will need to request one from an available CA.

Creating an entry in the Java Key Store

The Java sample code uses a certificate key that is stored in a Java Key Store (JKS). A default JKS, called Keystore.db is installed with the samples, and can be found within the C:\wse-interop\JKS directory.

To administer the JKS, a tool called Keytool.exe (shipped with the J2SE SDK) is used.

To list the contents of the current Keystore.db file, navigate to C:\wse-interop\JKS and run the following command:

keytool –list –keystore keystore.db

The default password for this key store is password (lower case). This command returns the following:

Keystore type: jks
Keystore provider: SUN

Your keystore contains 0 entries:

As shown here, there are no certificates or keys in the Java Key Store. In order to create a key that can be used for signing, use the following command, exactly as shown:

keytool -genkey -keystore keystore.db -alias test –keyalg rsa

Enter the key store password and complete the list of certificate questions presented (Fullname, organization, locality, etc.). Although the alias of the key must be called test for the sample code, these other details can be your own and are not specific to the sample code. At the end of the questions, make the password of the test key the same as the keystore password by pressing the Enter key.

Repeat the keytool –list command previously shown. The test key that we have created should now be listed.

test, Sun Jan 12 14:29:46 PST 2003, keyEntry,
Certificate fingerprint (MD5): 91:43:81:C0:C9:22:04:27:22:27:A5:1D:E1:60:E5:8D

The certificate stores are now complete. With these configured and the sample code built, we now need to import a trusted certificate for GLUE Professional.

Using WS-Security with GLUE Professional 4.0.1

In order to show request signing with GLUE Professional, let's run the sample code to see how it works.

Starting the GLUE Professional Web Service

The sample code in the GLUE Professional Web Service directory (C:\wse-interop\GLUE\X509Signing\GlueWebService) contains an AddInt Web Service that requires a valid X.509 certificate in order to be accessed. This can be found in the Service1.java file.

There are two options for hosting this Web service. The classes can be packaged into a WAR file that can be deployed to any Java-based Web server, or we can use an internal application server that is shipped with GLUE Professional. For the purposes of this sample, we will be using the latter, but you should consult the documentation that comes with GLUE Professional in order to review the options available.

To start the GLUE Web Service using the built in application server:

  1. Navigate to the C:\wse-interop\GLUE\X509Signing\GlueWebService directory.
  2. Run Setenv.bat if the required JARs need to be added to your CLASSPATH (again, this may need to be tailored for your own environment).
  3. Run Server.bat to start the server.

If all is successful, a separate command prompt window will open displaying the following to indicate that the server is operational:

[STARTUP] GLUE professional 4.0.1 (c) 2001-2003 The Mind Electric
[STARTUP] http server started on http://localhost:8004/GLUEX509Interop
Note   The URL will be replaced with the IP address of your machine instead of localhost.

Calling with the .NET Client

The .NET client can be found in the C:\wse-interop\GLUE\X509Signing\dotNETClient directory. It calls both the WSE and GLUE Professional Web services, and signs the request.

If you have not done so already, build the client by running Build.bat in this directory and run the Client.exe that is created. As with the sample code supplied with WSE 1.0, you will need to supply the A and B parameters. For example:

CLIENT /a 40 /b 50

The first thing the client does is request the X.509 certificate to use to sign the request, and then the Select Certificate dialog box opens as shown in Figure 6.

Figure 6. Select Certificate dialog box

Select the certificate to use to sign this request. This should be the same certificate as the one that was imported into the Java Key Store in our previous steps.

If all is successful, the client sample generates the following output:

Key Name                       : C=US, S=WA, L=Redmond, O=Microsoft, OU=.NEAT, C
N=Simon Guest, E=sguest@microsoft.com
Key ID of Certificate selected : 67WE7bDjBnbsb2JUEFvo7qi/iUg=

Calling the WSE 1.0 X509 Service...
Calling the GLUE X509 Service...

The details of the certificate selected are displayed. Two Web service requests are made: the first to the WSE Web service, and the second to the GLUE Professional Web service. Both these requests are signed with the X.509 certificate presented earlier.

Calling with the GLUE Professional Client

As with the WSE sample code, the GLUE client also runs from the command line.

The sample code for the client is found in the C:\wse-interop\GLUE\X509Signing\GlueClient directory. To build the sample, run the Build.bat file from this directory.

To run the client, use the same command line used for the .NET client:

CLIENT /a 40 /b 50

If all is successful, the following displays:

Calling the WSE 1.0 X509 Service...
Calling the GLUE X509 Service...

How the WSE 1.0/GLUE Professional 4.0.1 Sample Works

The key to getting the WSE/GLUE sample to work is in understanding how the deployment works. Here, we look at the server and client configuration for the GLUE Professional sample code, and see how that interoperates with WSE.

GLUE Professional sample Web service configuration

Similar to the WSE example, using GLUE Professional, we do most of the configuration in code instead of configuration files. It is also possible to configure the application via a Config.xml and service descriptors, the details of which are in the documentation that is supplied with GLUE Professional.

The GLUE Professional Web Service is split into two parts: Service1.java and Server.java.

Service1.java contains the default AddInt function that is going to be exposed. Server.java contains the code to publish the Web service and apply the WS Security settings.

Following is the Server.java file:

HTTP.startup( "http://localhost:8004/GLUEX509Interop" );

WSSContext wss = new WSSContext();
ProxyContext proxyContext = new ProxyContext();

WSSSignature sigSpec= new WSSSignature(new ElementReference("/soap:Envelope/soap:Body"));
wss.in.addAuthenticator(new X509NullAuthenticator());
wss.in.addGuard(new SignatureGuard(sigSpec));

Registry.publish( "Service1", new Service1(), proxyContext );

The HTTP application server is started, and a new WSSContext and WSSSignature is created. The key lines to implement the WS Security portion of the Web service are:

wss.in.addAuthenticator(new X509NullAuthenticator());
wss.in.addGuard(new SignatureGuard(sigSpec));

These two add an authenticator (of type X509NullAuthenticator, intended for testing and accepting all incoming requests) and a guard to ensure that only signed requests ever make it through.

Finally, the service itself is published with the Registry.publish command.

GLUE Professional sample client configuration

The GLUE client works in a similar way to the WSE client in that the proxy files to access the Web services were generated beforehand with the WSDL2JAVA tool in the C:\TME\GLUE\bin directory of the toolkit.

The proxy for the GLUE Professional Web service is found in the C:\wse-interop\GLUE\X509Signing\GlueClient\glueproxy subdirectory. The proxy for the WSE can be found in the C:\wse-interop\GLUE\X509Signing\GlueClient\wseproxy directory.

The client code to call these proxies, and ultimately the Web Services, can be found in the Client.java file in the same directory:

String WSEurl = "http://localhost/WSEX509Interop/Service1.asmx?WSDL";
String GLUEurl = "http://localhost:8004/GLUEX509Interop/Service1.wsdl";

ProxyContext proxyContext = new ProxyContext();

KeyStore keyStore = loadKeyStore("c:\\wse-interop\\JKS\\keystore.db", "password");
PrivateKey privateKey = (PrivateKey) keyStore.getKey("test","password".toCharArray());
X509Certificate cert = (X509Certificate) keyStore.getCertificate("test");

WSSContext wss = new WSSContext();
WSSSignature signatureSpec = new WSSSignature(new 

System.out.println("Calling the WSE 1.0 X509 Service...");
WSEProxy.IService1Soap wseService = 
(WSEProxy.IService1Soap)Registry.bind(WSEurl,WSEProxy.IService1Soap.class, proxyContext);

System.out.println("Calling the GLUE X509 Service...");
GLUEProxy.IService1 glueService = 

The client code works by first creating a new context and then loading the key store. The key store is responsible for storing certificates that can be used to sign the request. The alias and password specify the details of the certificate that is selected.

To create the call, a WSSContext and WSSSignature are created. The signature is configured with the certificate from the keystore, and both are applied to the current Web service context.

Both the WSE and GLUE Web services are then called with the same proxy context.

WSE sample client configuration

The configuration for the WSE sample client is also done in code, and follows a similar pattern.

In order to call the GLUE Web service, the WSDL.exe tool generates a proxy class similar to the WSDL2JAVA tool that was used to create the GLUE proxies.

The WSDL.exe tool also creates the WSTKProxy.cs file that can be found in the C:\wse-interop\GLUE\X509Signing\dotNETClient directory. As with the generic WSE samples, this proxy file was modified to extend WebServicesClientProtocol from the Microsoft.Web.Services namespace, and adjusted to contain the localhost:8080 reference to the GLUE Web server. A similar proxy file (WSEProxy.cs) was also created for the WSE Web service.

The main class for the .NET client, Client.cs contains the required calls for both the WSE and GLUE Web services.

WSEProxy wp = new WSEProxy();
GlueProxy gp = new GlueProxy();
SoapContext wpReqContext = wp.RequestSoapContext;
SoapContext gpReqContext = gp.RequestSoapContext;

X509SecurityToken token = GetSecurityToken("");
if (token == null)
       throw new ApplicationException("No key provided for signature.");

wpReqContext.Security.Elements.Add(new Signature(token));

gpReqContext.Security.Elements.Add(new Signature(token));
gpReqContext.Path.MustUnderstand = false;

Console.WriteLine("Calling the WSE 1.0 X509 Service...");

Console.WriteLine("Calling the GLUE X509 Service...");

These calls should look familiar to anyone who has run any of the sample code that comes with WSE 1.0. One addition that was made was the following line:

gpReqContext.Path.MustUnderstand = false;

By default, the WSRP header contains a MustUnderstand=1 SOAP header, which works fine with WSE based Web services, but throws an exception when trying to call the GLUE Professional Web service (this part of the specification may not have been implemented as of yet). To get around this problem, this line of code removes the requirement for the Web service to understand the header for the Path (a MustUnderstand = 1 still exists for the WS Security section, however).

WSE sample Web service configuration

The WSE Web service itself is again very similar to the default samples, with the main portion of the exposed method located in the Service1.asmx.cs file, in the c:\wse-interop\dotNETWebService directory.

The AddInt class itself looks as follows:

        public int AddInt(int a, int b)
            SoapContext requestContext = HttpSoapContext.RequestContext;
            if (requestContext == null)
                throw new ApplicationException("Only SOAP requests are permitted.");

            if ( !IsValid(requestContext) )
                throw new SoapException(
"The security information supplied was not valid.",
                    new System.Xml.XmlQualifiedName("Bad.Security",

            return a+b;

As shown here, we check in code—whether or not the request from the client has been signed—with an IsValid method, also in this class.

Using the SOAP Trace Utility to Examine the Results

This article outlines some initial samples for showing WS-Security interoperability between WSE and GLUE Professional. If you are like me however, you may have a burning desire to know what information is being sent underneath the covers.

To enable this, we can use the SOAP Trace Utility that comes as part of the Microsoft SOAP Toolkit 3.0 (the SOAP Toolkit actually provides SOAP and Web service functionality for non-.NET-connected applications). You can download the SOAP Toolkit 3.0.

Once the SOAP Toolkit is installed, the Trace Utility that ships with the toolkit can be configured to listen on one port and redirect to another. Doing this, however, requires some slight changes in the configuration of these samples, which is outlined below.

Using the SOAP Trace Utility with WSE and GLUE Professional

To enable the SOAP Trace Utility to trap calls between WSE and GLUE Professional

  1. Open the Trace Utility and create two new formatted traces (on the File menu, click select New Formatted Trace). One of the traces should listen on port 8005 and redirect to port 8004. The other trace should listen on port 81 and redirect to port 80.
  2. Edit the Server.java file (found in C:\wse-interop\GLUE\X509Signing\GlueWebService) by replacing the localhost:8004 to localhost:8005 in the Http.Startup line, and remove the comment from the following line:
  3. In the C:\wse-interop\GLUE\X509Signing\GlueClient\GLUEProxy directory, in the Service1Helper.java file, replace localhost:8004 with localhost:8005.
  4. In the C:\wse-interop\GLUE\X509Signing\GlueClient\WSEProxy directory, in the Service1Helper.java file, replace localhost:80 with localhost:81 .
  5. In the Client.java file (found in C:\wse-interop\GLUE\X509Signing\GlueClient), for the two initial URIs, replace localhost:8004 with localhost:8005 and localhost:80 with localhost:81.
  6. Edit WSEProxy.cs and GLUEProxy.cs in the C:\wse-interop\GLUE\X509Signing\dotNETClient directory. Replace each occurrence of localhost:80 with localhost:81 in WSEProxy.cs , and each occurrence of localhost:8004 with localhost:8005 in GLUEProxy.cs
  7. Rebuild the sample code, and restart the GLUE Services as described earlier.


This article provides insight and a working code sample to show how WS-Security can be used to apply X.509 signatures to requests between Web services based on Web Services Enhancements 1.0 for Microsoft .NET, and Web services based on the Java platform using GLUE Professional 4.0.1 from The Mind Electric. This provides a way to help ensure that Web service requests achieve end-to-end security in both applications and services.

In future articles in this series, I'll show how to build on this sample code with more operations and specifications as they are released.