HttpInvoker支持不需要证书的HTTPS

【问题】
遇到内部管理非常严格的客户可能存在一套内部系统的部署规范,例如只支持HTTPS协议不支持HTTP,如果系统多出采用HttpInvoker,而此处的配置大多不能直接支持HTTPS。我们可以建议客户同时开放HTTP和HTTPS,对外只开放HTTPS端口,此时物理服务器内部的应用可以使用HTTP协议进行HttpInvoker交互,但如果是分布式部署呢?
 
   【解决办法】
1.  大多的配置如下(很多程序都采用如下配置方式),此时只能支持HTTP协议,不支持HTTPS:
  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:           
  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同时还不校验证书(有点安全隐患,不过用该可以接收),于是采用如下配置:
  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>

【示例代码】
  1. package org.kevin;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetAddress;  
  5. import java.net.Socket;  
  6. import java.net.UnknownHostException;  
  7. import java.security.cert.CertificateException;  
  8. import java.security.cert.X509Certificate;  
  9.   
  10. import javax.net.ssl.SSLContext;  
  11. import javax.net.ssl.TrustManager;  
  12. import javax.net.ssl.X509TrustManager;  
  13.   
  14. import org.apache.commons.httpclient.ConnectTimeoutException;  
  15. import org.apache.commons.httpclient.HttpClientError;  
  16. import org.apache.commons.httpclient.params.HttpConnectionParams;  
  17. import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;  
  18. import org.apache.commons.httpclient.protocol.Protocol;  
  19. import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;  
  20. import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;  
  21. import org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor;  
  22.   
  23. /** 
  24.  * <p> 
  25.  * Title: HttpInvoker的自定义httpInvokerRequestExecutor实现 
  26.  * </p> 
  27.  *  
  28.  * <p> 
  29.  * Description: 支持HTTP和HTTPS,同时HTTPS不进行证书的校验 
  30.  * </p> 
  31.  *  
  32.  * <p> 
  33.  * Company: 北京九恒星科技股份有限公司 
  34.  * </p> 
  35.  *  
  36.  * @author li.wenkai 
  37.  *  
  38.  * @since:2011-10-18 下午03:37:03 
  39.  *  
  40.  */  
  41. public class KevinCommonsHttpInvokerRequestExecutor extends CommonsHttpInvokerRequestExecutor {  
  42.   
  43.     static {  
  44.         ProtocolSocketFactory fcty = new MySecureProtocolSocketFactory();  
  45.         Protocol.registerProtocol("https"new Protocol("https", fcty, 443));  
  46.     }  
  47. }  
  48.   
  49. class MyX509TrustManager implements X509TrustManager {  
  50.   
  51.     /* 
  52.      * (non-Javadoc) 
  53.      *  
  54.      * @see 
  55.      * javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert. 
  56.      * X509Certificate[], java.lang.String) 
  57.      */  
  58.     public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {  
  59.   
  60.     }  
  61.   
  62.     /* 
  63.      * (non-Javadoc) 
  64.      *  
  65.      * @see 
  66.      * javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert. 
  67.      * X509Certificate[], java.lang.String) 
  68.      */  
  69.     public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {  
  70.   
  71.     }  
  72.   
  73.     /* 
  74.      * (non-Javadoc) 
  75.      *  
  76.      * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() 
  77.      */  
  78.     public X509Certificate[] getAcceptedIssuers() {  
  79.         return null;  
  80.     }  
  81.   
  82.     public boolean isClientTrusted(X509Certificate[] arg0) {  
  83.         return false;  
  84.     }  
  85.   
  86.     public boolean isServerTrusted(X509Certificate[] arg0) {  
  87.         return false;  
  88.     }  
  89.   
  90. }  
  91.   
  92. class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory {  
  93.   
  94.     private SSLContext sslContext = null;  
  95.   
  96.     /** 
  97.      * Constructor for MySecureProtocolSocketFactory. 
  98.      */  
  99.     public MySecureProtocolSocketFactory() {  
  100.     }  
  101.   
  102.     /** 
  103.      *  
  104.      * @return 
  105.      */  
  106.     private static SSLContext createEasySSLContext() {  
  107.         try {  
  108.             SSLContext context = SSLContext.getInstance("SSL");  
  109.             context.init(nullnew TrustManager[] { new MyX509TrustManager() }, null);  
  110.             return context;  
  111.         } catch (Exception e) {  
  112.             throw new HttpClientError(e.toString());  
  113.         }  
  114.     }  
  115.   
  116.     /** 
  117.      *  
  118.      * @return 
  119.      */  
  120.     private SSLContext getSSLContext() {  
  121.         if (this.sslContext == null) {  
  122.             this.sslContext = createEasySSLContext();  
  123.         }  
  124.         return this.sslContext;  
  125.     }  
  126.   
  127.     /* 
  128.      * (non-Javadoc) 
  129.      *  
  130.      * @see 
  131.      * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket 
  132.      * (java.lang.String, int, java.net.InetAddress, int) 
  133.      */  
  134.     public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException,  
  135.             UnknownHostException {  
  136.   
  137.         return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);  
  138.     }  
  139.   
  140.     /* 
  141.      * (non-Javadoc) 
  142.      *  
  143.      * @see 
  144.      * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket 
  145.      * (java.lang.String, int, java.net.InetAddress, int, 
  146.      * org.apache.commons.httpclient.params.HttpConnectionParams) 
  147.      */  
  148.     public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort,  
  149.             final HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException {  
  150.         if (params == null) {  
  151.             throw new IllegalArgumentException("Parameters may not be null");  
  152.         }  
  153.         int timeout = params.getConnectionTimeout();  
  154.         if (timeout == 0) {  
  155.             return createSocket(host, port, localAddress, localPort);  
  156.         } else {  
  157.             return ControllerThreadSocketFactory.createSocket(this, host, port, localAddress, localPort, timeout);  
  158.         }  
  159.     }  
  160.   
  161.     /* 
  162.      * (non-Javadoc) 
  163.      *  
  164.      * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) 
  165.      */  
  166.     public Socket createSocket(String host, int port) throws IOException, UnknownHostException {  
  167.         return getSSLContext().getSocketFactory().createSocket(host, port);  
  168.     }  
  169.   
  170.     /* 
  171.      * (non-Javadoc) 
  172.      *  
  173.      * @see 
  174.      * SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String 
  175.      * ,int,boolean) 
  176.      */  
  177.     public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,  
  178.             UnknownHostException {  
  179.         return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);  
  180.     }  
  181. }  
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);
	}
}

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值