View Javadoc

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 }