001 /**
002 * Copyright 2005-2014 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 }