rPath Appliance Platform Agent:XML-RPC Java Client
From rPath Wiki
|
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.
- http://ws.apache.org/xmlrpc/
- http://blogs.sun.com/andreas/entry/no_more_unable_to_find
- http://java.sun.com/products/jsse/INSTALL.html
