How to set a certificate to be trusted for a spring RestTemplate

18,866

Solution 1

The server-keystore.jks that you specified in the connector for jboss-web is only used as server certificate for incoming connections.

For outbound connections, JBoss acts like any other java client, so you need to import the server certificate into the default java truststore. You could use the default %JAVA_HOME%\lib\security\cacerts, and import your server certificate using:

keytool -import -trustcacerts -keystore cacerts -storepass changeit -noprompt -alias mycert -file mycert.cer

If you don't want to edit the default cacerts, you could define an alternative truststore by setting system properties like explained in: Java client certificates over HTTPS/SSL.

A third way is to override the https ProtocolSocketFactory so that it accepts all certificates, like: http://drumcoder.co.uk/blog/2011/mar/30/httpclient-self-signed-certificates/

Solution 2

I made a simple method:

static HttpComponentsClientHttpRequestFactory requestFactory = null;

/**
 *
 * @return
 */
public static ServerProperties getServerProperties() {
    return serverProperties;
}

/**
 * @return
 */
public static HttpComponentsClientHttpRequestFactory getRequestFactory() {
    if (requestFactory == null) {
        TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                return true;
            }
        };
        SSLContext sslContext = null;
        try {
            sslContext = org.apache.http.ssl.SSLContexts.custom()
                    .loadTrustMaterial(null, acceptingTrustStrategy)
                    .build();
            SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);

            CloseableHttpClient httpClient = HttpClients.custom()
                    .setSSLSocketFactory(csf)
                    .build();
            requestFactory = new HttpComponentsClientHttpRequestFactory();
            requestFactory.setHttpClient(httpClient);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
    }
    return requestFactory;
}

Then when I instance restTemplate:

 RestTemplate  restTemplate = new RestTemplate(getRequestFactory());

Simple.

Share:
18,866
Filip Majernik
Author by

Filip Majernik

I am a passionate coder specialised in enterprise frameworks (Java, JEE, BPMN/BPEL, WebServices) with a strong security background, especially XML security (WS-Security, XML-Encryption, XML-Signature, etc...). I am also interested in the mobile App development with the Android SDK and iOS.

Updated on June 04, 2022

Comments

  • Filip Majernik
    Filip Majernik almost 2 years

    I am using Spring RestTemplate in my application to access external web services. This web service hat SSL enabled, however, with a self signed certificate (domain, etc... are also not valid). This is just on a local network, so I do not have to be worry about some security issues. I want to make Spring to accept this certificate. This is what I've done so far:

    1.) I have configured my JBOSS 7 to use this keystore

    <connector name="https" protocol="HTTP/1.1" socket-binding="https" scheme="https" enable-lookups="false" secure="true">
        <ssl name="ssl" key-alias="my-private-key" password="rmi+ssl" certificate-key-file="../standalone/configuration/server-keystore.jks" protocol="TLSv1" verify-client="false"/>
    </connector>
    

    2.) Here is the configuration of my RestTemplate Bean (I am using autowireing in my classes)

    <bean id="stringHttpConverter" class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
    
    <bean id="httpClientParams" class="org.apache.commons.httpclient.params.HttpClientParams">
        <property name="authenticationPreemptive" value="true"/>
        <property name="connectionManagerClass" value="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
    </bean>
    
    <bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
        <constructor-arg ref="httpClientParams"/>
    </bean>
    
    <bean id="httpClientFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory">
        <constructor-arg ref="httpClient"/>
    </bean>
    
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <constructor-arg ref="httpClientFactory"/>
        <property name="messageConverters">
            <list>
                <!-- <ref bean="marshallingConverter" /> -->
                <ref bean="stringHttpConverter" />              
            </list>
        </property>
    </bean>
    

    I have imported the server certificate into the keystore, it is definitely in there. What else do I have to do? I've already checked all similar questions here, but none of them helped. Thanks.

  • Filip Majernik
    Filip Majernik over 12 years
    So in my case I should import the server certificate into server-keystore.jks? Or it does to be a separate keystore for trusted certificates? And another question, should I import the server certificate or the server CA certificate? Thanks.
  • Jan Mares
    Jan Mares over 5 years
    nasty, never trust everyone - in programming or real life ;-)