Details
-
Bug
-
Status: Open
-
Major
-
Resolution: Unresolved
-
3.1.3
-
None
-
None
Description
I am trying to connect to XmlRpc server through SSL using a self signed certificate.
For that I am using commons httpclient transport together with AuthSSLProtocolSocketFactory from httpclient 3.1 contrib section.
Here's my setup code:
XmlRpcClientConfigImpl xmlRpcConfig = new XmlRpcClientConfigImpl(); xmlRpcConfig.setServerURL(serverUrl); XmlRpcClient xmlRpcClient = new XmlRpcClient(); xmlRpcClient.setConfig(xmlRpcConfig); ProtocolSocketFactory sslSocketFactory = new AuthSSLProtocolSocketFactory(null, null, keyStoreUrl, keyStorePass); Protocol protocol = new Protocol("https", sslSocketFactory, serverUrl.getPort()); HttpClient httpClient = new HttpClient(); httpClient.getHostConfiguration().setHost(serverUrl.getHost(), serverUrl.getPort(), protocol); XmlRpcCommonsTransportFactory transportFactory = new XmlRpcCommonsTransportFactory(xmlRpcClient); transportFactory.setHttpClient(httpClient); xmlRpcClient.setTransportFactory(transportFactory);
Unfortunately, when the request is being made, XmlRpcCommonsTransport.newPostMethod(XmlRpcHttpClientConfig pConfig) is executed and it creates the PostMethod object in the following way:
return new PostMethod(pConfig.getServerURL().toString());
When XmlRpcCommonsTransport.writeRequest(final ReqWriter pWriter) execution, HttpClient.executeMethod(HttpMethod method) is invoked. It calls HttpClient.executeMethod(HostConfiguration hostconfig, final HttpMethod method, final HttpState state) with null hostconfig parameter. This combined with the fact that PostMethod uri is absolute, causes hostconfig to be initialized from scratch using the URI. Whatever host configuration was provided by the user through HttpClient.getHostConfiguration().setHost(...) is ignored.
I am aware that I could override httpclient's protocol handler for https using Protocol.registerProtocol(String id, Protocol protocol) call, but that would have ClassLoader wide scope, which is not something a "good citizen" application component should do.
In order to circumvent this issue I have subclassed XmlRpcCommonsTransport to override PostMethod newPostMethod(XmlRpcHttpClientConfig pConfig) as follows:
protected PostMethod newPostMethod(XmlRpcHttpClientConfig pConfig) { HostConfiguration hostConfiguration = client.getHostConfiguration(); URL requestUrl = pConfig.getServerURL(); if(hostConfig != null) { if(requestUrl.getProtocol().equals(hostConfiguration.getProtocol().getScheme()) && requestUrl.getHost().equals(hostConfiguration.getHost()) && requestUrl.getPort() == hostConfiguration.getPort()) { // use URI relative to base URI determined by HostConfiguration return new PostMethod(requestUrl.getFile()); } else { throw new IllegalArgumentException("Server URL " + requestUrl + "does not agree with HttpClient host configuration " + hostConfiguration); } } // use absolute URI return new PostMethod(requestUrl.toString()); }
If the user bothered to set a custom HostConfiguration but used different server base URL for the XmlRpcClient, the method throws an exception. I think it'll help the user to spot the configuration error earlier.
Using this derived class (and matching XmlRpcCommonsTransportFactory) I was able to connect to the server using SSL with self signed certificate loaded from JKS keystore loaded into AuthSSLProtocolSocketFactory.