3

We've been using Springs HttpInvoker for a few weeks now and it works like a charm. From my front end (web)application I connect to the backend's userService like this:

<bean id="userService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl" value="http://${backend.host}/backend-ws/remoting/UserService"/>
    <property name="serviceInterface" value="com...service.UserService"/>
</bean>

The UserService is then nicely injected into our front end classes.

Now we're deploying this on a proper (WAS7) server and the requirement there is to use SSL (https). So, I change the http (of the serviceUrl) to https but then I get:

 org.springframework.remoting.RemoteAccessException: Could not access HTTP invoker remote service at [https://pbp-dev.dev.echonet/public/backend-ws/remoting/ParameterHelper]; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

which makes sense because the certificate installed on the server (where WAS runs) is not signed by a CA.

We already have some experience with this since on the same WAS there is a webservice running; for this we use cxf and we have generated a jks file (with keytool) that resides in the client application and is set as following:

<http:conduit name="https://serverurl/.*">
<http:tlsClientParameters secureSocketProtocol="SSL" disableCNCheck="false">
    <sec:trustManagers>
        <sec:keyStore type="jks" password="pass123" resource="trust.jks"/>
    </sec:trustManagers>
</http:tlsClientParameters>

I guess for the Http Invoker we need to do something similar but we have no idea how to use this trust.jks in the invoker.

One thing I did find is to use a different requestExecutor; like this:

<bean id="userService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl" value="https://${backend.host}/backend-ws/remoting/UserService"/>
    <property name="serviceInterface" value="com...service.UserService"/>
    <property name="httpInvokerRequestExecutor">
    <bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor" />
    </property>
</bean>

After this I no longer get the certificate error but the userService does not appear to be created since then I get:

NoSuchBeanDefinitionException: No matching bean of type [com...service.UserService] found for dependency
Stijn Geukens
  • 15,454
  • 8
  • 66
  • 101
  • May this helps: http://blog.jayway.com/2008/09/30/spring-remoting-with-security-and-ssl/ – Ralph Jan 05 '12 at 11:51
  • @Ralph, tx, I already had a look at this blog before but, as I understand it, it doesn't completely address our issue (see the last post in this blog). – Stijn Geukens Jan 05 '12 at 12:36

2 Answers2

2

If you mix what you can find here (http://stackoverflow.com/questions/5947162/https-and-self-signed-certificate-issue) to configure the HttpClient returned to have a pre configured SSLSocketFactory, you can change the hostname verifier of the socket factory to accept the cerificate, something close to this:

xxx.setHostnameVerifier(new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) { println("bypassing ssl cert handshaking as configured for self signed cert."); return true; }
});

According to you config, besides using CommonsHttpInvokerRequestExecutor you also have to configure the HTTPClient used and the SSL Socket factory

I know this probably does not completely answer your question but it's a starting point for other searches! Good Luck and don't forget to post the final solution.

Jose Muanis
  • 547
  • 4
  • 13
2

You can try something as follows:

First write a custom class of org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor :

package com.myorg.proid.sample;

import static org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.X509Certificate;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor;

/**
 * @author visruth
 *
 */
public class CustomHttpComponentsHttpInvokerRequestExecutor extends
        HttpComponentsHttpInvokerRequestExecutor {

    public CustomHttpComponentsHttpInvokerRequestExecutor() {
        skipSecurityChecking();
    }

    @SuppressWarnings("deprecation")
    private void skipSecurityChecking() {

        // HttpClient from super class.
        HttpClient httpClient = getHttpClient();

        TrustStrategy trustStrategy = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] certificate,
                    String authType) {
                return true;
            }
        };

        try {
            httpClient
                    .getConnectionManager()
                    .getSchemeRegistry()
                    .register(
                            new Scheme("https", 80, new SSLSocketFactory(
                                    trustStrategy,
                                    ALLOW_ALL_HOSTNAME_VERIFIER)));
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
    }

}

and refer this class in your xml file instead of org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor as

<bean id="userService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl" value="https://${backend.host}/backend-ws/remoting/UserService"/>
    <property name="serviceInterface" value="com...service.UserService"/>
    <property name="httpInvokerRequestExecutor">
    <bean class="com.myorg.proid.sample.CustomHttpComponentsHttpInvokerRequestExecutor" />
    </property>
</bean>
Visruth
  • 3,430
  • 35
  • 48
  • We no longer use Spring HTTP invoker so I can't validate your answer but +1 anyway for making the effort to provide a good reply to an old question – Stijn Geukens Oct 16 '15 at 15:18
  • @StijnGeukens Thank you. But, may know why you don't use HTTP invoker, I mean if you are using any alternative for it? – Visruth Oct 16 '15 at 16:57
  • I believe we switched to hessian. – Stijn Geukens Oct 17 '15 at 15:37
  • The implementation can be updated for the last version of Apache HttpClient. See : https://stackoverflow.com/questions/19517538/ignoring-ssl-certificate-in-apache-httpclient-4-3 – cactuschibre Sep 09 '20 at 14:23