1 /* 2 * ==================================================================== 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one or more 5 * contributor license agreements. See the NOTICE file distributed with 6 * this work for additional information regarding copyright ownership. 7 * The ASF licenses this file to You under the Apache License, Version 2.0 8 * (the "License"); you may not use this file except in compliance with 9 * the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * ==================================================================== 19 * 20 * This software consists of voluntary contributions made by many 21 * individuals on behalf of the Apache Software Foundation. For more 22 * information on the Apache Software Foundation, please see 23 * <http://www.apache.org/>. 24 * 25 */ 26 27 package org.apache.commons.httpclient.contrib.ssl; 28 29 import java.io.IOException; 30 import java.net.InetAddress; 31 import java.net.InetSocketAddress; 32 import java.net.Socket; 33 import java.net.SocketAddress; 34 import java.net.UnknownHostException; 35 36 import javax.net.SocketFactory; 37 import javax.net.ssl.SSLContext; 38 import javax.net.ssl.TrustManager; 39 40 import org.apache.commons.httpclient.ConnectTimeoutException; 41 import org.apache.commons.httpclient.HttpClientError; 42 import org.apache.commons.httpclient.params.HttpConnectionParams; 43 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; 44 import org.apache.commons.logging.Log; 45 import org.apache.commons.logging.LogFactory; 46 47 /** 48 * <p> 49 * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s 50 * that accept self-signed certificates. 51 * </p> 52 * <p> 53 * This socket factory SHOULD NOT be used for productive systems 54 * due to security reasons, unless it is a concious decision and 55 * you are perfectly aware of security implications of accepting 56 * self-signed certificates 57 * </p> 58 * 59 * <p> 60 * Example of using custom protocol socket factory for a specific host: 61 * <pre> 62 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); 63 * 64 * URI uri = new URI("https://localhost/", true); 65 * // use relative url only 66 * GetMethod httpget = new GetMethod(uri.getPathQuery()); 67 * HostConfiguration hc = new HostConfiguration(); 68 * hc.setHost(uri.getHost(), uri.getPort(), easyhttps); 69 * HttpClient client = new HttpClient(); 70 * client.executeMethod(hc, httpget); 71 * </pre> 72 * </p> 73 * <p> 74 * Example of using custom protocol socket factory per default instead of the standard one: 75 * <pre> 76 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); 77 * Protocol.registerProtocol("https", easyhttps); 78 * 79 * HttpClient client = new HttpClient(); 80 * GetMethod httpget = new GetMethod("https://localhost/"); 81 * client.executeMethod(httpget); 82 * </pre> 83 * </p> 84 * 85 * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a> 86 * 87 * <p> 88 * DISCLAIMER: HttpClient developers DO NOT actively support this component. 89 * The component is provided as a reference material, which may be inappropriate 90 * for use without additional customization. 91 * </p> 92 */ 93 94 public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory { 95 96 /** Log object for this class. */ 97 private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); 98 99 private SSLContext sslcontext = null; 100 101 /** 102 * Constructor for EasySSLProtocolSocketFactory. 103 */ 104 public EasySSLProtocolSocketFactory() { 105 super(); 106 } 107 108 private static SSLContext createEasySSLContext() { 109 try { 110 SSLContext context = SSLContext.getInstance("SSL"); 111 context.init( 112 null, 113 new TrustManager[] {new EasyX509TrustManager(null)}, 114 null); 115 return context; 116 } catch (Exception e) { 117 LOG.error(e.getMessage(), e); 118 throw new HttpClientError(e.toString()); 119 } 120 } 121 122 private SSLContext getSSLContext() { 123 if (this.sslcontext == null) { 124 this.sslcontext = createEasySSLContext(); 125 } 126 return this.sslcontext; 127 } 128 129 /** 130 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) 131 */ 132 public Socket createSocket( 133 String host, 134 int port, 135 InetAddress clientHost, 136 int clientPort) 137 throws IOException, UnknownHostException { 138 139 return getSSLContext().getSocketFactory().createSocket( 140 host, 141 port, 142 clientHost, 143 clientPort 144 ); 145 } 146 147 /** 148 * Attempts to get a new socket connection to the given host within the given time limit. 149 * <p> 150 * To circumvent the limitations of older JREs that do not support connect timeout a 151 * controller thread is executed. The controller thread attempts to create a new socket 152 * within the given limit of time. If socket constructor does not return until the 153 * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException} 154 * </p> 155 * 156 * @param host the host name/IP 157 * @param port the port on the host 158 * @param clientHost the local host name/IP to bind the socket to 159 * @param clientPort the port on the local machine 160 * @param params {@link HttpConnectionParams Http connection parameters} 161 * 162 * @return Socket a new socket 163 * 164 * @throws IOException if an I/O error occurs while creating the socket 165 * @throws UnknownHostException if the IP address of the host cannot be 166 * determined 167 */ 168 public Socket createSocket( 169 final String host, 170 final int port, 171 final InetAddress localAddress, 172 final int localPort, 173 final HttpConnectionParams params 174 ) throws IOException, UnknownHostException, ConnectTimeoutException { 175 if (params == null) { 176 throw new IllegalArgumentException("Parameters may not be null"); 177 } 178 int timeout = params.getConnectionTimeout(); 179 SocketFactory socketfactory = getSSLContext().getSocketFactory(); 180 if (timeout == 0) { 181 return socketfactory.createSocket(host, port, localAddress, localPort); 182 } else { 183 Socket socket = socketfactory.createSocket(); 184 SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); 185 SocketAddress remoteaddr = new InetSocketAddress(host, port); 186 socket.bind(localaddr); 187 socket.connect(remoteaddr, timeout); 188 return socket; 189 } 190 } 191 192 /** 193 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) 194 */ 195 public Socket createSocket(String host, int port) 196 throws IOException, UnknownHostException { 197 return getSSLContext().getSocketFactory().createSocket( 198 host, 199 port 200 ); 201 } 202 203 /** 204 * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) 205 */ 206 public Socket createSocket( 207 Socket socket, 208 String host, 209 int port, 210 boolean autoClose) 211 throws IOException, UnknownHostException { 212 return getSSLContext().getSocketFactory().createSocket( 213 socket, 214 host, 215 port, 216 autoClose 217 ); 218 } 219 220 public boolean equals(Object obj) { 221 return ((obj != null) && obj.getClass().equals(EasySSLProtocolSocketFactory.class)); 222 } 223 224 public int hashCode() { 225 return EasySSLProtocolSocketFactory.class.hashCode(); 226 } 227 228 }