1 /**
2 * Copyright 2005-2016 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.log4j.Logger;
34
35 /**
36 * <p>
37 * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s
38 * that accept self-signed certificates.
39 * </p>
40 * <p>
41 * This socket factory SHOULD NOT be used for productive systems
42 * due to security reasons, unless it is a concious decision and
43 * you are perfectly aware of security implications of accepting
44 * self-signed certificates
45 * </p>
46 *
47 * <p>
48 * Example of using custom protocol socket factory for a specific host:
49 * <pre>
50 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
51 *
52 * URI uri = new URI("https://localhost/", true);
53 * // use relative url only
54 * GetMethod httpget = new GetMethod(uri.getPathQuery());
55 * HostConfiguration hc = new HostConfiguration();
56 * hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
57 * HttpClient client = new HttpClient();
58 * client.executeMethod(hc, httpget);
59 * </pre>
60 * </p>
61 * <p>
62 * Example of using custom protocol socket factory per default instead of the standard one:
63 * <pre>
64 * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
65 * Protocol.registerProtocol("https", easyhttps);
66 *
67 * HttpClient client = new HttpClient();
68 * GetMethod httpget = new GetMethod("https://localhost/");
69 * client.executeMethod(httpget);
70 * </pre>
71 * </p>
72 *
73 * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
74 *
75 * <p>
76 * DISCLAIMER: HttpClient developers DO NOT actively support this component.
77 * The component is provided as a reference material, which may be inappropriate
78 * for use without additional customization.
79 * </p>
80 */
81
82 public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory {
83
84 /** Log object for this class. */
85 private static final Logger LOG = Logger.getLogger(EasySSLProtocolSocketFactory.class);
86
87 private SSLContext sslcontext = null;
88
89 /**
90 * Constructor for EasySSLProtocolSocketFactory.
91 */
92 public EasySSLProtocolSocketFactory() {
93 super();
94 }
95
96 private static SSLContext createEasySSLContext() {
97 try {
98 SSLContext context = SSLContext.getInstance("SSL");
99 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 }