1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.mina.core.service;
22
23 import static org.junit.Assert.fail;
24
25 import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
26 import org.apache.mina.core.future.ConnectFuture;
27 import org.apache.mina.core.service.AbstractIoService;
28 import org.apache.mina.core.service.IoHandlerAdapter;
29 import org.apache.mina.core.session.IoSession;
30 import org.apache.mina.filter.codec.ProtocolCodecFilter;
31 import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
32 import org.apache.mina.filter.ssl.SslFilter;
33 import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
34 import org.apache.mina.transport.socket.nio.NioSocketConnector;
35 import org.apache.mina.util.AvailablePortFinder;
36 import org.junit.Ignore;
37 import org.junit.Test;
38
39 import javax.net.ssl.KeyManagerFactory;
40 import javax.net.ssl.SSLContext;
41 import javax.net.ssl.TrustManagerFactory;
42
43 import java.io.IOException;
44 import java.net.InetAddress;
45 import java.net.InetSocketAddress;
46 import java.net.SocketAddress;
47 import java.security.GeneralSecurityException;
48 import java.security.KeyStore;
49 import java.security.Security;
50 import java.util.concurrent.CountDownLatch;
51
52
53
54
55
56
57
58 public class SslTestHandshakeExceptionDIRMINA1077Test {
59 private int port = AvailablePortFinder.getNextAvailable();
60 private static InetAddress address;
61 private static NioSocketAcceptor acceptor;
62
63
64 private static final String KEY_MANAGER_FACTORY_ALGORITHM;
65
66 static {
67 String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
68 if (algorithm == null) {
69 algorithm = KeyManagerFactory.getDefaultAlgorithm();
70 }
71
72 KEY_MANAGER_FACTORY_ALGORITHM = algorithm;
73 }
74
75
76 private static class TestHandler extends IoHandlerAdapter {
77 public void messageReceived(IoSession session, Object message) throws Exception {}
78
79 @Override
80 public void exceptionCaught( IoSession session, Throwable cause )
81 throws Exception {}
82 }
83
84
85
86
87
88 private void startServer(int port) throws Exception {
89 acceptor = new NioSocketAcceptor();
90
91 acceptor.setReuseAddress(true);
92 DefaultIoFilterChainBuilder filters = acceptor.getFilterChain();
93
94
95 SslFilter sslFilter = new SslFilter(createSSLContext(true));
96 filters.addLast("sslFilter", sslFilter);
97 sslFilter.setNeedClientAuth(true);
98
99
100 filters.addLast("text", new ProtocolCodecFilter(new TextLineCodecFactory()));
101
102 acceptor.setHandler(new TestHandler());
103 acceptor.bind(new InetSocketAddress(port));
104 }
105
106 private static void stopServer() {
107 acceptor.dispose(true);
108 }
109
110 private void startAndStopClient( int port, CountDownLatch disposalLatch ) throws Exception {
111 NioSocketConnector nioSocketConnector = new NioSocketConnector();
112 nioSocketConnector.setHandler(new TestHandler());
113 DefaultIoFilterChainBuilder filters = nioSocketConnector.getFilterChain();
114
115
116 SslFilter sslFilter = new SslFilter(createSSLContext(false));
117 sslFilter.setUseClientMode( true );
118 filters.addLast("sslFilter", sslFilter);
119
120 address = InetAddress.getByName("localhost");
121 SocketAddress remoteAddress = new InetSocketAddress( address, port );
122 ConnectFuture connect = nioSocketConnector.connect( remoteAddress );
123 connect.awaitUninterruptibly();
124
125 nioSocketConnector.dispose( true );
126 disposalLatch.countDown();
127
128 }
129
130 private static SSLContext createSSLContext(boolean emptyKeystore) throws IOException, GeneralSecurityException {
131 char[] passphrase = "password".toCharArray();
132
133 SSLContext ctx = SSLContext.getInstance("TLSv1.2");
134 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
135 TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
136
137 KeyStore ks = KeyStore.getInstance("JKS");
138 KeyStore ts = KeyStore.getInstance("JKS");
139
140
141 if (emptyKeystore) {
142 ks.load(SslTestHandshakeExceptionDIRMINA1077Test.class.getResourceAsStream("emptykeystore.sslTest"), passphrase);
143 } else {
144 ks.load(SslTestHandshakeExceptionDIRMINA1077Test.class.getResourceAsStream("keystore.sslTest"), passphrase);
145 }
146 ts.load(SslTestHandshakeExceptionDIRMINA1077Test.class.getResourceAsStream("truststore.sslTest"), passphrase);
147
148 kmf.init(ks, passphrase);
149 tmf.init(ts);
150
151 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
152
153 return ctx;
154 }
155
156 @Test(timeout=15000)
157 @Ignore
158 public void testSSL() throws Exception {
159 long startTime = System.currentTimeMillis();
160
161 while (System.currentTimeMillis() < startTime + 10000) {
162 try {
163 port = AvailablePortFinder.getNextAvailable();
164 final CountDownLatch disposalLatch = new CountDownLatch( 1 );
165 startServer(port);
166
167 Thread t = new Thread() {
168 public void run() {
169 try {
170 startAndStopClient(port, disposalLatch);
171 } catch ( Exception e ) {}
172 }
173 };
174 t.setDaemon( true );
175 t.start();
176 disposalLatch.await();
177 t.join( 1000 );
178
179 if ( t.isAlive() ) {
180 for ( StackTraceElement stackTraceElement : t.getStackTrace() ) {
181 if ( "dispose".equals( stackTraceElement.getMethodName() )
182 && AbstractIoService.class.getCanonicalName()
183 .equals( stackTraceElement.getClassName() ) ) {
184 System.err.println( "Detected hang in AbstractIoService.dispose()!" );
185 }
186 }
187 fail( "Thread should have died by now, supposed hang in AbstractIoService.dispose()" );
188 }
189 } finally {
190 stopServer();
191 }
192 }
193 }
194 }