1 | /* |
2 | * $Header$ |
3 | * $Revision: 10 $ |
4 | * $Date: 2006-02-16 19:35:22 +0700 (Thu, 16 Feb 2006) $ |
5 | * |
6 | * ==================================================================== |
7 | * |
8 | * Copyright 2002-2004 The Apache Software Foundation |
9 | * |
10 | * Licensed under the Apache License, Version 2.0 (the "License"); |
11 | * you may not use this file except in compliance with the License. |
12 | * You may obtain a copy of the License at |
13 | * |
14 | * http://www.apache.org/licenses/LICENSE-2.0 |
15 | * |
16 | * Unless required by applicable law or agreed to in writing, software |
17 | * distributed under the License is distributed on an "AS IS" BASIS, |
18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
19 | * See the License for the specific language governing permissions and |
20 | * limitations under the License. |
21 | * ==================================================================== |
22 | * |
23 | * This software consists of voluntary contributions made by many |
24 | * individuals on behalf of the Apache Software Foundation. For more |
25 | * information on the Apache Software Foundation, please see |
26 | * <http://www.apache.org/>. |
27 | * |
28 | */ |
29 | |
30 | package org.apache.commons.httpclient.contrib.ssl; |
31 | |
32 | import java.io.IOException; |
33 | import java.net.InetAddress; |
34 | import java.net.Socket; |
35 | import java.net.UnknownHostException; |
36 | |
37 | import org.apache.commons.httpclient.ConnectTimeoutException; |
38 | import org.apache.commons.httpclient.HttpClientError; |
39 | import org.apache.commons.httpclient.params.HttpConnectionParams; |
40 | import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory; |
41 | import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; |
42 | import org.apache.commons.logging.Log; |
43 | import org.apache.commons.logging.LogFactory; |
44 | |
45 | import javax.net.ssl.SSLContext; |
46 | import javax.net.ssl.TrustManager; |
47 | |
48 | /** |
49 | * <p> |
50 | * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s |
51 | * that accept self-signed certificates. |
52 | * </p> |
53 | * <p> |
54 | * This socket factory SHOULD NOT be used for productive systems |
55 | * due to security reasons, unless it is a concious decision and |
56 | * you are perfectly aware of security implications of accepting |
57 | * self-signed certificates |
58 | * </p> |
59 | * |
60 | * <p> |
61 | * Example of using custom protocol socket factory for a specific host: |
62 | * <pre> |
63 | * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); |
64 | * |
65 | * HttpClient client = new HttpClient(); |
66 | * client.getHostConfiguration().setHost("localhost", 443, easyhttps); |
67 | * // use relative url only |
68 | * GetMethod httpget = new GetMethod("/"); |
69 | * client.executeMethod(httpget); |
70 | * </pre> |
71 | * </p> |
72 | * <p> |
73 | * Example of using custom protocol socket factory per default instead of the standard one: |
74 | * <pre> |
75 | * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); |
76 | * Protocol.registerProtocol("https", easyhttps); |
77 | * |
78 | * HttpClient client = new HttpClient(); |
79 | * GetMethod httpget = new GetMethod("https://localhost/"); |
80 | * client.executeMethod(httpget); |
81 | * </pre> |
82 | * </p> |
83 | * |
84 | * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a> |
85 | * |
86 | * <p> |
87 | * DISCLAIMER: HttpClient developers DO NOT actively support this component. |
88 | * The component is provided as a reference material, which may be inappropriate |
89 | * for use without additional customization. |
90 | * </p> |
91 | */ |
92 | |
93 | public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory { |
94 | |
95 | /** Log object for this class. */ |
96 | private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); |
97 | |
98 | private SSLContext sslcontext = null; |
99 | |
100 | /** |
101 | * Constructor for EasySSLProtocolSocketFactory. |
102 | */ |
103 | public EasySSLProtocolSocketFactory() { |
104 | super(); |
105 | } |
106 | |
107 | private static SSLContext createEasySSLContext() { |
108 | try { |
109 | SSLContext context = SSLContext.getInstance("SSL"); |
110 | context.init( |
111 | null, |
112 | new TrustManager[] {new EasyX509TrustManager(null)}, |
113 | null); |
114 | return context; |
115 | } catch (Exception e) { |
116 | LOG.error(e.getMessage(), e); |
117 | throw new HttpClientError(e.toString()); |
118 | } |
119 | } |
120 | |
121 | private SSLContext getSSLContext() { |
122 | if (this.sslcontext == null) { |
123 | this.sslcontext = createEasySSLContext(); |
124 | } |
125 | return this.sslcontext; |
126 | } |
127 | |
128 | /** |
129 | * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) |
130 | */ |
131 | public Socket createSocket( |
132 | String host, |
133 | int port, |
134 | InetAddress clientHost, |
135 | int clientPort) |
136 | throws IOException, UnknownHostException { |
137 | |
138 | return getSSLContext().getSocketFactory().createSocket( |
139 | host, |
140 | port, |
141 | clientHost, |
142 | clientPort |
143 | ); |
144 | } |
145 | |
146 | /** |
147 | * Attempts to get a new socket connection to the given host within the given time limit. |
148 | * <p> |
149 | * To circumvent the limitations of older JREs that do not support connect timeout a |
150 | * controller thread is executed. The controller thread attempts to create a new socket |
151 | * within the given limit of time. If socket constructor does not return until the |
152 | * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException} |
153 | * </p> |
154 | * |
155 | * @param host the host name/IP |
156 | * @param port the port on the host |
157 | * @param localAddress the local host name/IP to bind the socket to |
158 | * @param localPort the port on the local machine |
159 | * @param params {@link HttpConnectionParams Http connection parameters} |
160 | * |
161 | * @return Socket a new socket |
162 | * |
163 | * @throws IOException if an I/O error occurs while creating the socket |
164 | * @throws UnknownHostException if the IP address of the host cannot be |
165 | * determined |
166 | */ |
167 | public Socket createSocket( |
168 | final String host, |
169 | final int port, |
170 | final InetAddress localAddress, |
171 | final int localPort, |
172 | final HttpConnectionParams params |
173 | ) throws IOException, UnknownHostException, ConnectTimeoutException { |
174 | if (params == null) { |
175 | throw new IllegalArgumentException("Parameters may not be null"); |
176 | } |
177 | int timeout = params.getConnectionTimeout(); |
178 | if (timeout == 0) { |
179 | return createSocket(host, port, localAddress, localPort); |
180 | } else { |
181 | // To be eventually deprecated when migrated to Java 1.4 or above |
182 | return ControllerThreadSocketFactory.createSocket( |
183 | this, host, port, localAddress, localPort, timeout); |
184 | } |
185 | } |
186 | |
187 | /** |
188 | * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) |
189 | */ |
190 | public Socket createSocket(String host, int port) |
191 | throws IOException, UnknownHostException { |
192 | return getSSLContext().getSocketFactory().createSocket( |
193 | host, |
194 | port |
195 | ); |
196 | } |
197 | |
198 | /** |
199 | * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) |
200 | */ |
201 | public Socket createSocket( |
202 | Socket socket, |
203 | String host, |
204 | int port, |
205 | boolean autoClose) |
206 | throws IOException, UnknownHostException { |
207 | return getSSLContext().getSocketFactory().createSocket( |
208 | socket, |
209 | host, |
210 | port, |
211 | autoClose |
212 | ); |
213 | } |
214 | |
215 | public boolean equals(Object obj) { |
216 | return ((obj != null) && obj.getClass().equals(EasySSLProtocolSocketFactory.class)); |
217 | } |
218 | |
219 | public int hashCode() { |
220 | return EasySSLProtocolSocketFactory.class.hashCode(); |
221 | } |
222 | |
223 | } |