001 /** 002 * Copyright 2005-2011 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.apache.commons.httpclient.contrib.ssl; 017 018 import java.io.IOException; 019 import java.net.InetAddress; 020 import java.net.InetSocketAddress; 021 import java.net.Socket; 022 import java.net.SocketAddress; 023 import java.net.UnknownHostException; 024 025 import javax.net.SocketFactory; 026 import javax.net.ssl.SSLContext; 027 import javax.net.ssl.TrustManager; 028 029 import org.apache.commons.httpclient.ConnectTimeoutException; 030 import org.apache.commons.httpclient.HttpClientError; 031 import org.apache.commons.httpclient.params.HttpConnectionParams; 032 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; 033 import org.apache.commons.logging.Log; 034 import org.apache.commons.logging.LogFactory; 035 036 /** 037 * <p> 038 * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s 039 * that accept self-signed certificates. 040 * </p> 041 * <p> 042 * This socket factory SHOULD NOT be used for productive systems 043 * due to security reasons, unless it is a concious decision and 044 * you are perfectly aware of security implications of accepting 045 * self-signed certificates 046 * </p> 047 * 048 * <p> 049 * Example of using custom protocol socket factory for a specific host: 050 * <pre> 051 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); 052 * 053 * URI uri = new URI("https://localhost/", true); 054 * // use relative url only 055 * GetMethod httpget = new GetMethod(uri.getPathQuery()); 056 * HostConfiguration hc = new HostConfiguration(); 057 * hc.setHost(uri.getHost(), uri.getPort(), easyhttps); 058 * HttpClient client = new HttpClient(); 059 * client.executeMethod(hc, httpget); 060 * </pre> 061 * </p> 062 * <p> 063 * Example of using custom protocol socket factory per default instead of the standard one: 064 * <pre> 065 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); 066 * Protocol.registerProtocol("https", easyhttps); 067 * 068 * HttpClient client = new HttpClient(); 069 * GetMethod httpget = new GetMethod("https://localhost/"); 070 * client.executeMethod(httpget); 071 * </pre> 072 * </p> 073 * 074 * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a> 075 * 076 * <p> 077 * DISCLAIMER: HttpClient developers DO NOT actively support this component. 078 * The component is provided as a reference material, which may be inappropriate 079 * for use without additional customization. 080 * </p> 081 */ 082 083 public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory { 084 085 /** Log object for this class. */ 086 private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); 087 088 private SSLContext sslcontext = null; 089 090 /** 091 * Constructor for EasySSLProtocolSocketFactory. 092 */ 093 public EasySSLProtocolSocketFactory() { 094 super(); 095 } 096 097 private static SSLContext createEasySSLContext() { 098 try { 099 SSLContext context = SSLContext.getInstance("SSL"); 100 context.init( 101 null, 102 new TrustManager[] {new EasyX509TrustManager(null)}, 103 null); 104 return context; 105 } catch (Exception e) { 106 LOG.error(e.getMessage(), e); 107 throw new HttpClientError(e.toString()); 108 } 109 } 110 111 private SSLContext getSSLContext() { 112 if (this.sslcontext == null) { 113 this.sslcontext = createEasySSLContext(); 114 } 115 return this.sslcontext; 116 } 117 118 /** 119 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) 120 */ 121 public Socket createSocket( 122 String host, 123 int port, 124 InetAddress clientHost, 125 int clientPort) 126 throws IOException, UnknownHostException { 127 128 return getSSLContext().getSocketFactory().createSocket( 129 host, 130 port, 131 clientHost, 132 clientPort 133 ); 134 } 135 136 /** 137 * Attempts to get a new socket connection to the given host within the given time limit. 138 * <p> 139 * To circumvent the limitations of older JREs that do not support connect timeout a 140 * controller thread is executed. The controller thread attempts to create a new socket 141 * within the given limit of time. If socket constructor does not return until the 142 * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException} 143 * </p> 144 * 145 * @param host the host name/IP 146 * @param port the port on the host 147 * @param clientHost the local host name/IP to bind the socket to 148 * @param clientPort the port on the local machine 149 * @param params {@link HttpConnectionParams Http connection parameters} 150 * 151 * @return Socket a new socket 152 * 153 * @throws IOException if an I/O error occurs while creating the socket 154 * @throws UnknownHostException if the IP address of the host cannot be 155 * determined 156 */ 157 public Socket createSocket( 158 final String host, 159 final int port, 160 final InetAddress localAddress, 161 final int localPort, 162 final HttpConnectionParams params 163 ) throws IOException, UnknownHostException, ConnectTimeoutException { 164 if (params == null) { 165 throw new IllegalArgumentException("Parameters may not be null"); 166 } 167 int timeout = params.getConnectionTimeout(); 168 SocketFactory socketfactory = getSSLContext().getSocketFactory(); 169 if (timeout == 0) { 170 return socketfactory.createSocket(host, port, localAddress, localPort); 171 } else { 172 Socket socket = socketfactory.createSocket(); 173 SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); 174 SocketAddress remoteaddr = new InetSocketAddress(host, port); 175 socket.bind(localaddr); 176 socket.connect(remoteaddr, timeout); 177 return socket; 178 } 179 } 180 181 /** 182 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) 183 */ 184 public Socket createSocket(String host, int port) 185 throws IOException, UnknownHostException { 186 return getSSLContext().getSocketFactory().createSocket( 187 host, 188 port 189 ); 190 } 191 192 /** 193 * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) 194 */ 195 public Socket createSocket( 196 Socket socket, 197 String host, 198 int port, 199 boolean autoClose) 200 throws IOException, UnknownHostException { 201 return getSSLContext().getSocketFactory().createSocket( 202 socket, 203 host, 204 port, 205 autoClose 206 ); 207 } 208 209 public boolean equals(Object obj) { 210 return ((obj != null) && obj.getClass().equals(EasySSLProtocolSocketFactory.class)); 211 } 212 213 public int hashCode() { 214 return EasySSLProtocolSocketFactory.class.hashCode(); 215 } 216 217 }