Moebius Moebius - 1 month ago 18
Scala Question

Scala https client with SSL certificate

I want to connect to a server using https protocol. I have the self-signed certificate of this website (.crt file). Now I want to connect to this website using this certificate. I am currently using the client

org.apache.http.impl.nio.client
, but I am ready to use another client if it proves to be useful.

How to connect to a server over https given I have the ssl certificate of this server ?

Answer

In order to allow only a specific certificate in your application, you have to follow the following procedure:

1- Download certificate

To do this, I opened firefox, paste the address of the website from which I want to get the certificate. Add exception to download this certificate. You can then access it by clicking on the green lock on the right of the address bar. The screen-shot will help you find how to download it.

enter image description here

Note that you should download the chain certificate, not the single certificate of the website. Here this is done in the file explorer of ubuntu, when choosing the type of file you want to export.

2- Create a java key store

Execute this command with the file you just downloaded :

keytool -import -file file_you_just_downloaded.crt -alias description_of_certificate -keystore 

You now have a java key store with all the required certificate to connect to your website using https.

3- Create a client with those certificate

Those example are made with the apache nio web client.

import java.io.FileInputStream
import java.security.cert.X509Certificate
import java.security.{KeyStore, SecureRandom}
import javax.net.ssl._

import org.apache.http.conn.ssl.NoopHostnameVerifier
import org.apache.http.impl.nio.client.{CloseableHttpAsyncClient, HttpAsyncClients}
import org.apache.commons.io.IOUtils
import org.apache.http.ssl.SSLContexts

def httpClientFactory(
  keyStoreFileName: String
): CloseableHttpAsyncClient = {
  val httpClientBuilder = HttpAsyncClients.custom()

  // activating or not the certificate checking
  if (checkCertificate) {
    // import keystore
    val keyStorePassword = jksPassword // the password you used whit the command keytool
    val ks = KeyStore.getInstance(KeyStore.getDefaultType)
    val keyStorePath = getClass.getClassLoader.getResource(keyStoreFileName)
    val inputStream = new FileInputStream(keyStorePath.getPath)
    ks.load(inputStream, keyStorePassword.toArray)
    IOUtils.closeQuietly(inputStream)
    // create trust manager from keystore
    val tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
    tmf.init(ks)
    val trustManager = tmf.getTrustManagers
    // associate trust manager with the httpClient
    val sslContext = SSLContext.getInstance("TLS")
    sslContext.init(Array(), trustManager, null)
    httpClientBuilder.setSSLContext(sslContext)
  } else {
    logger.warn("Warning ! Https connections will be done without checking certificate. Do not use in production.")
    val sslContext = SSLContexts.createDefault()
    sslContext.init(null, Array(new X509TrustManager {
      override def getAcceptedIssuers: Array[X509Certificate] = Array.empty[X509Certificate]
      override def checkClientTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {}
      override def checkServerTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {}
    }), new SecureRandom())
    httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
      .setSSLContext(sslContext)
  }

  // ending httpClient creation
  httpClientBuilder.build()
}

4- Use the HttpClient

Nothing change here.