-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FFM-7004 - Java SDK - TLS - support custom CAs (#138)
* FFM-7004 - Java SDK - TLS - support custom CAs What Allow the SDK user to provide a custom TLS CA via the HarnessConnector API Why We currently rely on pre-installed CA bundles in the JDK for TLS connections, e.g. those hostnames signed by public CAs, it's useful to provide alternative methods of loading private TLS CAs for internal on-prem deployments Testing Manual - tested against a ff-server proxy with TLS termination enabled
- Loading branch information
1 parent
588e42e
commit e7a1ce1
Showing
9 changed files
with
220 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
examples/src/main/java/io/harness/ff/examples/TlsExample.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package io.harness.ff.examples; | ||
|
||
import io.harness.cf.client.api.BaseConfig; | ||
import io.harness.cf.client.api.CfClient; | ||
import io.harness.cf.client.api.FeatureFlagInitializeException; | ||
import io.harness.cf.client.connector.HarnessConfig; | ||
import io.harness.cf.client.connector.HarnessConnector; | ||
import io.harness.cf.client.dto.Target; | ||
import org.bouncycastle.cert.X509CertificateHolder; | ||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; | ||
import org.bouncycastle.jce.provider.BouncyCastleProvider; | ||
import org.bouncycastle.openssl.PEMParser; | ||
|
||
import java.io.FileReader; | ||
import java.io.IOException; | ||
import java.security.GeneralSecurityException; | ||
import java.security.Provider; | ||
import java.security.cert.CertificateException; | ||
import java.security.cert.X509Certificate; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ScheduledExecutorService; | ||
import java.util.concurrent.TimeUnit; | ||
import static java.lang.System.out; | ||
|
||
public class TlsExample { | ||
private static final String apiKey = getEnvOrDefault("FF_API_KEY", ""); | ||
private static final String flagName = getEnvOrDefault("FF_FLAG_NAME", "harnessappdemodarkmode"); | ||
private static final String trustedCaPemFile = getEnvOrDefault("FF_TRUSTED_CA_FILE_NAME", "/change/me/CA.pem"); | ||
|
||
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); | ||
private static final Provider bcProvider = new BouncyCastleProvider(); | ||
|
||
|
||
public static void main(String[] args) throws InterruptedException, FeatureFlagInitializeException, GeneralSecurityException, IOException { | ||
out.println("Java SDK TLS example"); | ||
|
||
List<X509Certificate> trustedServers = loadCerts(trustedCaPemFile); | ||
|
||
// Note that this code uses ffserver hostname as an example, likely you'll have your own hostname or IP. | ||
// You should ensure the endpoint is returning a cert with valid SANs configured for the host/IP. | ||
HarnessConfig config = HarnessConfig.builder() | ||
.configUrl("https://ffserver:8001/api/1.0") | ||
.eventUrl("https://ffserver:8000/api/1.0") | ||
.tlsTrustedCAs(trustedServers) | ||
.build(); | ||
|
||
HarnessConnector connector = new HarnessConnector(apiKey, config); | ||
|
||
try (CfClient cfClient = new CfClient(connector)) { | ||
|
||
cfClient.waitForInitialization(); | ||
|
||
final Target target = Target.builder() | ||
.identifier("javasdk") | ||
.name("JavaSDK") | ||
.build(); | ||
|
||
// Loop forever reporting the state of the flag | ||
scheduler.scheduleAtFixedRate( | ||
() -> { | ||
boolean result = cfClient.boolVariation(flagName, target, false); | ||
out.println("Flag '" + flagName + "' Boolean variation is " + result); | ||
}, | ||
0, | ||
10, | ||
TimeUnit.SECONDS); | ||
|
||
|
||
TimeUnit.MINUTES.sleep(15); | ||
|
||
out.println("Cleaning up..."); | ||
scheduler.shutdownNow(); | ||
} | ||
} | ||
|
||
// Get the value from the environment or return the default | ||
private static String getEnvOrDefault(String key, String defaultValue) { | ||
String value = System.getenv(key); | ||
if (value == null || value.isEmpty()) { | ||
return defaultValue; | ||
} | ||
return value; | ||
} | ||
|
||
// Here we're using BC's PKIX lib to convert the PEM to an X.509, you can use any crypto library you prefer | ||
private static List<X509Certificate> loadCerts(String filename) throws IOException, CertificateException { | ||
List<X509Certificate> list = new ArrayList<>(); | ||
try (PEMParser parser = new PEMParser(new FileReader(filename))) { | ||
Object obj; | ||
while ((obj = parser.readObject()) != null) { | ||
if (obj instanceof X509CertificateHolder) { | ||
list.add(new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate((X509CertificateHolder) obj)); | ||
} | ||
} | ||
} | ||
return list; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
log4j.rootLogger=debug | ||
log4j.logger.io.harness=debug | ||
log4j.rootLogger=info | ||
log4j.logger.io.harness=info |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.