View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */package org.apache.mina.filter.ssl;
    20
    21  import java.io.BufferedReader;
    22  import java.io.IOException;
    23  import java.io.InputStreamReader;
    24  import java.net.InetAddress;
    25  import java.net.InetSocketAddress;
    26  import java.net.Socket;
    27  import java.security.GeneralSecurityException;
    28  import java.security.KeyStore;
    29  import java.security.Security;
    30
    31  import javax.net.ssl.KeyManagerFactory;
    32  import javax.net.ssl.SSLContext;
    33  import javax.net.ssl.SSLSocketFactory;
    34  import javax.net.ssl.TrustManagerFactory;
    35
    36  import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
    37  import org.apache.mina.core.service.IoHandlerAdapter;
    38  import org.apache.mina.core.session.IoSession;
    39  import org.apache.mina.filter.codec.ProtocolCodecFilter;
    40  import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
    41  import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
    42  import org.apache.mina.util.AvailablePortFinder;
    43  import org.junit.Test;
    44
    45  /**
    46   * Test a SSL session where the connection is established and closed twice. It should be
    47   * processed correctly (Test for DIRMINA-650)
    48   *
    49   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    50   */
    51  public class SslTest {
    52      /** A static port used for his test, chosen to avoid collisions */
    53      private static final int port = AvailablePortFinder.getNextAvailable(5555);
    54
    55      private static Exception clientError = null;
    56
    57      private static InetAddress address;
    58
    59      private static SSLSocketFactory factory;
    60
    61      /** A JVM independant KEY_MANAGER_FACTORY algorithm */
    62      private static final String KEY_MANAGER_FACTORY_ALGORITHM;
    63
    64      static {
    65          String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
    66          if (algorithm == null) {
    67              algorithm = KeyManagerFactory.getDefaultAlgorithm();
    68          }
    69
    70          KEY_MANAGER_FACTORY_ALGORITHM = algorithm;
    71      }
    72
    73      private static class TestHandler extends IoHandlerAdapter {
    74          public void messageReceived(IoSession session, Object message) throws Exception {
    75              String line = (String) message;
    76
    77              if (line.startsWith("hello")) {
    78                  System.out.println("Server got: 'hello', waiting for 'send'");
    79                  Thread.sleep(1500);
    80              } else if (line.startsWith("send")) {
    81                  System.out.println("Server got: 'send', sending 'data'");
    82                  session.write("data");
    83              }
    84          }
    85      }
    86
    87      /**
    88       * Starts a Server with the SSL Filter and a simple text line
    89       * protocol codec filter
    90       */
    91      private static void startServer() throws Exception {
    92          NioSocketAcceptor acceptor = new NioSocketAcceptor();
    93
    94          acceptor.setReuseAddress(true);
    95          DefaultIoFilterChainBuilder filters = acceptor.getFilterChain();
    96
    97          // Inject the SSL filter
    98          SslFilter sslFilter = new SslFilter(createSSLContext());
    99          filters.addLast("sslFilter", sslFilter);
    100
    101         // Inject the TestLine codec filter
    102         filters.addLast("text", new ProtocolCodecFilter(new TextLineCodecFactory()));
    103
    104         acceptor.setHandler(new TestHandler());
    105         acceptor.bind(new InetSocketAddress(port));
    106     }
    107
    108     /**
    109      * Starts a client which will connect twice using SSL
    110      */
    111     private static void startClient() throws Exception {
    112         address = InetAddress.getByName("localhost");
    113
    114         SSLContext context = createSSLContext();
    115         factory = context.getSocketFactory();
    116
    117         connectAndSend();
    118
    119         // This one will throw a SocketTimeoutException if DIRMINA-650 is not fixed
    120         connectAndSend();
    121     }
    122
    123     private static void connectAndSend() throws Exception {
    124         Socket parent = new Socket(address, port);
    125         Socket socket = factory.createSocket(parent, address.getCanonicalHostName(), port, false);
    126
    127         System.out.println("Client sending: hello");
    128         socket.getOutputStream().write("hello                      \n".getBytes());
    129         socket.getOutputStream().flush();
    130         socket.setSoTimeout(10000);
    131
    132         System.out.println("Client sending: send");
    133         socket.getOutputStream().write("send\n".getBytes());
    134         socket.getOutputStream().flush();
    135
    136         BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    137         String line = in.readLine();
    138         System.out.println("Client got: " + line);
    139         socket.close();
    140
    141     }
    142
    143     private static SSLContext createSSLContext() throws IOException, GeneralSecurityException {
    144         char[] passphrase = "password".toCharArray();
    145
    146         SSLContext ctx = SSLContext.getInstance("TLS");
    147         KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
    148         TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
    149
    150         KeyStore ks = KeyStore.getInstance("JKS");
    151         KeyStore ts = KeyStore.getInstance("JKS");
    152
    153         ks.load(SslTest.class.getResourceAsStream("keystore.sslTest"), passphrase);
    154         ts.load(SslTest.class.getResourceAsStream("truststore.sslTest"), passphrase);
    155
    156         kmf.init(ks, passphrase);
    157         tmf.init(ts);
    158         ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    159
    160         return ctx;
    161     }
    162
    163     @Test
    164     public void testSSL() throws Exception {
    165         startServer();
    166
    167         Thread t = new Thread() {
    168             public void run() {
    169                 try {
    170                     startClient();
    171                 } catch (Exception e) {
    172                     clientError = e;
    173                 }
    174             }
    175         };
    176         t.start();
    177         t.join();
    178         if (clientError != null)
    179             throw clientError;
    180     }
    181 }