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.Map;
36  import java.util.concurrent.TimeUnit;
37  
38  import javax.net.ssl.HostnameVerifier;
39  import javax.net.ssl.SSLContext;
40  import javax.net.ssl.SSLHandshakeException;
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.ServerBootstrap;
47  import org.apache.http.localserver.LocalServerTestBase;
48  import org.apache.http.localserver.SSLTestContexts;
49  import org.apache.http.protocol.BasicHttpContext;
50  import org.apache.http.protocol.HttpContext;
51  import org.junit.After;
52  import org.junit.Assert;
53  import org.junit.Ignore;
54  import org.junit.Test;
55  
56  /**
57   * Unit tests for {@link SSLConnectionSocketFactory}.
58   */
59  public class TestSSLSocketFactory {
60  
61      private HttpServer server;
62  
63      @After
64      public void shutDown() throws Exception {
65          if (this.server != null) {
66              this.server.shutdown(10, TimeUnit.SECONDS);
67          }
68      }
69  
70      static class TestX509HostnameVerifier implements HostnameVerifier {
71  
72          private boolean fired = false;
73  
74          @Override
75          public boolean verify(final String host, final SSLSession session) {
76              this.fired = true;
77              return true;
78          }
79  
80          public boolean isFired() {
81              return this.fired;
82          }
83  
84      }
85  
86      @Test
87      public void testBasicSSL() throws Exception {
88          this.server = ServerBootstrap.bootstrap()
89                  .setServerInfo(LocalServerTestBase.ORIGIN)
90                  .setSslContext(SSLTestContexts.createServerSSLContext())
91                  .create();
92          this.server.start();
93  
94          final HttpContext context = new BasicHttpContext();
95          final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
96          final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
97                  SSLTestContexts.createClientSSLContext(), hostVerifier);
98          final Socket socket = socketFactory.createSocket(context);
99          final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
100         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
101         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
102         try {
103             final SSLSession sslsession = sslSocket.getSession();
104 
105             Assert.assertNotNull(sslsession);
106             Assert.assertTrue(hostVerifier.isFired());
107         } finally {
108             sslSocket.close();
109         }
110     }
111 
112     @Test
113     public void testClientAuthSSL() throws Exception {
114         this.server = ServerBootstrap.bootstrap()
115                 .setServerInfo(LocalServerTestBase.ORIGIN)
116                 .setSslContext(SSLTestContexts.createServerSSLContext())
117                 .create();
118         this.server.start();
119 
120         final HttpContext context = new BasicHttpContext();
121         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
122         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
123                 SSLTestContexts.createClientSSLContext(), hostVerifier);
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             Assert.assertTrue(hostVerifier.isFired());
133         } finally {
134             sslSocket.close();
135         }
136     }
137 
138     @Ignore("There is no way to force client auth with HttpServer in 4.4a1")
139     @Test(expected=IOException.class)
140     public void testClientAuthSSLFailure() throws Exception {
141         this.server = ServerBootstrap.bootstrap()
142                 .setServerInfo(LocalServerTestBase.ORIGIN)
143                 .setSslContext(SSLTestContexts.createServerSSLContext())
144                 .create();
145         this.server.start();
146 
147         final HttpContext context = new BasicHttpContext();
148         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
149         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
150                 SSLTestContexts.createClientSSLContext(), hostVerifier);
151         final Socket socket = socketFactory.createSocket(context);
152         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
153         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
154         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
155         try {
156             final SSLSession sslsession = sslSocket.getSession();
157 
158             Assert.assertNotNull(sslsession);
159             Assert.assertTrue(hostVerifier.isFired());
160         } finally {
161             sslSocket.close();
162         }
163     }
164 
165     @Test
166     public void testClientAuthSSLAliasChoice() throws Exception {
167         // TODO unused - is there a bug in the test?
168         final PrivateKeyStrategy aliasStrategy = new PrivateKeyStrategy() {
169 
170             @Override
171             public String chooseAlias(
172                     final Map<String, PrivateKeyDetails> aliases, final Socket socket) {
173                 Assert.assertEquals(2, aliases.size());
174                 Assert.assertTrue(aliases.containsKey("hc-test-key-1"));
175                 Assert.assertTrue(aliases.containsKey("hc-test-key-2"));
176                 return "hc-test-key-2";
177             }
178 
179         };
180 
181         this.server = ServerBootstrap.bootstrap()
182                 .setServerInfo(LocalServerTestBase.ORIGIN)
183                 .setSslContext(SSLTestContexts.createServerSSLContext())
184                 .create();
185         this.server.start();
186 
187         final HttpContext context = new BasicHttpContext();
188         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
189         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
190                 SSLTestContexts.createClientSSLContext(), hostVerifier);
191         final Socket socket = socketFactory.createSocket(context);
192         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
193         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
194         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
195         try {
196             final SSLSession sslsession = sslSocket.getSession();
197 
198             Assert.assertNotNull(sslsession);
199             Assert.assertTrue(hostVerifier.isFired());
200         } finally {
201             sslSocket.close();
202         }
203     }
204 
205     @Test(expected=SSLHandshakeException.class)
206     public void testSSLTrustVerification() throws Exception {
207         this.server = ServerBootstrap.bootstrap()
208                 .setServerInfo(LocalServerTestBase.ORIGIN)
209                 .setSslContext(SSLTestContexts.createServerSSLContext())
210                 .create();
211         this.server.start();
212 
213         final HttpContext context = new BasicHttpContext();
214         // Use default SSL context
215         final SSLContext defaultsslcontext = SSLContexts.createDefault();
216 
217         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(defaultsslcontext,
218                 NoopHostnameVerifier.INSTANCE);
219 
220         final Socket socket = socketFactory.createSocket(context);
221         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
222         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
223         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
224         sslSocket.close();
225     }
226 
227     @Test
228     public void testSSLTrustVerificationOverride() throws Exception {
229         this.server = ServerBootstrap.bootstrap()
230                 .setServerInfo(LocalServerTestBase.ORIGIN)
231                 .setSslContext(SSLTestContexts.createServerSSLContext())
232                 .create();
233         this.server.start();
234 
235         final HttpContext context = new BasicHttpContext();
236 
237         final TrustStrategy trustStrategy = new TrustStrategy() {
238 
239             @Override
240             public boolean isTrusted(
241                     final X509Certificate[] chain, final String authType) throws CertificateException {
242                 return chain.length == 1;
243             }
244 
245         };
246         final SSLContext sslcontext = SSLContexts.custom()
247             .loadTrustMaterial(null, trustStrategy)
248             .build();
249         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
250                 sslcontext,
251                 NoopHostnameVerifier.INSTANCE);
252 
253         final Socket socket = socketFactory.createSocket(context);
254         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
255         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
256         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
257         sslSocket.close();
258     }
259 
260 }