001 /* 002 * ==================================================================== 003 * 004 * Licensed to the Apache Software Foundation (ASF) under one or more 005 * contributor license agreements. See the NOTICE file distributed with 006 * this work for additional information regarding copyright ownership. 007 * The ASF licenses this file to You under the Apache License, Version 2.0 008 * (the "License"); you may not use this file except in compliance with 009 * the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * ==================================================================== 019 * 020 * This software consists of voluntary contributions made by many 021 * individuals on behalf of the Apache Software Foundation. For more 022 * information on the Apache Software Foundation, please see 023 * <http://www.apache.org/>. 024 * 025 */ 026 027 package org.apache.commons.httpclient.contrib.ssl; 028 029 import java.io.IOException; 030 import java.net.InetAddress; 031 import java.net.InetSocketAddress; 032 import java.net.Socket; 033 import java.net.SocketAddress; 034 import java.net.UnknownHostException; 035 036 import javax.net.SocketFactory; 037 import javax.net.ssl.SSLContext; 038 import javax.net.ssl.TrustManager; 039 040 import org.apache.commons.httpclient.ConnectTimeoutException; 041 import org.apache.commons.httpclient.HttpClientError; 042 import org.apache.commons.httpclient.params.HttpConnectionParams; 043 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; 044 import org.apache.commons.logging.Log; 045 import org.apache.commons.logging.LogFactory; 046 047 /** 048 * <p> 049 * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s 050 * that accept self-signed certificates. 051 * </p> 052 * <p> 053 * This socket factory SHOULD NOT be used for productive systems 054 * due to security reasons, unless it is a concious decision and 055 * you are perfectly aware of security implications of accepting 056 * self-signed certificates 057 * </p> 058 * 059 * <p> 060 * Example of using custom protocol socket factory for a specific host: 061 * <pre> 062 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); 063 * 064 * URI uri = new URI("https://localhost/", true); 065 * // use relative url only 066 * GetMethod httpget = new GetMethod(uri.getPathQuery()); 067 * HostConfiguration hc = new HostConfiguration(); 068 * hc.setHost(uri.getHost(), uri.getPort(), easyhttps); 069 * HttpClient client = new HttpClient(); 070 * client.executeMethod(hc, httpget); 071 * </pre> 072 * </p> 073 * <p> 074 * Example of using custom protocol socket factory per default instead of the standard one: 075 * <pre> 076 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); 077 * Protocol.registerProtocol("https", easyhttps); 078 * 079 * HttpClient client = new HttpClient(); 080 * GetMethod httpget = new GetMethod("https://localhost/"); 081 * client.executeMethod(httpget); 082 * </pre> 083 * </p> 084 * 085 * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a> 086 * 087 * <p> 088 * DISCLAIMER: HttpClient developers DO NOT actively support this component. 089 * The component is provided as a reference material, which may be inappropriate 090 * for use without additional customization. 091 * </p> 092 */ 093 094 public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory { 095 096 /** Log object for this class. */ 097 private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); 098 099 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 }