1 /**
2 * Copyright 2005-2011 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/ecl2.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.httpclient.contrib.ssl;
17
18 import java.io.IOException;
19 import java.net.InetAddress;
20 import java.net.InetSocketAddress;
21 import java.net.Socket;
22 import java.net.SocketAddress;
23 import java.net.UnknownHostException;
24
25 import javax.net.SocketFactory;
26 import javax.net.ssl.SSLContext;
27 import javax.net.ssl.TrustManager;
28
29 import org.apache.commons.httpclient.ConnectTimeoutException;
30 import org.apache.commons.httpclient.HttpClientError;
31 import org.apache.commons.httpclient.params.HttpConnectionParams;
32 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35
36 /**
37 * <p>
38 * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s
39 * that accept self-signed certificates.
40 * </p>
41 * <p>
42 * This socket factory SHOULD NOT be used for productive systems
43 * due to security reasons, unless it is a concious decision and
44 * you are perfectly aware of security implications of accepting
45 * self-signed certificates
46 * </p>
47 *
48 * <p>
49 * Example of using custom protocol socket factory for a specific host:
50 * <pre>
51 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
52 *
53 * URI uri = new URI("https://localhost/", true);
54 * // use relative url only
55 * GetMethod httpget = new GetMethod(uri.getPathQuery());
56 * HostConfiguration hc = new HostConfiguration();
57 * hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
58 * HttpClient client = new HttpClient();
59 * client.executeMethod(hc, httpget);
60 * </pre>
61 * </p>
62 * <p>
63 * Example of using custom protocol socket factory per default instead of the standard one:
64 * <pre>
65 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
66 * Protocol.registerProtocol("https", easyhttps);
67 *
68 * HttpClient client = new HttpClient();
69 * GetMethod httpget = new GetMethod("https://localhost/");
70 * client.executeMethod(httpget);
71 * </pre>
72 * </p>
73 *
74 * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
75 *
76 * <p>
77 * DISCLAIMER: HttpClient developers DO NOT actively support this component.
78 * The component is provided as a reference material, which may be inappropriate
79 * for use without additional customization.
80 * </p>
81 */
82
83 public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory {
84
85 /** Log object for this class. */
86 private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class);
87
88 private SSLContext sslcontext = null;
89
90 /**
91 * Constructor for EasySSLProtocolSocketFactory.
92 */
93 public EasySSLProtocolSocketFactory() {
94 super();
95 }
96
97 private static SSLContext createEasySSLContext() {
98 try {
99 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 }