Adding SSLContext to RESTclient mTLS (Groovy/Java)

588 Views Asked by At

I'm struggeling a bit with my code to make it possible to use mTLS in the RESTClient. So I'm looking for a way to establish an mTLS connection. Here is my code:

...
def mymTLSservice = "https://my-token-service.example.com"

// Load custom my TrustStore and KeyStore
def pathToKeyStore = "/path/to/keystore.jceks"
def pathToTrustStore = "/path/to/truststore"
def keyStorePW = "myKeyStorePW"
def trustStorePW = "myTrustStorePW"

final char[] pwdKeyStore = keyStorePW.toCharArray()
final char[] pwdTrustStore = trustStorePW.toCharArray()

String keyAlias = "my-mTls-cert-alias" // If you have more than one key
String storeType = "JCEKS"

FileInputStream keyStoreInputStream = new FileInputStream(pathToKeyStore)
FileInputStream trustStoreInputStream = new FileInputStream(pathToTrustStore)

KeyStore ks = KeyStore.getInstance(storeType)
ks.load(keyStoreInputStream, pwdKeyStore)
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType())
trustStore.load(trustStoreInputStream, pwdTrustStore)

Key mTlsPrivateKey = ks.getKey(keyAlias, pwdKeyStore)
Certificate[] mTlsChain = ks.getCertificateChain(keyAlias)
KeyStore mtlsKeyStore = KeyStore.getInstance("jks")
mtlsKeyStore.load(null, null)
mtlsKeyStore.setKeyEntry(keyAlias, mTlsPrivateKey, pwdKeyStore, mTlsChain)

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
keyManagerFactory.init(mtlsKeyStore, pwdKeyStore)
TrustManagerFactory trustManagerFactory =
    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);

// Create SSLContext
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(
    keyManagerFactory.getKeyManagers(),
    trustManagerFactory,
    new java.security.SecureRandom());

SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(sc)

def http = new RESTClient(mymTLSservice)
http.auth.basic 'user', 'password'
// HOW CAN I ADD THE SSLConnectionSocketFactory here
http.handler.failure = { resp -> println "Failure: ${resp.statusLine}" }


// Trying request"

def access_token = ''

try{
    http.get(
        path : "/v2/token"
    ) 
    { resp, json ->
         access_token = json
         println "access_token"
                }
    println resp
} catch(HttpResponseException e) {
        r = e.response
        println("Success: $r.success")
        println("Status:  $r.status")
        println("Reason:  $r.statusLine.reasonPhrase")
        println("Could not retrieve an access token from token provider!")
}

How can I correctly add the SSLConnectionSocketFactory to http? Thank you!

I'm trying to communicate over mTLS with a service.

1

There are 1 best solutions below

0
On

After long investigation I finally figured it out. Hope it helps someone in the same situation.

In the above snippet we create an SSLContext "sc" which we need to pass to the new defined SSLSocketFactory "sf". Then we create a new "Scheme" definition which will use the newly created SSLSocketFactory "sf" for every "https" request. So the above line were we create a SSLConnectionSocketFactory has to replaced with SSLSocketFactory.

SSLSocketFactory sf = new SSLSocketFactory(sc); 
Scheme httpsScheme = new Scheme("https", 443, sf);

And at the end we override the ConnectionManager of the RESTClient with the scheme definition "httpsScheme".

def http = new RESTClient(mymTLSservice)
http.auth.basic 'user', 'password'
http.client.connectionManager.schemeRegistry.register(httpsScheme) // this will add the custom keyStore to every https call

This will cause that during SSL negotiation a client certificate will be presented.