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 }