天天看點

HttpInvoker支援不需要證書的HTTPS

【問題】 遇到内部管理非常嚴格的客戶可能存在一套内部系統的部署規範,例如隻支援HTTPS協定不支援HTTP,如果系統多出采用HttpInvoker,而此處的配置大多不能直接支援HTTPS。我們可以建議客戶同時開放HTTP和HTTPS,對外隻開放HTTPS端口,此時實體伺服器内部的應用可以使用HTTP協定進行HttpInvoker互動,但如果是分布式部署呢?      【解決辦法】 1.  大多的配置如下(很多程式都采用如下配置方式),此時隻能支援HTTP協定,不支援HTTPS: [java] view plain copy print ?

  1. <bean id="remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">  
  2.             <!--  遠端服務的url-->  
  3.             <property name="serviceUrl" value="${tt.server}/remoteService.remoting" />  
  4.             <!--  遠端服務所實作的接口-->  
  5.         <property name="serviceInterface" value="org.kevin.SimpleService" />  
  6.         </bean>  
<bean id="remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
           	<!--  遠端服務的url-->
    		<property name="serviceUrl" value="${tt.server}/remoteService.remoting" />
    		<!--  遠端服務所實作的接口-->
   		<property name="serviceInterface" value="org.kevin.SimpleService" />
	    </bean>
           

  2.  可以調整為如下,使其同時支援HTTP和HTTPS:            [java] view plain copy print ?

  1. <SPAN style="WHITE-SPACE: pre">     </SPAN><bean id="remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">  
  2.             <!--  遠端服務的url-->  
  3.                         <property name="serviceUrl" value="${tt.server}/remoteService.remoting" />  
  4.                         <!--  遠端服務所實作的接口-->  
  5.                         <property name="serviceInterface" value="org.kevin.SimpleService" />  
  6.                         <property name="httpInvokerRequestExecutor">  
  7.                             <bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"></bean>  
  8.                         </property>  
  9.             </bean>  
<bean id="remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
   			<!--  遠端服務的url-->
                        <property name="serviceUrl" value="${tt.server}/remoteService.remoting" />
                        <!--  遠端服務所實作的接口-->
                        <property name="serviceInterface" value="org.kevin.SimpleService" />
                        <property name="httpInvokerRequestExecutor">
                            <bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"></bean>
                        </property>
           	</bean>
           

                  但問題是又來了,這個httpInvokerRequestExecutor使用的是HttpClient,而這個家夥要求你必須配置證書檔案(配置方法很複雜,還要考慮證書過期更新問題)。   3. 怎麼辦!?改寫一下CommonsHttpInvokerRequestExecutor ,讓他即支援HTTPS同時還不校驗證書(有點安全隐患,不過用該可以接收),于是采用如下配置: [java] view plain copy print ?

  1. <bean id="remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">  
  2.         <!--  遠端服務的url-->  
  3.         <property name="serviceUrl" value="${tt.server}/remoteService.remoting" />  
  4.         <!--  遠端服務所實作的接口-->  
  5.         <property name="serviceInterface" value="org.kevin.SimpleService" />  
  6.         <property name="httpInvokerRequestExecutor">  
  7.                 <bean class="org.kevin.KevinCommonsHttpInvokerRequestExecutor"></bean>  
  8.         </property>  
  9.   </bean>  
<bean id="remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
        	<!--  遠端服務的url-->
        	<property name="serviceUrl" value="${tt.server}/remoteService.remoting" />
        	<!--  遠端服務所實作的接口-->
        	<property name="serviceInterface" value="org.kevin.SimpleService" />
        	<property name="httpInvokerRequestExecutor">
            		<bean class="org.kevin.KevinCommonsHttpInvokerRequestExecutor"></bean>
        	</property>
	    </bean>
           

【示例代碼】 [java] view plain copy print ?

  1. package org.kevin;  
  2. import java.io.IOException;  
  3. import java.net.InetAddress;  
  4. import java.net.Socket;  
  5. import java.net.UnknownHostException;  
  6. import java.security.cert.CertificateException;  
  7. import java.security.cert.X509Certificate;  
  8. import javax.net.ssl.SSLContext;  
  9. import javax.net.ssl.TrustManager;  
  10. import javax.net.ssl.X509TrustManager;  
  11. import org.apache.commons.httpclient.ConnectTimeoutException;  
  12. import org.apache.commons.httpclient.HttpClientError;  
  13. import org.apache.commons.httpclient.params.HttpConnectionParams;  
  14. import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;  
  15. import org.apache.commons.httpclient.protocol.Protocol;  
  16. import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;  
  17. import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;  
  18. import org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor;  
  19. public class KevinCommonsHttpInvokerRequestExecutor extends CommonsHttpInvokerRequestExecutor {  
  20.     static {  
  21.         ProtocolSocketFactory fcty = new MySecureProtocolSocketFactory();  
  22.         Protocol.registerProtocol("https", new Protocol("https", fcty, 443));  
  23.     }  
  24. }  
  25. class MyX509TrustManager implements X509TrustManager {  
  26.     public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {  
  27.     }  
  28.     public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {  
  29.     }  
  30.     public X509Certificate[] getAcceptedIssuers() {  
  31.         return null;  
  32.     }  
  33.     public boolean isClientTrusted(X509Certificate[] arg0) {  
  34.         return false;  
  35.     }  
  36.     public boolean isServerTrusted(X509Certificate[] arg0) {  
  37.         return false;  
  38.     }  
  39. }  
  40. class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory {  
  41.     private SSLContext sslContext = null;  
  42.     public MySecureProtocolSocketFactory() {  
  43.     }  
  44.     private static SSLContext createEasySSLContext() {  
  45.         try {  
  46.             SSLContext context = SSLContext.getInstance("SSL");  
  47.             context.init(null, new TrustManager[] { new MyX509TrustManager() }, null);  
  48.             return context;  
  49.         } catch (Exception e) {  
  50.             throw new HttpClientError(e.toString());  
  51.         }  
  52.     }  
  53.     private SSLContext getSSLContext() {  
  54.         if (this.sslContext == null) {  
  55.             this.sslContext = createEasySSLContext();  
  56.         }  
  57.         return this.sslContext;  
  58.     }  
  59.     public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException,  
  60.             UnknownHostException {  
  61.         return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);  
  62.     }  
  63.     public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort,  
  64.             final HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException {  
  65.         if (params == null) {  
  66.             throw new IllegalArgumentException("Parameters may not be null");  
  67.         }  
  68.         int timeout = params.getConnectionTimeout();  
  69.         if (timeout == 0) {  
  70.             return createSocket(host, port, localAddress, localPort);  
  71.         } else {  
  72.             return ControllerThreadSocketFactory.createSocket(this, host, port, localAddress, localPort, timeout);  
  73.         }  
  74.     }  
  75.     public Socket createSocket(String host, int port) throws IOException, UnknownHostException {  
  76.         return getSSLContext().getSocketFactory().createSocket(host, port);  
  77.     }  
  78.     public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,  
  79.             UnknownHostException {  
  80.         return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);  
  81.     }  
  82. }  
package org.kevin;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpClientError;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
import org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor;

/**
 * <p>
 * Title: HttpInvoker的自定義httpInvokerRequestExecutor實作
 * </p>
 * 
 * <p>
 * Description: 支援HTTP和HTTPS,同時HTTPS不進行證書的校驗
 * </p>
 * 
 * <p>
 * Company: 北京九恒星科技股份有限公司
 * </p>
 * 
 * @author li.wenkai
 * 
 * @since:2011-10-18 下午03:37:03
 * 
 */
public class KevinCommonsHttpInvokerRequestExecutor extends CommonsHttpInvokerRequestExecutor {

	static {
		ProtocolSocketFactory fcty = new MySecureProtocolSocketFactory();
		Protocol.registerProtocol("https", new Protocol("https", fcty, 443));
	}
}

class MyX509TrustManager implements X509TrustManager {

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.
	 * X509Certificate[], java.lang.String)
	 */
	public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.
	 * X509Certificate[], java.lang.String)
	 */
	public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
	 */
	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}

	public boolean isClientTrusted(X509Certificate[] arg0) {
		return false;
	}

	public boolean isServerTrusted(X509Certificate[] arg0) {
		return false;
	}

}

class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory {

	private SSLContext sslContext = null;

	/**
	 * Constructor for MySecureProtocolSocketFactory.
	 */
	public MySecureProtocolSocketFactory() {
	}

	/**
	 * 
	 * @return
	 */
	private static SSLContext createEasySSLContext() {
		try {
			SSLContext context = SSLContext.getInstance("SSL");
			context.init(null, new TrustManager[] { new MyX509TrustManager() }, null);
			return context;
		} catch (Exception e) {
			throw new HttpClientError(e.toString());
		}
	}

	/**
	 * 
	 * @return
	 */
	private SSLContext getSSLContext() {
		if (this.sslContext == null) {
			this.sslContext = createEasySSLContext();
		}
		return this.sslContext;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket
	 * (java.lang.String, int, java.net.InetAddress, int)
	 */
	public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException,
			UnknownHostException {

		return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket
	 * (java.lang.String, int, java.net.InetAddress, int,
	 * org.apache.commons.httpclient.params.HttpConnectionParams)
	 */
	public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort,
			final HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
		if (params == null) {
			throw new IllegalArgumentException("Parameters may not be null");
		}
		int timeout = params.getConnectionTimeout();
		if (timeout == 0) {
			return createSocket(host, port, localAddress, localPort);
		} else {
			return ControllerThreadSocketFactory.createSocket(this, host, port, localAddress, localPort, timeout);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
	 */
	public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
		return getSSLContext().getSocketFactory().createSocket(host, port);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String
	 * ,int,boolean)
	 */
	public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
			UnknownHostException {
		return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
	}
}