Mutual Authentication in Scala with Akka

只谈情不闲聊 提交于 2021-02-10 15:14:12

问题


I would create a TLS Session in Scala using Akka with mutual authentication between a client and a server. I have created two CA certificate that have to trust the respective certificates incoming from the other part. Could you give me an exemple of how implement this? Thank you.


回答1:


I created a github project which demonstrates mutual authentication with different kind of clients, including Akka. Please have a look here: https://github.com/Hakky54/mutual-tls-ssl

It contains a full example of loading the ssl material into the client and server

A summary what you need to do is:

  • For the client

    • Create a key and a certificate and load it into a keystore
    • Export the certificate
    • Create a separate keystore for trusted certificates and import server certificate
    • Load the two keystores into your http client
  • For the server

    • Create a key and a certificate and load it into a keystore
    • Export the certificate
    • Create a separate keystore for trusted certificates and import client certificate
    • Load the two keystores into your server

It is not really clear to me what kind of server you are using, but if you are using spring-boot the example configuration would be:

server:
  port: 8443
  ssl:
    enabled: true
    key-store: classpath:identity.jks
    key-password: secret
    key-store-password: secret
    trust-store: classpath:truststore.jks
    trust-store-password: secret
    client-auth: need

Akka requires a pre-configured instance of SSLContext to be able to configure HTTPS. An example of creating a client with https options would be the code snippet below.

import akka.actor.ActorSystem;
import akka.http.javadsl.ConnectionContext;
import akka.http.javadsl.Http;
import akka.http.javadsl.HttpsConnectionContext;
import com.typesafe.config.ConfigFactory;

import javax.net.ssl.SSLContext;
import java.util.Optional;

class App {

    public static void main(String[] args) {
        ActorSystem actorSystem = ActorSystem.create(
                App.class.getSimpleName(),
                ConfigFactory.defaultApplication(App.class.getClassLoader())
        );

        SSLContext sslContext = ...; //Initialized SSLContext

        Http http = Http.get(actorSystem);
        HttpsConnectionContext httpsContext = ConnectionContext.https(
                sslContext,
                Optional.empty(),
                Optional.empty(),
                Optional.empty(),
                Optional.of(sslContext.getDefaultSSLParameters()));
        http.setDefaultClientHttpsContext(httpsContext);
    }
}

There are couple of libraries which provides easy to use utility/factory/builder classes to help you to create a SSLContext.

  • Apache SSLContextBuilder
  • Jetty SslContextFactory
  • SSLContext-Kickstart

There could be a bunch other libraries which provide similar functionality, but I am only aware of these three. By the way the sslcontext-kickstart is a library which is maintained by me.

Below is an overview of four ways to load the keystores and create an SSLContext. Vanilla Java and by using the three libraries.

import io.netty.handler.ssl.SslContextBuilder;
import nl.altindag.sslcontext.SSLFactory;
import org.apache.http.ssl.SSLContextBuilder;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import javax.net.ssl.*;
import java.io.File;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Objects;

class SslExample {

    public static void main(String[] args) throws Exception {

        //Traditional flow of creating sslContext
        String keyStorePath = "keystore.p12";
        String trustStorePath = "truststore.p12";

        char[] keyStorePassword = "secret".toCharArray();
        char[] trustStorePassword = "secret".toCharArray();

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        KeyStore trustStore = KeyStore.getInstance("PKCS12");

        try(InputStream keyStoreInputStream = SslExample.class.getClassLoader().getResourceAsStream(keyStorePath);
            InputStream trustStoreInputStream = SslExample.class.getClassLoader().getResourceAsStream(trustStorePath)) {

            Objects.requireNonNull(keyStoreInputStream);
            Objects.requireNonNull(trustStoreInputStream);

            keyStore.load(keyStoreInputStream, keyStorePassword);
            trustStore.load(trustStoreInputStream, trustStorePassword);
        }

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, keyStorePassword);
        KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(keyManagers, trustManagers, new SecureRandom());

        //creating sslContext with Apache SSLContextBuilder
        SSLContext sslContext1 = SSLContextBuilder.create()
                .loadKeyMaterial(new File("keystore.p12"), "secret".toCharArray(), "secret".toCharArray())
                .loadTrustMaterial(new File("truststore.p12"), "secret".toCharArray())
                .build();

        //creating sslContext with Jetty SslContextFactory
        SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
        sslContextFactory.setKeyStorePath("keystore.p12");
        sslContextFactory.setKeyStorePassword("secret");
        sslContextFactory.setTrustStorePath("truststore.p12");
        sslContextFactory.setTrustStorePassword("secret");
        sslContextFactory.start();

        SSLContext sslContext2 = sslContextFactory.getSslContext();

        //creating sslContext with sslcontext-kickstart
        SSLFactory sslFactory = SSLFactory.builder()
                .withIdentity("keystore.p12", "secret".toCharArray())
                .withTrustStore("truststore.p12", "secret".toCharArray())
                .build();

        SSLContext sslContext3 = sslFactory.getSslContext();
    }

}

It is in java, but IntelliJ Idea provides a handy translate function to scala when pasting the code snippet.



来源:https://stackoverflow.com/questions/61868096/mutual-authentication-in-scala-with-akka

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!