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.SSLContext;
39  import javax.net.ssl.SSLException;
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 X509HostnameVerifier {
71  
72          private boolean fired = false;
73  
74          @Override
75          public boolean verify(final String host, final SSLSession session) {
76              return true;
77          }
78  
79          @Override
80          public void verify(final String host, final SSLSocket ssl) throws IOException {
81              this.fired = true;
82          }
83  
84          @Override
85          public void verify(final String host, final String[] cns, final String[] subjectAlts) throws SSLException {
86          }
87  
88          @Override
89          public void verify(final String host, final X509Certificate cert) throws SSLException {
90          }
91  
92          public boolean isFired() {
93              return this.fired;
94          }
95  
96      }
97  
98      @Test
99      public void testBasicSSL() throws Exception {
100         this.server = ServerBootstrap.bootstrap()
101                 .setServerInfo(LocalServerTestBase.ORIGIN)
102                 .setSslContext(SSLTestContexts.createServerSSLContext())
103                 .create();
104         this.server.start();
105 
106         final HttpContext context = new BasicHttpContext();
107         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
108         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
109                 SSLTestContexts.createClientSSLContext(), hostVerifier);
110         final Socket socket = socketFactory.createSocket(context);
111         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
112         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
113         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
114         try {
115             final SSLSession sslsession = sslSocket.getSession();
116 
117             Assert.assertNotNull(sslsession);
118             Assert.assertTrue(hostVerifier.isFired());
119         } finally {
120             sslSocket.close();
121         }
122     }
123 
124     @Test
125     public void testClientAuthSSL() throws Exception {
126         this.server = ServerBootstrap.bootstrap()
127                 .setServerInfo(LocalServerTestBase.ORIGIN)
128                 .setSslContext(SSLTestContexts.createServerSSLContext())
129                 .create();
130         this.server.start();
131 
132         final HttpContext context = new BasicHttpContext();
133         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
134         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
135                 SSLTestContexts.createClientSSLContext(), hostVerifier);
136         final Socket socket = socketFactory.createSocket(context);
137         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
138         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
139         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
140         try {
141             final SSLSession sslsession = sslSocket.getSession();
142 
143             Assert.assertNotNull(sslsession);
144             Assert.assertTrue(hostVerifier.isFired());
145         } finally {
146             sslSocket.close();
147         }
148     }
149 
150     @Ignore("There is no way to force client auth with HttpServer in 4.4a1")
151     @Test(expected=IOException.class)
152     public void testClientAuthSSLFailure() throws Exception {
153         this.server = ServerBootstrap.bootstrap()
154                 .setServerInfo(LocalServerTestBase.ORIGIN)
155                 .setSslContext(SSLTestContexts.createServerSSLContext())
156                 .create();
157         this.server.start();
158 
159         final HttpContext context = new BasicHttpContext();
160         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
161         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
162                 SSLTestContexts.createClientSSLContext(), hostVerifier);
163         final Socket socket = socketFactory.createSocket(context);
164         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
165         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
166         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
167         try {
168             final SSLSession sslsession = sslSocket.getSession();
169 
170             Assert.assertNotNull(sslsession);
171             Assert.assertTrue(hostVerifier.isFired());
172         } finally {
173             sslSocket.close();
174         }
175     }
176 
177     @Test
178     public void testClientAuthSSLAliasChoice() throws Exception {
179         // TODO unused - is there a bug in the test?
180         final PrivateKeyStrategy aliasStrategy = new PrivateKeyStrategy() {
181 
182             @Override
183             public String chooseAlias(
184                     final Map<String, PrivateKeyDetails> aliases, final Socket socket) {
185                 Assert.assertEquals(2, aliases.size());
186                 Assert.assertTrue(aliases.containsKey("hc-test-key-1"));
187                 Assert.assertTrue(aliases.containsKey("hc-test-key-2"));
188                 return "hc-test-key-2";
189             }
190 
191         };
192 
193         this.server = ServerBootstrap.bootstrap()
194                 .setServerInfo(LocalServerTestBase.ORIGIN)
195                 .setSslContext(SSLTestContexts.createServerSSLContext())
196                 .create();
197         this.server.start();
198 
199         final HttpContext context = new BasicHttpContext();
200         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
201         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
202                 SSLTestContexts.createClientSSLContext(), hostVerifier);
203         final Socket socket = socketFactory.createSocket(context);
204         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
205         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
206         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
207         try {
208             final SSLSession sslsession = sslSocket.getSession();
209 
210             Assert.assertNotNull(sslsession);
211             Assert.assertTrue(hostVerifier.isFired());
212         } finally {
213             sslSocket.close();
214         }
215     }
216 
217     @Test(expected=SSLHandshakeException.class)
218     public void testSSLTrustVerification() throws Exception {
219         this.server = ServerBootstrap.bootstrap()
220                 .setServerInfo(LocalServerTestBase.ORIGIN)
221                 .setSslContext(SSLTestContexts.createServerSSLContext())
222                 .create();
223         this.server.start();
224 
225         final HttpContext context = new BasicHttpContext();
226         // Use default SSL context
227         final SSLContext defaultsslcontext = SSLContexts.createDefault();
228 
229         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(defaultsslcontext,
230                 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
231 
232         final Socket socket = socketFactory.createSocket(context);
233         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
234         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
235         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
236         sslSocket.close();
237     }
238 
239     @Test
240     public void testSSLTrustVerificationOverride() throws Exception {
241         this.server = ServerBootstrap.bootstrap()
242                 .setServerInfo(LocalServerTestBase.ORIGIN)
243                 .setSslContext(SSLTestContexts.createServerSSLContext())
244                 .create();
245         this.server.start();
246 
247         final HttpContext context = new BasicHttpContext();
248 
249         final TrustStrategy trustStrategy = new TrustStrategy() {
250 
251             @Override
252             public boolean isTrusted(
253                     final X509Certificate[] chain, final String authType) throws CertificateException {
254                 return chain.length == 1;
255             }
256 
257         };
258         final SSLContext sslcontext = SSLContexts.custom()
259             .loadTrustMaterial(null, trustStrategy)
260             .build();
261         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
262                 sslcontext,
263                 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
264 
265         final Socket socket = socketFactory.createSocket(context);
266         final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
267         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
268         final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
269         sslSocket.close();
270     }
271 
272     @Test
273     public void testDefaultHostnameVerifier() throws Exception {
274         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
275                 SSLContexts.createDefault(),
276                 null);
277         Assert.assertNotNull(socketFactory.getHostnameVerifier());
278     }
279 
280 }