Skip to content

Instantly share code, notes, and snippets.

@kannangce
Last active April 3, 2024 09:11
Show Gist options
  • Save kannangce/4fed4d42fb8c980c82623e3eed9413ef to your computer and use it in GitHub Desktop.
Save kannangce/4fed4d42fb8c980c82623e3eed9413ef to your computer and use it in GitHub Desktop.
Feign client for 1 or 2-way TLS with self signed certificates when javax.net.ssl.keyStore / javax.net.ssl.trustStore cannot be overridden.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.AccessController;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import feign.Client;
import feign.Feign;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
import feign.codec.ErrorDecoder;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
/**
* Class containing the utilities required to create SSL enabled fiegn clients for
* self-signed certificate servers
*
* @author kannan.r
*/
public class FeignSSLUtils
{
/**
* Returns the custom feign client that can be used for the TLS enabled
* communication using self signed certificates.
* <br/>
* Use cases:
* <ol>
* <li>The client needs to communicate with a system with self-signed
* CAs, with 1 or 2-way TLS</li>
* <li>And, we are not allowed to override the
* <i>javax.net.ssl.trustStore</i> and <i>javax.net.ssl.keyStore</i>
* properties.</li>
* </ol>
*
* @param theTrustStoreFile
* The truststore file using which the outgoing connections will
* be trusted.
* @param theKeyStoreFile
* The keystore file, for the peer to trust the outgoing. Can be
* null if the connection doesn't requires 2-way TLS.
* @param theKeyStorePassword
* The keystore password
* @return {@link Client} instance based on the given params
* @throws Exception
* When there is problem in initializing the client instance.
*/
public static Client getFeignClient(File theTrustStoreFile, File theKeyStoreFile,
String theKeyStorePassword) throws Exception
{
try
{
return new Client.Default(getClientSSLSocketFactory(theTrustStoreFile, theKeyStoreFile,
theKeyStorePassword), null);
} catch (Exception e)
{
throw new Exception("Error in initializing feign client", e);
}
}
/**
* Gets the {@link SSLSocketFactory} instance for the client communication
* using the given truststore file and password.
*
* @param theTrustStoreFile
* The truststore file using which the outgoing connections will
* be trusted.
* @param theKeyStoreFile
* The keystore file, for the peer to trust the outgoing. Can be
* null if the connection doesn't requires 2-way TLS.
* @param theKeyStorePassword
* The keystore passowrd
* @return TLS supported {@link SSLSocketFactory} instance with the given
* key and trust stores.
* @throws NoSuchAlgorithmException
* When the underlying security providers doesn't support TLS.
* @throws KeyStoreException
* If no Provider supports a KeyStoreSpi implementation for the
* specified type.
* @throws PrivilegedActionException
* When there is access issue with the truststore file
* @throws CertificateException
* If the certificates from the truststore is unable to be read
* @throws IOException
* When there is error in reading the truststore
* @throws KeyManagementException
* If the SSL context initialization fails
* @throws UnrecoverableKeyException
* When there is problem in using the given keystore file
*/
private static SSLSocketFactory getClientSSLSocketFactory(File theTrustStoreFile,
File theKeyStoreFile, String theKeyStorePassword)
throws NoSuchAlgorithmException, KeyStoreException, PrivilegedActionException,
CertificateException, IOException, KeyManagementException, UnrecoverableKeyException
{
// This supports TLSv1.2
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyStore tStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream tStorefile = getFileInputStream(theTrustStoreFile);
tStore.load(tStorefile, null);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(tStore);
KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType());
KeyManager[] keyManagers = null;
if (theKeyStoreFile != null)
{
FileInputStream kStorefile = getFileInputStream(theKeyStoreFile);
kStore.load(kStorefile, theKeyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(kStore, theKeyStorePassword.toCharArray());
keyManagers = kmf.getKeyManagers();
}
if (keyManagers == null)
{
// 2-way TLS not required. Let JVM uses its default
keyManagers = new KeyManager[] {};
}
sslContext.init(keyManagers, tmf.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
/**
* Reads the file into {@link FileInputStream} instance.
*
* @param file
* The file to be read.
* @return {@link FileInputStream} that represents the file content/
* @throws Exception
* When there is any error in reading the file.
*/
private static FileInputStream getFileInputStream(final File file)
throws PrivilegedActionException
{
return AccessController.doPrivileged(new PrivilegedExceptionAction<FileInputStream>()
{
@Override
public FileInputStream run() throws Exception
{
try
{
if (file.exists())
{
return new FileInputStream(file);
} else
{
return null;
}
} catch (FileNotFoundException e)
{
// couldn't find it, oh well.
return null;
}
}
});
}
}
@ajitdas91
Copy link

I have not passed these values as parameter but used as injected value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment