View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.conn.ssl;
29  
30  import java.io.IOException;
31  import java.net.InetSocketAddress;
32  import java.net.Socket;
33  import java.security.KeyManagementException;
34  import java.security.KeyStoreException;
35  import java.security.NoSuchAlgorithmException;
36  import java.security.cert.CertificateException;
37  import java.security.cert.X509Certificate;
38  import java.util.concurrent.TimeUnit;
39  
40  import javax.net.ssl.HostnameVerifier;
41  import javax.net.ssl.SSLContext;
42  import javax.net.ssl.SSLException;
43  import javax.net.ssl.SSLServerSocket;
44  import javax.net.ssl.SSLSession;
45  import javax.net.ssl.SSLSocket;
46  
47  import org.apache.http.HttpHost;
48  import org.apache.http.impl.bootstrap.HttpServer;
49  import org.apache.http.impl.bootstrap.SSLServerSetupHandler;
50  import org.apache.http.impl.bootstrap.ServerBootstrap;
51  import org.apache.http.localserver.LocalServerTestBase;
52  import org.apache.http.localserver.SSLTestContexts;
53  import org.apache.http.protocol.BasicHttpContext;
54  import org.apache.http.protocol.HttpContext;
55  import org.apache.http.ssl.SSLContexts;
56  import org.junit.After;
57  import org.junit.Assert;
58  import org.junit.Test;
59  
60  /**
61   * Unit tests for {@link SSLConnectionSocketFactory}.
62   */
63  public class TestSSLSocketFactory {
64  
65      private HttpServer server;
66  
67      @After
68      public void shutDown() throws Exception {
69          if (this.server != null) {
70              this.server.shutdown(10, TimeUnit.SECONDS);
71          }
72      }
73  
74      static class TestX509HostnameVerifier implements HostnameVerifier {
75  
76          private boolean fired = false;
77  
78          @Override
79          public boolean verify(final String host, final SSLSession session) {
80              this.fired = true;
81              return true;
82          }
83  
84          public boolean isFired() {
85              return this.fired;
86          }
87  
88      }
89  
90      @Test
91      public void testBasicSSL() throws Exception {
92          // @formatter:off
93          this.server = ServerBootstrap.bootstrap()
94                  .setServerInfo(LocalServerTestBase.ORIGIN)
95                  .setSslContext(SSLTestContexts.createServerSSLContext())
96                  .create();
97          // @formatter:on
98          this.server.start();
99  
100         final HttpContext context = new BasicHttpContext();
101         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
102         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
103                 SSLTestContexts.createClientSSLContext(), hostVerifier);
104         final Socket socket = socketFactory.createSocket(context);
105         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
106         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
107         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
108                 context);
109         try {
110             final SSLSession sslsession = sslSocket.getSession();
111 
112             Assert.assertNotNull(sslsession);
113             Assert.assertTrue(hostVerifier.isFired());
114         } finally {
115             sslSocket.close();
116         }
117     }
118 
119     @Test
120     public void testBasicDefaultHostnameVerifier() throws Exception {
121         // @formatter:off
122         this.server = ServerBootstrap.bootstrap()
123                 .setServerInfo(LocalServerTestBase.ORIGIN)
124                 .setSslContext(SSLTestContexts.createServerSSLContext())
125                 .create();
126         // @formatter:on
127         this.server.start();
128 
129         final HttpContext context = new BasicHttpContext();
130         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
131                 SSLTestContexts.createClientSSLContext(), SSLConnectionSocketFactory.getDefaultHostnameVerifier());
132         final Socket socket = socketFactory.createSocket(context);
133         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
134         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
135         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
136                 context);
137         try {
138             final SSLSession sslsession = sslSocket.getSession();
139 
140             Assert.assertNotNull(sslsession);
141         } finally {
142             sslSocket.close();
143         }
144     }
145 
146     @Test
147     public void testClientAuthSSL() throws Exception {
148         // @formatter:off
149         this.server = ServerBootstrap.bootstrap()
150                 .setServerInfo(LocalServerTestBase.ORIGIN)
151                 .setSslContext(SSLTestContexts.createServerSSLContext())
152                 .create();
153         // @formatter:on
154         this.server.start();
155 
156         final HttpContext context = new BasicHttpContext();
157         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
158         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
159                 SSLTestContexts.createClientSSLContext(), hostVerifier);
160         final Socket socket = socketFactory.createSocket(context);
161         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
162         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
163         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
164                 context);
165         try {
166             final SSLSession sslsession = sslSocket.getSession();
167 
168             Assert.assertNotNull(sslsession);
169             Assert.assertTrue(hostVerifier.isFired());
170         } finally {
171             sslSocket.close();
172         }
173     }
174 
175     @Test(expected = IOException.class)
176     public void testClientAuthSSLFailure() throws Exception {
177         // @formatter:off
178         this.server = ServerBootstrap.bootstrap()
179                 .setServerInfo(LocalServerTestBase.ORIGIN)
180                 .setSslContext(SSLTestContexts.createServerSSLContext())
181                 .setSslSetupHandler(new SSLServerSetupHandler() {
182 
183                     @Override
184                     public void initialize(final SSLServerSocket socket) throws SSLException {
185                         socket.setNeedClientAuth(true);
186                     }
187 
188                 })
189                 .create();
190         // @formatter:on
191         this.server.start();
192 
193         final HttpContext context = new BasicHttpContext();
194         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
195         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
196                 SSLTestContexts.createClientSSLContext(), hostVerifier);
197         final Socket socket = socketFactory.createSocket(context);
198         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
199         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
200         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
201                 context);
202         try {
203             final SSLSession sslsession = sslSocket.getSession();
204 
205             Assert.assertNotNull(sslsession);
206             Assert.assertTrue(hostVerifier.isFired());
207         } finally {
208             sslSocket.close();
209         }
210     }
211 
212     @Test(expected = SSLException.class)
213     public void testSSLTrustVerification() throws Exception {
214         // @formatter:off
215         this.server = ServerBootstrap.bootstrap()
216                 .setServerInfo(LocalServerTestBase.ORIGIN)
217                 .setSslContext(SSLTestContexts.createServerSSLContext())
218                 .create();
219         // @formatter:on
220         this.server.start();
221 
222         final HttpContext context = new BasicHttpContext();
223         // Use default SSL context
224         final SSLContext defaultsslcontext = SSLContexts.createDefault();
225 
226         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(defaultsslcontext,
227                 NoopHostnameVerifier.INSTANCE);
228 
229         final Socket socket = socketFactory.createSocket(context);
230         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
231         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
232         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
233                 context);
234         sslSocket.close();
235     }
236 
237     @Test
238     public void testSSLTrustVerificationOverrideWithCustsom() throws Exception {
239         final TrustStrategy trustStrategy = new TrustStrategy() {
240 
241             @Override
242             public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
243                 return chain.length == 1;
244             }
245 
246         };
247         testSSLTrustVerificationOverride(trustStrategy);
248     }
249 
250     @Test
251     public void testSSLTrustVerificationOverrideWithTrustSelfSignedStrategy() throws Exception {
252         testSSLTrustVerificationOverride(TrustSelfSignedStrategy.INSTANCE);
253     }
254 
255     @Test
256     public void testSSLTrustVerificationOverrideWithTrustAllStrategy() throws Exception {
257         testSSLTrustVerificationOverride(TrustAllStrategy.INSTANCE);
258     }
259 
260     private void testSSLTrustVerificationOverride(final TrustStrategy trustStrategy)
261             throws Exception, IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
262         // @formatter:off
263         this.server = ServerBootstrap.bootstrap()
264                 .setServerInfo(LocalServerTestBase.ORIGIN)
265                 .setSslContext(SSLTestContexts.createServerSSLContext())
266                 .create();
267         // @formatter:on
268         this.server.start();
269 
270         final HttpContext context = new BasicHttpContext();
271 
272         // @formatter:off
273         final SSLContext sslcontext = SSLContexts.custom()
274             .loadTrustMaterial(null, trustStrategy)
275             .build();
276         // @formatter:on
277         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext,
278                 NoopHostnameVerifier.INSTANCE);
279 
280         final Socket socket = socketFactory.createSocket(context);
281         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
282         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
283         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
284                 context);
285         sslSocket.close();
286     }
287 
288     @Test
289     public void testTLSOnly() throws Exception {
290         // @formatter:off
291         this.server = ServerBootstrap.bootstrap()
292                 .setServerInfo(LocalServerTestBase.ORIGIN)
293                 .setSslContext(SSLTestContexts.createServerSSLContext())
294                 .setSslSetupHandler(new SSLServerSetupHandler() {
295 
296                     @Override
297                     public void initialize(final SSLServerSocket socket) throws SSLException {
298                         socket.setEnabledProtocols(new String[] {"TLSv1"});
299                     }
300 
301                 })
302                 .create();
303         // @formatter:on
304         this.server.start();
305 
306         final HttpContext context = new BasicHttpContext();
307         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
308                 SSLTestContexts.createClientSSLContext());
309         final Socket socket = socketFactory.createSocket(context);
310         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
311         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
312         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
313                 context);
314         final SSLSession sslsession = sslSocket.getSession();
315         Assert.assertNotNull(sslsession);
316     }
317 
318     @Test(expected = IOException.class)
319     public void testSSLDisabledByDefault() throws Exception {
320         // @formatter:off
321         this.server = ServerBootstrap.bootstrap()
322                 .setServerInfo(LocalServerTestBase.ORIGIN)
323                 .setSslContext(SSLTestContexts.createServerSSLContext())
324                 .setSslSetupHandler(new SSLServerSetupHandler() {
325 
326                     @Override
327                     public void initialize(final SSLServerSocket socket) throws SSLException {
328                         socket.setEnabledProtocols(new String[] {"SSLv3"});
329                     }
330 
331                 })
332                 .create();
333         // @formatter:on
334         this.server.start();
335 
336         final HttpContext context = new BasicHttpContext();
337         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
338                 SSLTestContexts.createClientSSLContext());
339         final Socket socket = socketFactory.createSocket(context);
340         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
341         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
342         socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
343     }
344 }