001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.filter.ssl; 021 022import static org.junit.Assert.*; 023import java.io.IOException; 024import java.net.InetSocketAddress; 025import java.security.GeneralSecurityException; 026import java.security.KeyStore; 027import java.security.Security; 028import java.util.concurrent.CountDownLatch; 029import java.util.concurrent.TimeUnit; 030 031import javax.net.ssl.KeyManagerFactory; 032import javax.net.ssl.SSLContext; 033import javax.net.ssl.TrustManagerFactory; 034 035import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; 036import org.apache.mina.core.service.IoHandlerAdapter; 037import org.apache.mina.core.session.IoSession; 038import org.apache.mina.filter.codec.ProtocolCodecFilter; 039import org.apache.mina.filter.codec.textline.TextLineCodecFactory; 040import org.apache.mina.transport.socket.nio.NioSocketAcceptor; 041import org.apache.mina.transport.socket.nio.NioSocketConnector; 042import org.apache.mina.util.AvailablePortFinder; 043import org.junit.Ignore; 044import org.junit.Test; 045 046/** 047 * Test an SSL session where the connection cannot be established with the server due to 048 * incompatible protocols (Test for DIRMINA-937) 049 * 050 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 051 */ 052public class SslDIRMINA937Test { 053 /** A static port used for his test, chosen to avoid collisions */ 054 private static final int port = AvailablePortFinder.getNextAvailable(5555); 055 056 /** A JVM independant KEY_MANAGER_FACTORY algorithm */ 057 private static final String KEY_MANAGER_FACTORY_ALGORITHM; 058 059 static { 060 String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); 061 if (algorithm == null) { 062 algorithm = KeyManagerFactory.getDefaultAlgorithm(); 063 } 064 065 KEY_MANAGER_FACTORY_ALGORITHM = algorithm; 066 } 067 068 private static class TestHandler extends IoHandlerAdapter { 069 public void messageReceived(IoSession session, Object message) throws Exception { 070 String line = (String) message; 071 072 if (line.startsWith("hello")) { 073 //System.out.println("Server got: 'hello', waiting for 'send'"); 074 Thread.sleep(1500); 075 } else if (line.startsWith("send")) { 076 //System.out.println("Server got: 'send', sending 'data'"); 077 session.write("data"); 078 } 079 } 080 } 081 082 /** 083 * Starts a Server with the SSL Filter and a simple text line 084 * protocol codec filter 085 */ 086 private static void startServer() throws Exception { 087 NioSocketAcceptor acceptor = new NioSocketAcceptor(); 088 089 acceptor.setReuseAddress(true); 090 DefaultIoFilterChainBuilder filters = acceptor.getFilterChain(); 091 092 // Inject the SSL filter 093 SSLContext context = createSSLContext("TLSv1"); 094 SslFilter sslFilter = new SslFilter(context); 095 sslFilter.setEnabledProtocols(new String[] { "TLSv1" }); 096 //sslFilter.setEnabledCipherSuites(getServerCipherSuites(context.getDefaultSSLParameters().getCipherSuites())); 097 filters.addLast("sslFilter", sslFilter); 098 099 // Inject the TestLine codec filter 100 filters.addLast("text", new ProtocolCodecFilter(new TextLineCodecFactory())); 101 102 acceptor.setHandler(new TestHandler()); 103 acceptor.bind(new InetSocketAddress(port)); 104 } 105 106 /** 107 * Starts a client which will connect twice using SSL 108 */ 109 private static void startClient(final CountDownLatch counter) throws Exception { 110 NioSocketConnector connector = new NioSocketConnector(); 111 112 DefaultIoFilterChainBuilder filters = connector.getFilterChain(); 113 SslFilter sslFilter = new SslFilter(createSSLContext("TLSv1.1")); 114 sslFilter.setEnabledProtocols(new String[] { "TLSv1.1" }); 115 sslFilter.setUseClientMode(true); 116 //sslFilter.setEnabledCipherSuites(getClientCipherSuites()); 117 filters.addLast("sslFilter", sslFilter); 118 connector.setHandler(new IoHandlerAdapter() { 119 @Override 120 public void sessionCreated(IoSession session) throws Exception { 121 session.setAttribute(SslFilter.USE_NOTIFICATION, Boolean.TRUE); 122 } 123 124 @Override 125 public void messageReceived(IoSession session, Object message) throws Exception { 126 if (message == SslFilter.SESSION_SECURED) { 127 counter.countDown(); 128 } 129 } 130 131 132 }); 133 connector.connect(new InetSocketAddress("localhost", port)); 134 } 135 136 private static SSLContext createSSLContext(String protocol) throws IOException, GeneralSecurityException { 137 char[] passphrase = "password".toCharArray(); 138 139 SSLContext ctx = SSLContext.getInstance(protocol); 140 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM); 141 TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM); 142 143 KeyStore ks = KeyStore.getInstance("JKS"); 144 KeyStore ts = KeyStore.getInstance("JKS"); 145 146 ks.load(SslDIRMINA937Test.class.getResourceAsStream("keystore.sslTest"), passphrase); 147 ts.load(SslDIRMINA937Test.class.getResourceAsStream("truststore.sslTest"), passphrase); 148 149 kmf.init(ks, passphrase); 150 tmf.init(ts); 151 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 152 153 return ctx; 154 } 155 156 /** 157 * Test is ignore as it will cause the build to fail 158 */ 159 @Test 160 @Ignore("This test is not yet fully functionnal, it servers as the basis for validating DIRMINA-937") 161 public void testDIRMINA937() throws Exception { 162 startServer(); 163 164 final CountDownLatch counter = new CountDownLatch(1); 165 startClient(counter); 166 assertTrue(counter.await(10, TimeUnit.SECONDS)); 167 } 168}