Продолжаю небольшую серию постов про использование SSL. Сегодня я хочу завершить эксперимент с двусторонней аутентификацией, который не удалось реализовать на встроенном в JDK сервере. Я попробую настроить Tomcat и протестировать с ним одностороннюю и двустороннюю аутентификацию.

Поиски а интернете дали следующие результаты:

  • Страничка на StackOverflow с примером конфигурации Tomcat для SSL http://stackoverflow.com/questions/5162279/configure-tomcat-to-use-a-trust-store-other-than-cacerts
  • Tomcat SSL HowTo http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html#Configuration
  • Документация на теги конфигурационного файла Tomcat http://tomcat.apache.org/tomcat-6.0-doc/config/http.html#SSL_Support

Вкратце, получается следующее. Tomcat поддерживает 2 типа SSL соединений: на основе OpenSSL и на основе стандартной Java реализации. Чтобы сконфигурировать HTTPS нужно минимально раскомментировать в файле conf/server.xml соответствующий коннектор, добавив в него ссылку на keystore файл и пароль к keystore файлу. В моем случае, я хочу протестировать двустороннюю аутентификацию. Для этого нужно еще добавить trustStore-файл, для хранения клиентского trusted сертификата и указать атрибут clientAuth=»true».

<Connector
    protocol="org.apache.coyote.http11.Http11Protocol"
   port="8443" maxThreads="200"
   scheme="https" secure="true" SSLEnabled="true"
   keystoreFile="C:\java\apache-tomcat-6.0.29\conf\tomcat.jks" keystorePass="tomcat"
truststoreFile="C:\java\apache-tomcat-6.0.29\conf\tomcattrust.jks" truststorePass="tomcat"
clientAuth="true" sslProtocol="TLS" />

Генерирую tomcat.jks с помощью keytool:

keytool -genkey -dname "cn=tomcat,ou=dev64,o=dev64-wordpress,L=unspec, st=unspec, c=RU"
-alias tomcat -keypass tomcat -keystore tomcat.jks -storepass tomcat

Получаю файл с ключом и сертификатом сервера. Экспортирую сертификат сервера, чтобы подложить его в truststore моего тестового клиента:

keytool -export -keystore tomcat.jks -alias tomcat -storepass tomcat -file tomcat.cer

Получаю файл с сертификатом tomcat.cer. Импортирую сертификат сервера в truststore моего тестового клиента:

keytool -import -keystore clienttrust.jks -alias tomcat -file tomcat.cer -storepass storepass

Последним шагом, беру сертификат клиента и на его основе создаю tomcattrust.jsk — truststore для Tomcat:

keytool -import -keystore tomcattrust.jks -file client.cer -storepass tomcat

Беру свой тестовый код из предыдущего поста и тестирую.

@Test
public void testTwoWayAuthentication()
    throws CertificateException, InterruptedException, UnrecoverableKeyException, NoSuchAlgorithmException,
           IOException, KeyManagementException, KeyStoreException {

    URL url = new URL("https://localhost:8443/");

    HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
    con.setRequestMethod( "GET" );

    SSLContext sslContext = SSLContext.getInstance("TLS");

    char[]  passphrase = "storepass".toCharArray();
    char[]  keypass = "serverpass".toCharArray();

    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(SimpleServerTest.class.getResourceAsStream("client.jks"), passphrase);

    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, keypass);

    KeyStore ts = KeyStore.getInstance("JKS");
    ts.load(this.getClass().getResourceAsStream("clienttrust.jks"), passphrase);
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    tmf.init(ts);

    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String s, SSLSession sslSession) {
            return s.equals(sslSession.getPeerHost());
        }
    };
    con.setHostnameVerifier(hostnameVerifier);


    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    con.setSSLSocketFactory(sslContext.getSocketFactory());


    int responseCode = con.getResponseCode();
    InputStream inputStream;
    if (responseCode == HttpURLConnection.HTTP_OK) {
        inputStream = con.getInputStream();
    } else {
        inputStream = con.getErrorStream();
    }

    // Process the response
    BufferedReader reader;
    String line = null;
    reader = new BufferedReader( new InputStreamReader( inputStream ) );
    while( ( line = reader.readLine() ) != null )
    {
        System.out.println( line );
    }

    inputStream.close();
}

Получаю адекватный ответ от сервера. Тест проходит. Если убрать двустороннюю аутентификацию в конфиге Tomcat, т.е. clientAuth=»false», тогда коннект проходит из браузера.

Т.о. все тесты с односторонней и двусторонней аутентификацией прошли и на этом я, пока, тему HTTPS завершаю.

Взято:
https://dev64.wordpress.com/2013/06/19/configure-https-at-apache-tomcat-and-https-test-client/