Setup Tomcat SSL and Spring RESTful webservice Client

1. Generate a keystore using Java command : keytool 

    keytool -v -genkey -alias tomcat -keyalg RSA -keystore C:/test/tomcat.keystore -validity 36500

    For keytool usage , can refer to othere google search

Attention : 

   a. when prompted for password(e.g. changeit), please enter the same as you input in tomcat server.xml

   b. When prompted for " What is your first name and last name ?"  you should input the root web address :

    For example , your explored web address is   https://xxxx.yyy.zzz:8443/ , then the first name and last name should be xxx.yyy.zzz . otherwise , the client will fail to authorized  with exception like below :

Caused by: javax.net.ssl.SSLException: hostname in certificate didn't match: <xxx.yyy.zzz> != <your input for first and last name>
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:228)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:151)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:125)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:641)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:480)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:88)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:49)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:446)

2. Modify tomcat server.xml like below :

 TOMCAT/conf/server.xml 

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" keystoreFile="C:/test/tomcat.keystore"
               keystorePass="changeit" sslProtocol="TLS" />

3. Start the Tomcat

you must restart tomcat everytime when you changed the keystore . so that the new keystore can take effect .

4.1 Spring restTemplate setting in server side :

?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:int="http://www.springframework.org/schema/integration"
	xmlns:int-http="http://www.springframework.org/schema/integration/http"
	default-merge="false"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http-2.2.xsd
		http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.2.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	
	<int-http:inbound-gateway id="soa"
		request-channel="receiveRequestChannel" reply-channel="responseCallBackChannel"
		supported-methods="POST" path="/fcrsp/{indicator}" error-channel="logger"
		request-payload-type="java.lang.String" >
		 <int-http:header name="indicator" expression="#pathVariables.indicator"/>
	</int-http:inbound-gateway>
	
	<int:channel id="receiveRequestChannel"></int:channel>

	<int:service-activator input-channel="receiveRequestChannel" output-channel="responseCallBackChannel"
		expression="@myWebService.callStoreProcedure(headers.get('indicator'),payload)">
	</int:service-activator>

	<int:channel id="responseCallBackChannel"></int:channel>
	
</beans>

4.2 Spring restTemplate setting in client side :

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/tx 
                        http://www.springframework.org/schema/tx/spring-tx.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc.xsd
                        http://www.springframework.org/schema/jdbc
                        http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
                        http://www.springframework.org/schema/task 
                        http://www.springframework.org/schema/task/spring-task.xsd">

	
	<!-- Username and Password Credentials to access restful service -->
	<bean id="credentials" class="org.apache.http.auth.UsernamePasswordCredentials">
		<constructor-arg>
			<value>soauser</value>
		</constructor-arg>
		<constructor-arg>
			<value>soapassword</value>
		</constructor-arg>
	</bean>

	<bean id="httpClientFactory" class="com.hsbc.gbm.finit.lta.fcr.entity.FCRHttpComponentsClientHttpRequestFactory">
		<constructor-arg ref="credentials" />
	</bean>

	<!-- Rest template -->
	<bean id="restTemplate" name="restTemplate" class="org.springframework.web.client.RestTemplate">
		<constructor-arg ref="httpClientFactory" />
	</bean>
	
	<bean id="fcrWebserviceClient" class="mypackage.myWebserviceClient">
		<property name="restTemplate" ref="restTemplate" />
		<property name="requestUrl" value="https://xxx.yyy.zzz:8443/FCR-Webservice-orchestration/rest/fcrsp/getHierarchy" />
		<property name="compressed" value="false" />
	</bean>
</beans>

  FCRHttpComponentsClientHttpRequestFactory.java

set the keystore value 

public class FCRHttpComponentsClientHttpRequestFactory extends
		HttpComponentsClientHttpRequestFactory {

	public FCRHttpComponentsClientHttpRequestFactory(){
		super();
	}
	
	public FCRHttpComponentsClientHttpRequestFactory(Credentials credentials) throws Exception{
		super();
		DefaultHttpClient httpClient = (DefaultHttpClient) this.getHttpClient();
		httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY,credentials);
		httpClient.addRequestInterceptor(new FCRHttpRequestInterceptor(), 0);
		
		
		KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
        	FileInputStream instream = new FileInputStream(new File("c:/test/tomcat.keystore"));
       		try {
            		trustStore.load(instream, "changeit".toCharArray());
        	} finally {
            		try { instream.close(); } catch (Exception ignore) {}
        	}
        	SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
        	Scheme scheme = new Scheme("https", 8443, socketFactory);
        	httpClient.getConnectionManager().getSchemeRegistry().register(scheme);
		this.setHttpClient(httpClient);
		this.setConnectTimeout(999999999);
	} 
}
public class FCRHttpRequestInterceptor implements HttpRequestInterceptor {
	
	public void process(HttpRequest request, HttpContext context)
			throws HttpException, IOException {
		AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
		if (authState.getAuthScheme() == null) {
			CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
			HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
			Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
			if (creds == null) {
				throw new HttpException("No credentials for preemptive authentication");
			}
			authState.update(new BasicScheme(), creds);
		} 
	} 
}

相关推荐