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.cert.CertificateException;
34  import java.security.cert.X509Certificate;
35  import java.util.concurrent.TimeUnit;
36  
37  import javax.net.ssl.HostnameVerifier;
38  import javax.net.ssl.SSLContext;
39  import javax.net.ssl.SSLException;
40  import javax.net.ssl.SSLServerSocket;
41  import javax.net.ssl.SSLSession;
42  import javax.net.ssl.SSLSocket;
43  
44  import org.apache.http.HttpHost;
45  import org.apache.http.impl.bootstrap.HttpServer;
46  import org.apache.http.impl.bootstrap.SSLServerSetupHandler;
47  import org.apache.http.impl.bootstrap.ServerBootstrap;
48  import org.apache.http.localserver.LocalServerTestBase;
49  import org.apache.http.localserver.SSLTestContexts;
50  import org.apache.http.protocol.BasicHttpContext;
51  import org.apache.http.protocol.HttpContext;
52  import org.apache.http.ssl.SSLContexts;
53  import org.junit.After;
54  import org.junit.Assert;
55  import org.junit.Test;
56  
57  /**
58   * Unit tests for {@link SSLConnectionSocketFactory}.
59   */
60  public class TestSSLSocketFactory {
61  
62      private HttpServer server;
63  
64      @After
65      public void shutDown() throws Exception {
66          if (this.server != null) {
67              this.server.shutdown(10, TimeUnit.SECONDS);
68          }
69      }
70  
71      static class TestX509HostnameVerifier implements HostnameVerifier {
72  
73          private boolean fired = false;
74  
75          @Override
76          public boolean verify(final String host, final SSLSession session) {
77              this.fired = true;
78              return true;
79          }
80  
81          public boolean isFired() {
82              return this.fired;
83          }
84  
85      }
86  
87      @Test
88      public void testBasicSSL() throws Exception {
89          this.server = ServerBootstrap.bootstrap()
90                  .setServerInfo(LocalServerTestBase.ORIGIN)
91                  .setSslContext(SSLTestContexts.createServerSSLContext())
92                  .create();
93          this.server.start();
94  
95          final HttpContext context = new BasicHttpContext();
96          final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
97          final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
98                  SSLTestContexts.createClientSSLContext(), hostVerifier);
99          final Socket socket = socketFactory.createSocket(context);
100         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
101         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
102         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
103         try {
104             final SSLSession sslsession = sslSocket.getSession();
105 
106             Assert.assertNotNull(sslsession);
107             Assert.assertTrue(hostVerifier.isFired());
108         } finally {
109             sslSocket.close();
110         }
111     }
112 
113     @Test
114     public void testBasicDefaultHostnameVerifier() throws Exception {
115         this.server = ServerBootstrap.bootstrap()
116                 .setServerInfo(LocalServerTestBase.ORIGIN)
117                 .setSslContext(SSLTestContexts.createServerSSLContext())
118                 .create();
119         this.server.start();
120 
121         final HttpContext context = new BasicHttpContext();
122         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
123                 SSLTestContexts.createClientSSLContext(), SSLConnectionSocketFactory.getDefaultHostnameVerifier());
124         final Socket socket = socketFactory.createSocket(context);
125         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
126         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
127         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
128         try {
129             final SSLSession sslsession = sslSocket.getSession();
130 
131             Assert.assertNotNull(sslsession);
132         } finally {
133             sslSocket.close();
134         }
135     }
136 
137     @Test
138     public void testClientAuthSSL() throws Exception {
139         this.server = ServerBootstrap.bootstrap()
140                 .setServerInfo(LocalServerTestBase.ORIGIN)
141                 .setSslContext(SSLTestContexts.createServerSSLContext())
142                 .create();
143         this.server.start();
144 
145         final HttpContext context = new BasicHttpContext();
146         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
147         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
148                 SSLTestContexts.createClientSSLContext(), hostVerifier);
149         final Socket socket = socketFactory.createSocket(context);
150         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
151         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
152         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
153         try {
154             final SSLSession sslsession = sslSocket.getSession();
155 
156             Assert.assertNotNull(sslsession);
157             Assert.assertTrue(hostVerifier.isFired());
158         } finally {
159             sslSocket.close();
160         }
161     }
162 
163     @Test(expected=IOException.class)
164     public void testClientAuthSSLFailure() throws Exception {
165         this.server = ServerBootstrap.bootstrap()
166                 .setServerInfo(LocalServerTestBase.ORIGIN)
167                 .setSslContext(SSLTestContexts.createServerSSLContext())
168                 .setSslSetupHandler(new SSLServerSetupHandler() {
169 
170                     @Override
171                     public void initialize(final SSLServerSocket socket) throws SSLException {
172                         socket.setNeedClientAuth(true);
173                     }
174 
175                 })
176                 .create();
177         this.server.start();
178 
179         final HttpContext context = new BasicHttpContext();
180         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
181         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
182                 SSLTestContexts.createClientSSLContext(), hostVerifier);
183         final Socket socket = socketFactory.createSocket(context);
184         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
185         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
186         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
187         try {
188             final SSLSession sslsession = sslSocket.getSession();
189 
190             Assert.assertNotNull(sslsession);
191             Assert.assertTrue(hostVerifier.isFired());
192         } finally {
193             sslSocket.close();
194         }
195     }
196 
197     @Test(expected=SSLException.class)
198     public void testSSLTrustVerification() throws Exception {
199         this.server = ServerBootstrap.bootstrap()
200                 .setServerInfo(LocalServerTestBase.ORIGIN)
201                 .setSslContext(SSLTestContexts.createServerSSLContext())
202                 .create();
203         this.server.start();
204 
205         final HttpContext context = new BasicHttpContext();
206         // Use default SSL context
207         final SSLContext defaultsslcontext = SSLContexts.createDefault();
208 
209         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(defaultsslcontext,
210                 NoopHostnameVerifier.INSTANCE);
211 
212         final Socket socket = socketFactory.createSocket(context);
213         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
214         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
215         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
216         sslSocket.close();
217     }
218 
219     @Test
220     public void testSSLTrustVerificationOverride() throws Exception {
221         this.server = ServerBootstrap.bootstrap()
222                 .setServerInfo(LocalServerTestBase.ORIGIN)
223                 .setSslContext(SSLTestContexts.createServerSSLContext())
224                 .create();
225         this.server.start();
226 
227         final HttpContext context = new BasicHttpContext();
228 
229         final TrustStrategy trustStrategy = new TrustStrategy() {
230 
231             @Override
232             public boolean isTrusted(
233                     final X509Certificate[] chain, final String authType) throws CertificateException {
234                 return chain.length == 1;
235             }
236 
237         };
238         final SSLContext sslcontext = SSLContexts.custom()
239             .loadTrustMaterial(null, trustStrategy)
240             .build();
241         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
242                 sslcontext,
243                 NoopHostnameVerifier.INSTANCE);
244 
245         final Socket socket = socketFactory.createSocket(context);
246         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
247         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
248         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
249         sslSocket.close();
250     }
251 
252     @Test
253     public void testTLSOnly() throws Exception {
254         this.server = ServerBootstrap.bootstrap()
255                 .setServerInfo(LocalServerTestBase.ORIGIN)
256                 .setSslContext(SSLTestContexts.createServerSSLContext())
257                 .setSslSetupHandler(new SSLServerSetupHandler() {
258 
259                     @Override
260                     public void initialize(final SSLServerSocket socket) throws SSLException {
261                         socket.setEnabledProtocols(new String[] {"TLSv1"});
262                     }
263 
264                 })
265                 .create();
266         this.server.start();
267 
268         final HttpContext context = new BasicHttpContext();
269         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
270                 SSLTestContexts.createClientSSLContext());
271         final Socket socket = socketFactory.createSocket(context);
272         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
273         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
274         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
275         final SSLSession sslsession = sslSocket.getSession();
276         Assert.assertNotNull(sslsession);
277     }
278 
279     @Test(expected=IOException.class)
280     public void testSSLDisabledByDefault() throws Exception {
281         this.server = ServerBootstrap.bootstrap()
282                 .setServerInfo(LocalServerTestBase.ORIGIN)
283                 .setSslContext(SSLTestContexts.createServerSSLContext())
284                 .setSslSetupHandler(new SSLServerSetupHandler() {
285 
286                     @Override
287                     public void initialize(final SSLServerSocket socket) throws SSLException {
288                         socket.setEnabledProtocols(new String[] {"SSLv3"});
289                     }
290 
291                 })
292                 .create();
293         this.server.start();
294 
295         final HttpContext context = new BasicHttpContext();
296         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
297                 SSLTestContexts.createClientSSLContext());
298         final Socket socket = socketFactory.createSocket(context);
299         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
300         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
301         socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
302     }
303 }