View Javadoc

1   // Copyright (C) 2007 - 2011 Philip Aston
2   // All rights reserved.
3   //
4   // This file is part of The Grinder software distribution. Refer to
5   // the file LICENSE which is part of The Grinder distribution for
6   // licensing details. The Grinder distribution is available on the
7   // Internet at http://grinder.sourceforge.net/
8   //
9   // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13  // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17  // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20  // OF THE POSSIBILITY OF SUCH DAMAGE.
21  
22  package net.grinder.engine.process;
23  
24  import java.io.File;
25  import java.io.FileOutputStream;
26  import java.io.InputStream;
27  import java.security.UnrecoverableKeyException;
28  
29  import javax.net.ssl.KeyManager;
30  import javax.net.ssl.SSLContext;
31  
32  import net.grinder.common.SSLContextFactory;
33  import net.grinder.common.ThreadLifeCycleListener;
34  import net.grinder.common.SSLContextFactory.SSLContextFactoryException;
35  import net.grinder.script.InvalidContextException;
36  import net.grinder.script.SSLControl;
37  import net.grinder.testutility.AbstractFileTestCase;
38  import net.grinder.testutility.CallData;
39  import net.grinder.testutility.RandomStubFactory;
40  import net.grinder.util.StreamCopier;
41  
42  
43  /**
44   * Unit tests for {@link SSLControlImplementation}.
45   *
46   * @author Philip Aston
47   */
48  public class TestSSLControlImplementation extends AbstractFileTestCase {
49  
50    private final RandomStubFactory<ThreadContext> m_threadContextStubFactory =
51      RandomStubFactory.create(ThreadContext.class);
52    private final ThreadContext m_threadContext =
53      m_threadContextStubFactory.getStub();
54  
55    private final StubThreadContextLocator m_threadContextLocator=
56        new StubThreadContextLocator();
57  
58    {
59      m_threadContextLocator.set(m_threadContext);
60      m_threadContextStubFactory.setIgnoreMethod("getThreadSSLContextFactory");
61    }
62  
63    private final RandomStubFactory<KeyManager> m_keyManagerStubFactory =
64      RandomStubFactory.create(KeyManager.class);
65    private final KeyManager m_keyManager = m_keyManagerStubFactory.getStub();
66  
67    public void testShareContextBetweenRuns() throws Exception {
68      final SSLControl sslControl =
69        new SSLControlImplementation(m_threadContextLocator);
70  
71      assertFalse(sslControl.getShareContextBetweenRuns());
72      sslControl.setShareContextBetweenRuns(true);
73      assertTrue(sslControl.getShareContextBetweenRuns());
74      sslControl.setShareContextBetweenRuns(false);
75      assertFalse(sslControl.getShareContextBetweenRuns());
76  
77      sslControl.setKeyManagers(new KeyManager[] { m_keyManager });
78  
79      final CallData call =
80          m_threadContextStubFactory.assertSuccess("setThreadSSLContextFactory",
81                                                   SSLContextFactory.class);
82      final SSLContextFactory contextFactory =
83        (SSLContextFactory)call.getParameters()[0];
84  
85      m_threadContextStubFactory.assertSuccess("registerThreadLifeCycleListener",
86                                               contextFactory);
87  
88      m_threadContextStubFactory.assertNoMoreCalls();
89  
90      final ThreadLifeCycleListener lifecycleListener =
91        (ThreadLifeCycleListener)contextFactory;
92  
93      lifecycleListener.beginThread();
94      lifecycleListener.beginRun();
95  
96      final SSLContext context1 = contextFactory.getSSLContext();
97      assertSame(context1, contextFactory.getSSLContext());
98  
99      lifecycleListener.endRun();
100     lifecycleListener.beginRun();
101 
102     final SSLContext context2 = contextFactory.getSSLContext();
103     assertNotSame(context1, contextFactory.getSSLContext());
104     assertSame(context2, contextFactory.getSSLContext());
105 
106     sslControl.setShareContextBetweenRuns(true);
107 
108     lifecycleListener.endRun();
109     lifecycleListener.beginRun();
110 
111     assertSame(context2, contextFactory.getSSLContext());
112 
113     lifecycleListener.endRun();
114     lifecycleListener.endThread();
115     lifecycleListener.beginShutdown();
116 
117     m_threadContextStubFactory.assertNoMoreCalls();
118   }
119 
120   public void testSetKeyManagersDoesNotLeak() throws Exception {
121     final SSLControl sslControl =
122       new SSLControlImplementation(m_threadContextLocator);
123 
124     sslControl.setKeyManagers(new KeyManager[] { m_keyManager });
125 
126     final SSLContextFactory threadSSLContextFactory =
127       (SSLContextFactory)
128       m_threadContextStubFactory.assertSuccess("setThreadSSLContextFactory",
129                                                SSLContextFactory.class)
130                                                .getParameters()[0];
131 
132     m_threadContextStubFactory.assertSuccess("registerThreadLifeCycleListener",
133                                              SSLContextFactory.class);
134 
135     m_threadContextStubFactory.assertNoMoreCalls();
136 
137     m_threadContextStubFactory.setResult("getThreadSSLContextFactory",
138                                          threadSSLContextFactory);
139 
140     sslControl.setKeyManagers(new KeyManager[] { m_keyManager });
141 
142     m_threadContextStubFactory.assertSuccess("removeThreadLifeCycleListener",
143                                              threadSSLContextFactory);
144 
145     m_threadContextStubFactory.assertSuccess("setThreadSSLContextFactory",
146                                              SSLContextFactory.class);
147 
148     m_threadContextStubFactory.assertSuccess("registerThreadLifeCycleListener",
149                                              SSLContextFactory.class);
150 
151     m_threadContextStubFactory.assertNoMoreCalls();
152   }
153 
154   public void testGetSSLContext() throws Exception {
155     final SSLControl sslControl =
156       new SSLControlImplementation(m_threadContextLocator);
157 
158     // Call 1.
159     m_threadContextStubFactory.setResult("getThreadSSLContextFactory", null);
160 
161     final SSLContext context = sslControl.getSSLContext();
162     assertNotNull(context);
163 
164     final CallData call =
165       m_threadContextStubFactory.assertSuccess("setThreadSSLContextFactory",
166                                                SSLContextFactory.class);
167     final SSLContextFactory contextFactory =
168       (SSLContextFactory)call.getParameters()[0];
169 
170     assertSame(context, contextFactory.getSSLContext());
171 
172     m_threadContextStubFactory.assertSuccess("registerThreadLifeCycleListener",
173                                              contextFactory);
174     m_threadContextStubFactory.assertNoMoreCalls();
175 
176     // Call 2.
177     m_threadContextStubFactory.setResult("getThreadSSLContextFactory",
178                                          contextFactory);
179 
180     final SSLContext context2 = sslControl.getSSLContext();
181     assertNotNull(context2);
182 
183     assertSame(context, context2);
184   }
185 
186   public void testSetKeyStoreMethods() throws Exception {
187     final SSLControl sslControl =
188       new SSLControlImplementation(m_threadContextLocator);
189 
190     final InputStream keystoreStream =
191       getClass().getResourceAsStream("default.keystore");
192     sslControl.setKeyStore(
193       keystoreStream,
194         "passphrase",
195         "jks");
196 
197     keystoreStream.close();
198 
199     final SSLContextFactory threadSSLContextFactory =
200       (SSLContextFactory)
201       m_threadContextStubFactory.assertSuccess("setThreadSSLContextFactory",
202                                                SSLContextFactory.class)
203                                                .getParameters()[0];
204 
205     m_threadContextStubFactory.assertSuccess("registerThreadLifeCycleListener",
206                                              SSLContextFactory.class);
207 
208     m_threadContextStubFactory.assertNoMoreCalls();
209 
210     m_threadContextStubFactory.setResult("getThreadSSLContextFactory",
211                                          threadSSLContextFactory);
212 
213     final File myKeyStore = new File(getDirectory(), "my.jks");
214 
215     new StreamCopier(4096, true).
216     copy(
217       getClass().getResourceAsStream("default.keystore"),
218       new FileOutputStream(myKeyStore));
219 
220     try {
221       // Will fail since JKS doesn't support null passwords.
222       sslControl.setKeyStoreFile(myKeyStore.getAbsolutePath(), null, "jks");
223       fail("Expected IllegalArgumentException or UnrecoverableKeyException");
224     }
225     catch (Exception e) {
226       assertTrue("Unexpected exception type: " + e.getClass(),
227                  e instanceof UnrecoverableKeyException ||
228                  e instanceof IllegalArgumentException);
229     }
230 
231     sslControl.setKeyStoreFile(
232       myKeyStore.getAbsolutePath(), "passphrase", "jks");
233 
234     m_threadContextStubFactory.assertSuccess("removeThreadLifeCycleListener",
235                                              threadSSLContextFactory);
236 
237     m_threadContextStubFactory.assertSuccess("setThreadSSLContextFactory",
238                                              SSLContextFactory.class);
239 
240     m_threadContextStubFactory.assertSuccess("registerThreadLifeCycleListener",
241                                              SSLContextFactory.class);
242 
243     m_threadContextStubFactory.assertNoMoreCalls();
244   }
245 
246   public void testWithBadContext() throws Exception {
247     final SSLControl sslControl =
248       new SSLControlImplementation(m_threadContextLocator);
249 
250     m_threadContextLocator.set(null);
251 
252     try {
253       sslControl.setKeyManagers(new KeyManager[0]);
254       fail("Expected InvalidContextException");
255     }
256     catch (InvalidContextException e) {
257     }
258 
259     try {
260       sslControl.setKeyStore(null, "");
261       fail("Expected InvalidContextException");
262     }
263     catch (InvalidContextException e) {
264     }
265 
266     try {
267       sslControl.setKeyStoreFile("", "");
268       fail("Expected InvalidContextException");
269     }
270     catch (InvalidContextException e) {
271     }
272 
273     try {
274       sslControl.getSSLContext();
275       fail("Expected SSLContextFactoryException");
276     }
277     catch (SSLContextFactoryException e) {
278     }
279 
280     m_threadContextStubFactory.assertNoMoreCalls();
281   }
282 }