Personal tools

rPath Appliance Platform Agent:XML-RPC Java Client

From rPath Wiki

Jump to: navigation, search
rPath Appliance Platform --> Agent --> XML-RPC --> XML-RPC Java Client

Contents

Appliance developers can use the XML-RPC methods provided by rPath Appliance Platform Agent to develop a Java XML-RPC client to communicate with the appliance agent. This page uses code from the Apache XML-RPC library; developers using different code should note the differences between that code and the examples provided.

Install the XML-RPC Toolkit

If you do not already have the XML-RPC toolkit, download and unpack it:

$> wget http://mirror.olnevhost.net/pub/apache/ws/xmlrpc/xmlrpc-current-bin.tar.gz
$> tar xzf xmlrpc-current-bin.tar.gz

The necessary libraries for developing the Java client are in xmlrpc-X.Y/lib/, where X and Y are the major and minor version numbers of the current XML-RPC toolkit. Change to that directory to use those libraries (for this example, the version is 3.1, if you have a different version, specify that):

$> cd xmlrpc-3.1/lib/

Create a Client that Bypasses Certificate and Hostname Validation

rAP serves SSL-enabled traffic by default. Java tries to validate the certificate and host name by default. Bypass the validation with the getActiveTasksRss method as shown in the following code:

import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.HashMap;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
 
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
 
public class Test1 {
    private static void install() throws Exception {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] {
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
 
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    // Trust always
                }
 
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    // Trust always
                }
            }
        };
 
        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        // Create empty HostnameVerifier
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String arg0, SSLSession arg1) {
                    return true;
            }
        };
 
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }
 
    public static void call(String url) throws Exception {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        config.setServerURL(new URL(url));
        XmlRpcClient client = new XmlRpcClient();
        client.setConfig(config);
        HashMap result =  (HashMap) client.execute("getActiveTasksRss", new Object[0]);
        System.out.println("Returned: " + result.get("title"));
    }
 
    public static void main(String[] args) throws Exception {
    	String url = "https://127.0.0.1:8003/rAA/xmlrpc/";
        if(1 <= args.length) {
            url = args[0];
        }
 
        Test1.install();
        Test1.call(url);
        System.out.println("Finished.");
    }
}

The following commands are used to compile the example code and to run it. Again, substitute your version number of the XML-RPC toolkit that you have installed. You may also have to update the version number of ws-common-utils when you go to execute. Check to see what versions are installed in the lib directory.:

$> javac Test1.java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.1.jar:xmlrpc-common-3.1.jar

$> java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.1.jar:xmlrpc-common-3.1.jar:. Test1 https://localhost:8003/rAA/xmlrpc/
Returned: Future tasks
Finished.

Create a Client that Validates Certificates

The Appliance Platform certificate is saved in /etc/ssl/pem/raa.pem on the appliance with rAPA. You probably want to copy this file to your local development client. Convert the certificate to X.509-format before validating from the Java client, and use keytool to import it to the trust store:

$> openssl x509 -in raa.pem > raa.x509
$> keytool -import -alias raa -keystore raa.truststore -file raa.x509

The following code allows the default verification:

import java.net.URL;
import java.util.HashMap;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
 
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
 
public class Test2 {
    public static void install() throws Exception {
        // Bypass hostname verification.
        HttpsURLConnection.setDefaultHostnameVerifier(
                new HostnameVerifier() {
                    public boolean verify(String arg0, SSLSession arg1) {
                            return true;
                    }});
    }
    
    public static void call(String url) throws Exception {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        config.setServerURL(new URL(url));
        XmlRpcClient client = new XmlRpcClient();
        client.setConfig(config);
        HashMap result =  (HashMap) client.execute("getActiveTasksRss", new Object[0]);
        System.out.println("Returned: " + result.get("title"));
    }
    
    public static void main(String[] args) throws Exception {
        String url = "https://127.0.0.1:8003/rAA/xmlrpc/";
        if(1 <= args.length) {
            url = args[0];
        }
 
        Test2.install();
        Test2.call(url);
        System.out.println("Finished.");
    }
}

The following commands are used to compile the example code and to run it:

$> javac Test2.java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar

$> java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar:. -Djavax.net.ssl.trustStore=raa.truststore Test2 https://localhost:8003/rAA/xmlrpc/
Returned: Future tasks
Finished.

If the certificate is not loaded, such as in the following command, Java will return the following error:

$> java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar:. Test2 https://localhost:8003/rAA/xmlrpc/
Exception in thread "main" org.apache.xmlrpc.XmlRpcException: Failed to read servers response: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.sendRequest(XmlRpcStreamTransport.java:150)
...

Create a Client that Validates Certificates and Hostname

When a Java client tries to connect, it checks that the machine to which it is connected matches what the certificate says. The following is an example of a certficate with an unacceptable hostname:

$> LANG=C keytool -printcert -file raa.x509 
Owner: EMAILADDRESS=root@localhost.localdomain, CN=localhost.localdomain, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU
Issuer: EMAILADDRESS=root@localhost.localdomain, CN=localhost.localdomain, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU
Serial number: daaf3621eea0a769
Valid from: Tue Apr 17 03:30:14 CST 2007 until: Wed Apr 16 03:30:14 CST 2008
Certificate fingerprints:
         MD5:  98:24:2F:21:4F:81:8E:63:50:FE:6F:BB:24:17:4F:4F
         SHA1: 4B:CF:9C:A7:A8:82:74:B0:51:6B:8A:3C:E5:D0:F3:33:33:20:0A:23
         Signature algorithm name: MD5withRSA
         Version: 3

The certificate states that it belongs to localhost.localdomain. However, when the Java client is connecting to a remote server, it is not connecting to localhost.localdomain. To fix this conflict, generate a new certificate and upload it to rAP using the Upload SSL Certificate plugin, and then regenerate the Appliance Platform trust store.

$> LANG=C keytool -printcert -file raa.x509
Owner: EMAILADDRESS=root@server.example.com, CN=server.example.com, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU
Issuer: EMAILADDRESS=root@server.example.com, CN=server.example.com, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU
Serial number: bcc5921b88f342e6
Valid from: Tue Apr 17 03:33:18 CST 2007 until: Wed Apr 16 03:33:18 CST 2008
Certificate fingerprints:
         MD5:  73:1A:BB:FB:AC:CB:F6:FC:6D:CB:63:9D:FC:56:65:E9
         SHA1: 9A:2B:ED:56:E5:52:D8:9C:37:1A:55:04:67:AC:14:37:AA:DB:CA:F9
         Signature algorithm name: MD5withRSA
         Version: 3

With the correct certificate in place, the following code will verify certificate and hostname without any bypasses:

import java.net.URL;
import java.util.HashMap;
 
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
 
public class Test3 {
    public static void call(String url) throws Exception {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        config.setServerURL(new URL(url));
        XmlRpcClient client = new XmlRpcClient();
        client.setConfig(config);
        HashMap result =  (HashMap) client.execute("getActiveTasksRss", new Object[0]);
        System.out.println("Returned: " + result.get("title"));
    }
 
    public static void main(String[] args) throws Exception {
    	String url = "https://127.0.0.1:8003/rAA/xmlrpc/";
        if(1 <= args.length) {
        	url = args[0];
        }
 
        Test3.call(url);
        System.out.println("Finished.");
    }
}

The following commands are used to compile the example code and to run it:

$> javac Test3.java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar

$> java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar:. -Djavax.net.ssl.trustStore=raa.truststore Test3 https://server.example.com:8003/rAA/xmlrpc/
Returned: Future tasks
Finished.

If it's specified wrong, then the error message looks like

$ java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar:. -Djavax.net.ssl.trustStore=raa.truststore Test3 https://server.example.com:8003/rAA/xmlrpc/
Exception in thread "main" org.apache.xmlrpc.XmlRpcException: Failed to read servers response: java.security.cert.CertificateException: No name matching server.example.com found
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.sendRequest(XmlRpcStreamTransport.java:150)
...

Create a Client that Authenticates by Username and Password

The following is an example of a client using username and password for authentication:

import java.net.URL;
import java.util.HashMap;
 
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
 
public class Test4 {
    public static void call(String url, String user, String pass) throws Exception {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        config.setServerURL(new URL(url));
        config.setBasicUserName(user);
        config.setBasicPassword(pass);
        XmlRpcClient client = new XmlRpcClient();
        client.setConfig(config);
        String result =  (String) client.execute("config", new Object[0]);
        System.out.println("Returned: " + result);
    }
 
    public static void main(String[] args) throws Exception {
        String url = "https://127.0.0.1:8003/rAA/xmlrpc/";
        String user = "";
        String pass = "";
    
        if(1 <= args.length) {
                url = args[0];
        }
        if(2 <= args.length) {
                user = args[1];
        }
        if(3 <= args.length) {
                pass = args[2];
        }
 
        Test4.call(url, user, pass);
        System.out.println("Finished.");
    }
}

The following commands are used to compile the example code and to run it:

$> javac Test4.java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar

$> java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar:. -Djavax.net.ssl.trustStore=raa.truststore Test4 https://server.example.com:8003/rAA/xmlrpc/ admin password
Returned: [/backup/files]
...
Finished.

Without a username and password provided, as in the following example, Java displays the following errors:

$> java -classpath xmlrpc-client-3.1.jar:commons-logging-1.1.jar:ws-commons-util-1.0.2.jar:xmlrpc-common-3.1.jar:. -Djavax.net.ssl.trustStore=raa.truststore Test4 https://server.example.com:8003/rAA/xmlrpc/
Exception in thread "main" org.apache.xmlrpc.XmlRpcException: Failed to create input stream: Server returned HTTP response code: 403 for URL: https://server.example.com:8003/rAA/xmlrpc/
        at org.apache.xmlrpc.client.XmlRpcSunHttpTransport.getInputStream(XmlRpcSunHttpTransport.java:60)

Additional Resources

Reference the following XML-RPC and Java resources to help with creating a Java XML-RPC client for the rPath Appliance Platform.