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