Thursday, May 1, 2008

Gartner lists wso2 as a cool vendor in web technologies

WSO2 has been chosen as a cool vendor in web technologies by Gartner. More information can be found at Pauls' blog

Axis2 session management - Transport session

Apache Axis2 provides session handling capability using 4 session scopes; request, soapsession, transport and application. I have already blogged about application scope a few months ago.

Axis2 transportsession uses transport level session management techniques to manage sessions of a Web service. Life time of a session is governed by the underlined transport, not by Axis2 itself. If a service is deployed in a transportsession scope, then, there will be service instances for each of the transport session.

You can read my recent Knowledge base post on how to manage sessions with transport session scope here at wso2 oxygen tank.

Saturday, April 19, 2008

Data services and mediating SOAP messages with Synapse DBReport mediator

Apache Synapse is an ESB that has been designed to be simple to configure, very fast, and effective at solving many integration and gatewaying problems. It comes with a set of ready-to-use transports and mediators.
Visit Apache synapse web for more information about message mediation.

WSO2 data services is a convenient mechanism to provide a Web service interface for data stored in some data source. Data sources such as relational databases, CSV files & MS-Excel files can be easily service enabled using Data Services.
You can find more details about WSO2 Data services from here

I got a lot of positive feedback about my previous posts (securing web services) since they helped beginners to understand and experiment with simple examples without digging in to complex details.
I thought to describe a simple scenario which demonstrates the usage of data services and synapse together. I hope the following step-by-step instructions will help most of the novice users to get started with WSO2 data services and Apache synapse in a fairly simple manner.

I am going to use the following open source software tools in this demonstration. So, please make sure you have configured them in your environment.

Apache Synapse 1.1.1 (Download)
WSO2 WSAS 2.2.1 (Download)
Apache derby 10.3.2.1 (Download)
Apache JMeter (Download)

Scenario:
A SOAP request will be sent to WSO2 WSAS to get the net salary of an employee which resides in a database. The messages will be transferred via synapse. The response SOAP message will be subjected to mediation by synapse DBreport mediator. In which, the net salary of a different employee will be updated by evaluating the net salary of the requested employee. In other words, we will get the net salary of employee A and instruct synapse to update employee B's net salary to the net salary of employee A.

Step 1

Database preparation

We should prepare the necessary database and tables as the first step. Apache derby will be used in this example.
  • Start derby network server
Go to derby_home/bin and run startNetworkServer.bat
  • Create a database
start ij utility (derby_home/bin/ij.bat) and enter the following command.
CONNECT 'jdbc:derby://localhost:1527/employeedb;user=wsas;password=wsas;create=true';
  • Create a table and insert data
create table employee(name varchar(10), empid varchar(10), netsalary double);
insert into employee values ('Sean','1',1000.00);
insert into employee values ('John','1',3000.00);
insert into employee values ('David','1',2000.00);

Next, I'm going to create a data service using the above data source. Data services allow users to expose the relational data as web services so that they can be accessed and manipulated in programming language independent manner.

Step 2

Create a data service

Please make sure the derby client driver is available in your WSAS instance. Copy derby_home/lib/derbyclient.jar to WSAS_HOME/lib.

Install WSO2 WSAS if it is not already installed. start WSO2 WSAS using WSAS_HOME/bin/wso2wsas.bat

Access WSAS management console (https://localhost:9443) where we can configure our data service through UI.

Go to 'Services and service group management' page and click on 'Define data service' link. You will get a page as given below.


Enter 'Synapsedataservice' as the service name. Select 'RDBMS' as the data source. A pop-up window will be displayed where we can configure data base details.
Driver Class = org.apache.derby.jdbc.ClientDriver
JDBC URL = jdbc:derby://localhost:1527/employeedb
user name= wsas
password = wsas

Click on the 'Next' after configuring data source details. The second step of the data service configuration will be displayed. Click on 'New query' button. The following pop-up window will appear.


Enter the following details in the above window.

Query ID=Empsal
SQL Statement =
select * from employee where name = ?


Click on ' add new input mapping' and enter followings.
Name=name
sqlType
=STRING

Grouped by element = employees
Row name = employee

Click on 'add new Output mapping' and enter the following values.
Mapping Type = element
Output field name = name, SQL column Name = name
Output field name = empid, SQL column Name = empid
Output field name = netsalary, SQL column Name = netsalary

After entering all of the above values, click 'Next' button in the data service - step 2.

Step 3 of the wizard will be displayed. Click on 'Add new operation' button and enter the following values.
Operation Name = EmpSalOp
Query= Empsal

Click 'Finish' to deploy the data service.

Step 3

Test the data service

You can test your data service simply by invoking it in RESTful manner. Issue the following url.
http://localhost:9762/services/Synapsedataservice/EmpSalOp?name=Sean

You should get the details of employee, Sean.

<datas2:employees>
<datas2:employee>
<datas2:name>Sean</datas2:name>
<datas2:empid>1</datas2:empid>
<datas2:netsalary>1000.0</datas2:netsalary>
</datas2:employee>
</datas2:employees>

You should observe the simplicity of exposing relational data using WSO2 Data services. Lets see how we can use Apache Synapse to do some mediation in messages passing through it.

Step 4

Creating Synapse configuration

Install Synapse1.1.1 (just unzip the binary distribution). Synapse provides a xml configuration file to define the mediation rules using synpase configuration language. Open Synapse_home/repository/conf/synapse.xml.

Remove the existing contents of that file and add the following configuration.

<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="main">
<in>
<send>
<endpoint>
<address uri="http://localhost:9762/services/Synapsedataservice"/>
</endpoint>
</send>
</in>
<out>
<log level="custom">
<property name="text"
value="** Reporting to the Database **"/>
</log>
<dbreport>
<connection>
<pool>
<driver>org.apache.derby.jdbc.ClientDriver</driver>
<url>jdbc:derby://localhost:1527/employeedb;create=false</url>
<user>wsas</user>
<password>wsas</password>
</pool>
</connection>
<statement>
<sqlupdate employee set netsalary=? where name='John'</sql>
<parameter expression="//datas2:employees/datas2:employee/datas2:netsalary"
xmlns:datas2="http://ws.wso2.org/dataservice" type="DOUBLE"/>

</statement>
</dbreport>
<send/>
</out>
</sequence>
</definitions>

Here, the request message pass through synapse will be directed to the data service endpoint without doing any mediation. It is defined in the <in/> element.
The SOAP response will be transferred via two different mediators.

Log - when the soap response reaches synapse, it just logs the message as defined.
dbreport - writes information to a Database, using the specified insert SQL statement.

In this configuration, we evaluate the response SOAP message using an XPath expression and get the net salary of the employee. Then we update the net salary of employee John with that.

Now you can start synapse with the above configuration by running synapse.bat.

To see how this works, we need to send a SOAP request message to Synapse. Apache Jmeter can easily be used to transmit a soap message.

Step 5

Test message mediation

Install jmeter in your system (Just unzip jmeter binary distribution). Run jmeter.bat.
Create a thread group and add SOAP/XML-RPC request sampler. (Please read http://wso2.org/library/1085 if you are not familiar with testing web services using Jmeter)

Add the following soap request in to the SOAP/XML-RPC data section.

<soapenv:envelope soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:body>
<axis2ns5:empsalop axis2ns5="http://ws.wso2.org/dataservice">
<name>Sean</name>
</axis2ns5:empsalop>
</soapenv:body>
</soapenv:envelope>

You may have wondered how I captured the above request Soap message. There are several different approaches.
1. write a java client and invoke the data service. Capture the message using apache Tcpmon
2. Enable Soap Tracing in the WSAS management console. As we did above, invoke the service in RestFul manner. Then access the SoapTracer in WSAS management console and copy the soap request. (This will be the easiest method)

Enter 'http://localhost:8080' as the URL in SOAP/XML-RPC request.
Enable 'Send SoapAction' and enter 'urn:EmpSalOp'

If everything is correct, you should see the following in your Jmeter console.



Run the sampler. You may check the synapse console where you can monitor the message mediation.

Lets see whether the net salary of John is updated as expected. Open the ij utility of Derby and issue the following SQL statement.
select * from employee;

You should notice that the net salary of John and Sean are same.

In this post, we looked at the WSO2 data services and Apache Synapse using a simple scenario. You will be able to improve the above scenario by applying more mediation rules.


Saturday, March 15, 2008

Invoking a public web service programmatically using WSO2 WSAS

A Web service is defined as "a software system designed to support interoperable interaction over a network." Web services are referred to as Web APIs that can be accessed over a network and executed on a remote system hosting the requested services.
There are many publicly available web services which can be invoked remotely using client applications. www.webservicex.net is such a site that hosts different types of public web services.
I'm going to demonstrate how such web service is invoked programmaticaly using WSO2 Web services application server (WSO2 WSAS)

WSo2 Web services application server provides set of tools to interact with web services. You can download the latest version from here.

I'll use a public instance of WSO2 WSAS to generate client side code (stub). You will also try out WSAS public instance before downloading the server.

Step 1

First, we may access webservicex to identify a suitable web service which can be invoked remotely.
You may see 'Top Web Services' at the left menu of the home page. Click on 'Stock Quote'
You will get a page with stock quote service details.

Make a note of the followings;
Endpoint http://www.webservicex.net/stockquote.asmx
WSDL Location http://www.webservicex.net/stockquote.asmx?wsdl

Step 2

WSO2 provides a set of shared instances of WSO2 Web services application server at http://wso2.org/tools. You can easily try out several features of web services application server with these instances.

Go to WSAS 2.2 shared instances page and select 'shared WSO2 WSAS Instance 1'. You will be directed to the home page of WSAS management console. Select WSDL2Code from the left navigation menu.
You will see the following page.



Enter 'http://www.webservicex.net/stockquote.asmx?wsdl' as the uri of WSDL. We need to generate a client to invoke the stock quote service. Therefore, you don't want to configure server side settings. Simply click on 'generate' leaving the other fields blank.

Within a few seconds, you will be prompted to save a zip file in your file system. Save it in your machine.

Step 3

Go to the directory where you saved the generated zip file. You will see src directory, pom.xml and build.xml file inside the zip file. src directory contains the StockQuoteStub and StockQuoteCallbackHandler classes which can be considered as proxies used in our client.

Now open a command window and go to the extracted directory where the above pom.xml exists.
Assuming you are using Eclipse as IDE, enter mvn eclipse:eclipse to generate the complete project structure which can be imported in to your IDE. (If Intellij IDEA is used, then use mvn idea:idea)

Depending on your network connection and the contents available in your maven2 repository, the above command takes some time to download the necessary jars to your m2 repo.

If everything is successful, you will see 'BUILD SUCCESSFUL' message.

Step 4

Open eclipse IDE. Select File-->Import.
Select 'Existing projects in to workspace'. In the 'Import Projects' window, browse for the root directory of the above location (where you extracted the generated zip file)
Select the project and click next

The complete project structure will be created with the generated artifacts. You may need to define M2_REPO classpath variable if you have not done it previously.

Step 5

Now use the generated stubs to create a java client under the above project to consume Stock Quote service.

public class StockQuoteClient {

public static void main(String[] args)throws AxisFault {
StockQuoteStub stub = new StockQuoteStub("http://www.webservicex.net/stockquote.asmx");
StockQuoteStub.GetQuote req = new StockQuoteStub.GetQuote();
req.setSymbol("IBM");
try {
StockQuoteStub.GetQuoteResponse response = stub.GetQuote(req);
System.out.println(response.getGetQuoteResult());
} catch (RemoteException e) {
e.printStackTrace();
}

}

}

Run the application. You will get the stock quote for IBM.


Monday, March 10, 2008

Reasons to repeat tests

We usually need repeating certain type of tests in project testing cycles. James Bach explains the reasons to perform repetitive tests in this great article. A must read for anyone interested in SQA/testing!

Tuesday, March 4, 2008

Secure web services: Signing SOAP messages using WSO2 WSAS and Apache Rampart

In my previous blog post, I demonstrated how Axis2 or WSO2 WSAS web service is deployed and invoked securely with user name token authentication. Here I'm going to invoke the same web service by signing the SOAP messages using server/client keystores instead of username tokens.

When signing soap messages in this way, we can ensure;
Non-repudiation
No tampering of the messages
However, this can not be considered as a good mechanism for confidential message transmission since the message contents are not encrypted.

Scenario

We need to invoke the default version service in secure manner. For that, we are supposed to use two different keystores for client and service. Client uses the client keystore to sign the SOAP request and server responds by signing the reply message using server keystore.

Step 1

First, we need to create two separate keystores for client and server. Java keytool can be used to generate keystores.

Create client keystore

Open a command window (or shell in linux) and type:

keytool -genkey -alias clientks -keyalg RSA -keystore C:\wssecurity\clientks.jks -storepass clientks

This will generate a keystore with necessary client certificate at the specified location.

Create server keystore
keytool -genkey -alias serverks -keyalg RSA -keystore C:\wssecurity\serverks.jks -storepass serverks

Import the client certificate to server keystore

Having two different keystores are not enough for secure message transmission. We need to import certificates of each other to ensure the message authentication.

First, we need to get the client certificate out from the client keystore as follows.
keytool -export -alias clientks -keystore C:\wssecurity\clientks.jks -file C:\wssecurity\client.cert

Next, we can import that certificate to server keystore as follows.
keytool -import -file C:\wssecurity\client.cert -keystore C:\wssecurity\serverks.jks -storepass serverks -alias client

Similarly, we can import server certificate to client keystore as follows.

Import the server certificate to client keystore

keytool -export -alias serverks -keystore C:\wssecurity\serverks.jks -file C:\wssecurity\server.cert

keytool -import -file C:\wssecurity\server.cert -keystore C:\wssecurity\clientks.jks -storepass clientks -alias server

Now, our client and server keystores are ready.

Step 2

Lets configure the server side security first. For that, you need to upload the server keystore in to WSO2 WSAS as explained below.

Access WSO2 WSAS management console using https://localhost:9443 and log in using default admin credentials (admin/admin).

Click on the 'keystores' link in the left pane of the management console. The following page will be displayed. Browse serverks.jks and enter keystore password. Then, click 'Next'.



Enter private key password of the serverks.jks (serverks). Click next button to continue. If everything is successful, you will get 'Keystore serverks.jks successfully added.' message.

Step 3

Now we need to enable security on one of the services available in WSAS management console. Select 'version' service in services and service group management page. You will be directed to the service management page of the version service. Select 'Manage security configuration' link.
Following page will be displayed where you can select 'Sign only - X509 Authentication' option.



Now you should be in the Services> version>Security Configuration> scenario2' page. Select 'serverks.jks' as the trusted certificate store and private keystore. Click on 'Apply'. If everything is successful you will get "Security scenario successfully applied" message.

You can check the security policy which has been generated by WSAS if you click on 'Edit service policies' link in the service management page.



You will see the following element there in the generated policy.
<rampart:property name="org.wso2.wsas.security.wso2wsas.crypto.keystore">serverks.jks</rampart:property>
Make sure to change the path of the serverks.jks correctly in this element. In our case it should be C:\wssecurity\serverks.jks

Thats all about the server side security configuration. Lets write a java client and invoke the service securely!

Step 4

WSAS provides a very useful code generation utility which can be used to generate a client stub easily. Select version service and click on 'Generate Client' link. You will be directed to 'Services>version>Stub generation' page. Set unpack class option to false and click on 'Generate' by leaving the other default options.
Save the generated client jar file in your file system.

Step 5

In the client side, we need to sign the SOAP message using the client keystore and we must adhere to the security policy of the server. Therefore, we need to have a client side policy which provides the path of client keystore and user who signs the request SOAP message. I will not describe all the information available in client security policy. Please download policy.xml from here and save it in your file system. In the mean time, we should have a look at the RampartConfig element in policy.xml because it is where we configure the client keystore information.

<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:user>signingclient</ramp:user>
<ramp:passwordCallbackClass>org.test.PWCBHandler
</ramp:passwordCallbackClass>

<ramp:signatureCrypto>
<ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type">JKS
</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.file">C:\wssecurity\clientks.jks
</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.password"
>clientks
</ramp:property>
</ramp:crypto>
</ramp:signatureCrypto>
</ramp:RampartConfig>

Here we use PWCBHandler(password call back handler) class to get the password of the user who signs the message.

public class PWCBHandler implements CallbackHandler{

public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < pwcb =" (WSPasswordCallback)callbacks[i];" id =" pwcb.getIdentifer();" style="font-weight: bold;">

Step 6

We are going to complete our scenario by constructing the client using the generated stub in step 4. In our client, first we need to set the system properties for SSL since we are going to access version service via https. (Please modify keystore path according to your file system)

System.setProperty("javax.net.ssl.trustStore","C:\\wsas\\wsas-2.2.1\\
wso2wsas-2.2.1\\conf\\wso2wsas.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "wso2wsas");


We need to instruct our client to use rampart module, we cannot simply add a mar(module archive) to our class path. Therefore we can create a configurationContext instance using file system and use it as follows. Please make sure to have the rampart-*.mar in your repository.
ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem("C:\\wsas
\\client-repo\\", null);

Next, create an instance of version service stub with passing the above Configurationcontext as an argument in the constructor.
VersionStub stub = new VersionStub(ctx, "https://192.168.1.2:9443/services/version");

Rampart module can be engaged in client as follows.

stub._getServiceClient().engageModule("rampart");

Next, the policy.xml which has been defined in step 5 needs to be loaded. We can do that using ServiceClient options class by setting it as a property.

Options options = stub._getServiceClient().getOptions();
options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, loadPolicy("C:\\wsas\\client-repo\\policy.xml"));
stub._getServiceClient().setOptions(options);

private static Policy loadPolicy(String xmlPath){
StAXOMBuilder builder = new StAXOMBuilder(xmlPath);
return PolicyEngine.getPolicy(builder.getDocumentElement());
}

Everything is ready! We can run our client now. Make sure to add jars included in WSO2WSAS_HOME/lib to your class path.
You can download the complete source of the client from here.