Web Services API - WSO2 Governance Registry
- Tharindu Mathew
- Technical Lead - WSO2
Introduction
This article gives a thorough analysis of the WS API so that the reader can understand the architecture, applicable scenarios, advantages and limitations of the same. Also, it includes recommendations and guides on how to use this component in the most effective and efficient manner.
It is assumed that the user has a basic knowledge of web services and Registry operations. In the context of this article, registry refers to WSO2 Governance Registry and WS API refers to the Registry Web Services API.
Applies To
WSO2 Governance Registry | 3.5 or later |
JDK | 1.5 or later |
The Registry WS API
With the release of the 3.5 version of the Registry, it features a WS API that allows users to conduct registry operations through simple SOAP requests. The opening up of this channel makes the Registry useful in a number of possible ways. Also, it introduces some best practices that should be adhered to, when using the WS API. First, I will outline some of the main uses of the WS API below:
Uses of the WS API
The WS API allows access to the core APIs through SOAP requests. This factor alone introduces a number of advantages to a user:
- True remote access - When the back end of the Registry is in a separate location, the WS API is a great way of performing operations on the Registry. Since the WS API communicates using port 80 over HTTP, users can avoid problems arising due to firewalls.
- Quality of Service (QoS) - Users require QoS aspects, such as security, reliability, etc., when accessing the Registry. The WS API allows users to engage Axis 2 modules for WS-Security, WS-Addressing, etc. according to their requirements.
- Any language, any platform - Since interoperability is an inherent nature of web services, the WS API allows a client to be written in any language on any platform to access the Registry.
- Programmatic interface – The registry currently allows programmatic access to its operations through the Registry Core API and Atom API. The WS API will add itself as an additional programmatic interface to the registry.
A Sample demonstration
Before diving into the architecture of the WS API, I'd like to look at demonstrating on how to work with the same. I'd be using the client library which is provided with the Registry distribution, that allows users to access the WS API just as they would be accessing the core Registry API itself. A more detailed sample is included in the WS API developer guide of the Registry documents.
Please extract and run a binary distribution of the Registry, available at https://wso2.com/products/governance-registry/, prior to trying out this sample. This can be done by running the wso2server.(bat or sh) script from the command line. The script is present in the $GREG_HOME/bin directory.
Setting up the WS API Registry Client
The following code shows how to set up the WS Client and authenticate it against an instance of the Governance Registry. NOTE: It is assumed that default configurations of the Registry have not been changed.
First, we have to set the system properties to enable the https connection.
String GREG_HOME = /path/to/Governance_Registry System.setProperty("javax.net.ssl.trustStore", "GREG_HOME/resources/security/client-truststore.jks"); System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon"); System.setProperty("javax.net.ssl.trustStoreType","JKS");
A number of parameters are required to initialize the client. These are initialized in the following code:
String axis2Repo = GREG_HOME + "/repository/deployment/client"; String axis2Conf = GREG_HOME + "/repository/repository/conf/axis2_client.xml"; ConfigurationContext configContext = ConfigurationContextFactory. createConfigurationContextFromFileSystem(axis2Repo, axis2Conf);
The final steps of the initialization is done in the following code segment:
String username = "admin"; String password = "admin"; String backEndServerURL = "https://localhost:9763/services/"; String serverURL = "https://localhost:9443/services/";
WSRegistryServiceClient registry = new WSRegistryServiceClient(serverURL, username, password, backEndServerURL, configContext);
Please run an "ant" command at GREG_HOME/bin and add all the jars created in GREG_HOME/repository/lib to the class path prior to running the examples in this guide.
Now, if you now run this example, an output similar to the following output will be generated at the server side console:
[TIMESTAMP] INFO - 'admin' logged in at [TIMESTAMP] from IP address https://localhost:9443/services/AuthenticationAdmin
This client instance can now be used just as using the Registry API. Some of the possible operations are illustrated below:
Adding a resource to the registry
Resource r1 = registry.newResource(); String path = "/dev_guide/r1"; String r1content = "R1 content"; r1.setContent(r1content); registry.put(path, r1);
From the above sample, I hope it is clear that the client is designed in such a way that every Registry operation can be performed as you are using the core Registry API itself. If I re-iterate this point, it means that every operation that can be called in the form of, registry.put(“/some_path”, some_resource) instead of registry.WSput(“/some_path”, some_resource).
Initializing the client just need the following parameters to be passed in :
WSRegistryServiceClient(String serverURL, String username, String password, String backendServerURL, ConfigurationContext configContext)
If I explain these parameters further, all that needs to be provided are the URLs of the Registry that has been started. In basic cases serverURL and backendServerURL are the same. The backendServerURL will always be used to access the registry. Therefore, a http port used here would increase performance. An example of the recommended usage is (using default settings),
String backendURL = "https://localhost:9763/services/"; String username = "admin"; String password = "admin"; String serverURL = "https://localhost:9443/services/";
The making of the configuration context is skipped here for brevity. It is shown in the sample code shown above.
The WS API Architecture
WSDL Location : Once the Registry is started up, the WSDL can be viewed by going to the following URL: https://YOUR_IP_ADDRESS:9443/services/WSRegistryService?wsdl
The WS API acts as a wrapper class to the core Registry API. For all registry operations, the WS API wraps the operation and makes it compatible to function with web services. The inter-operable nature of web services introduces some limitations, thus, making some data objects and methods inaccessible as a web service. The WS API solves this issue by introducing a WS compatible objects and operations that corresponds directly to objects and operations in the core Registry API.
The following table illustrates the mapping between objects:
WS API
|
Core API |
WSResource |
Resource |
WSCollection |
Collection |
WSComment |
Comment |
WSProperty (An array) |
Properties (Java util object) |
WSMap |
Map (Java util object) |
These web service objects are used for wrapping and unwrapping data to send across the network when the WS API is used.
The case of sending across a resource's content (obtained through getContent()), i.e. binary data or text, is done by using MTOM (Message Transmission Optimization Mechanism). It can be thought as the binary data or text is base64 encoded in the XML document, and set across the wire. To learn more about MTOM, please refer:
http://ws.apache.org/axis2/1_0/mtom-guide.html
The Registry WS Client performs the direct inverse of the wrapping/unwrapping done by the WS API. For ex: If a Collection (i.e. A Registry collection, not Java collection) is requested,
-
Server side – wraps the Collection and it's content as a WSCollection with an attachment, and sends it over across the wire as a SOAP message.
- Client side – unwraps the WSCollection and the attachment, and converts it into a Collection with content and presents it to the user.
The WS API has been implemented mainly thorough the class, WSRegistry. The class implements the main Registry interface. But some methods in the Registry interface are not compatible to be exposed as web services. Therefore, each of these incompatible methods are wrapped by a web service compatible methods. The following table illustrates each of the methods that went through the wrapping process:
WS API
|
Core API |
WSnewResource |
newResource |
WSnewCollection |
newCollection |
WSget |
get – 2 parameters |
WSgetMetaData |
getMetaData |
WSgetWithPageSize |
get – 3 parameters |
WSgetChildCollection |
getChildCollection |
WSput |
put |
WSimportResource |
importResource |
WSgetResourcePathsWithTag |
getResourcePathsWithTag |
WSaddComment |
addComment |
WSgetComments |
getComments |
WSexecuteQuery |
executeQuery |
WSsearchContent |
searchContent |
These methods will generally wrap Objects in WS compatible objects and send them over the wire.
A Sample Flow
Let me explain the flow of a method call and its response with the help of the following illustrations. I will consider a scenario where a registry.get() is called to obtain a registry Collection.
Let us first consider the flow of the method call. The numbers depict the order of the flow.
(1) - The user program executes a get() method call
(2) - The WS API Client converts this call into a web service compatible WSget() method call and sends it over the wire
(3) - The WS API converts this method back to a get() method call and that calls the Core API
Now let us look at the response for the get() method call.
(1) - The Core API returns the relevant Collection object
(2) - The WS API converts this into a web service compatible WSCollection object and send it over the wire
(3) - The WS API Client converts the received WS Collection back into a Collection object and returns it to the user program
WS API Security
The WS API exposes almost all of the methods of the core API so that it can be accessed through a web services client. This kind of method exposure would implicitly raise questions on security. Users would concern themselves on what security mechanisms are used to secure this WS API channel. Bearing these concerns in mind, the WS API supports 2 security mechanisms:
- Basic Authentication over HTTPS
- WS-Security
Let's look at these 2 mechanisms in detail:
-
Basic Authentication over HTTPS
Authentication through this mechanism is compulsory if you are to use the WS API. The client needs to be authenticated using valid credentials. These credentials are authenticated against the registry user base, so the user's registry credentials are valid for this purpose as well. The registry exposes a web service that allows authentication known as the Authentication Admin that allows a user to login to the registry using the exposed method 'login'. This web service is only accessible through HTTPS. The cookie obtained through the Authentication Admin is then used to access the WS API.
Here is how it's done in the Registry WS API service client:
String serviceEPR = serverURL + "AuthenticationAdmin";
AuthenticationAdminStub stub = new AuthenticationAdminStub(ctx, serviceEPR);
ServiceClient client = stub._getServiceClient();
Options options = client.getOptions();
options.setManageSession(true);
try {
boolean result = stub.login(username, password, serviceEPR);
if (result){
cookie = (String) stub._getServiceClient().getServiceContext().
getProperty(HTTPConstants.COOKIE_STRING);
}
return result;
} catch (Exception e) {
String msg = "Error occurred while logging in";
throw new AuthenticationException(msg, e);
}
Using this mechanism alone is recommended only when performance cannot be compromised. In other cases, the recommendation is to use WS-Security as well.
-
WS-Security
WS-Security can be engaged to the Registry WS API by simply by dropping in the relevant policy file to the conf directory inside directory. Let the Registry installation location be $GREG_HOME. The policy file must be named “ws-api-sec.xml” and should be places in the $GREG_HOME/repository/conf directory. This will then be picked up and applied to the WS API. A sample policy file is available at [1]. The rampart module should be dropped into $GREG_HOME/repository/deployment/server/axis2modules.
NOTE: The server has to be restarted after this file is placed in the said location.
On successful engagement of security the following log statement will be displayed on the console:
[TIMESTAMP] INFO - Loading security policy for the Registry WS-API Component from $GREG_HOME/repository/conf/ws-api-sec-policy.xml
The class known as WSDeploymentInterceptor is responsible for engaging WS-Security for the WS-API. This class implements the Axis Observer interface. The methods of this interface is then used to engage security if the presence of a policy file is detected. In the presence of a “ws-api-sec.xml”, the policy within a file is attached to the service and Apache Rampart is engaged for the service for the said policy.
Conclusion
The WS API, when strengthened with a sound security mechanism, it is possible to operate the Registry through any environment making it truly inter-operable. The architecture and security of this component makes it suitable for most user scenarios. Later releases will concentrate more on performance and additional features. But it is stressed that further additions and enhancements will be made to the WS API to increase it's efficiency and performance while continuing to support the interoperability.
References
Registry API - https://wso2.org/project/registry/3.5.0/docs/apidocs/kernel/org/wso2/carbon/registry/core/Registry.html
Apache Axis2 - http://ws.apache.org/axis2
MTOM with Axis2 - http://ws.apache.org/axis2/1_0/mtom-guide.html