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