launchdarkly/java-server-sdk

LDClient fails to initialize when used with Azul Zulu 8.46 (OpenJDK 8.0.252) and newer

BradRoot opened this issue · 3 comments

LDClient fails to initialize when used with Azul Zulu 8.46 (OpenJDK 8.0.252)+ and the runtime is configured with to run in FIPS mode with BouncyCastle cryptography providers.

Describe the bug
LDClient fails to initialize when used with Azul Zulu 8.46 (OpenJDK 8.0.252) and newer. This is due to a back-ported JDK 9 fix which causes OkHttp to detect the 8 runtime as 9. This is fixed in OkHttp 3.14.8+ and 4.6.0+. See square/okhttp#5970 for more information. The java-server-sdk library includes shadowed OkHttp classes.

To reproduce
Download Azul Zulu 8.46 (OpenJDK 8.0.252) and BouncyCastle FIPS libraries(https://www.azul.com/downloads/zulu-community/?version=java-8-lts&architecture=x86-64-bit&package=jdk, https://www.bouncycastle.org/fips-java/). Put these, as well as LD java-server-sdk 4.14.1 on the class path. Configure a custom java.security.override file:

jdk.tls.disabledAlgorithms=SSLv2Hello, SSLv3, TLSv1, RC4, MD5withRSA, DH keySize < 1024, EC keySize < 224, DES, 3DES
crypto.policy=unlimited
security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider C:DEFRND[HMACSHA256];ENABLE{ALL};
security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider fips:BCFIPS
security.provider.3=com.sun.net.ssl.internal.ssl.Provider
security.provider.4=sun.security.provider.Sun
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=sun.security.mscapi.SunMSCAPI
securerandom.source=file:/dev/urandom
jceks.key.serialFilter = org.bouncycastle.**;java.lang.Enum;java.security.KeyRep;
java.security.KeyRep$Type;javax.crypto.spec.SecretKeySpec;!*

Run LDClientTest with Azul Zulu:
java -cp LDClientTest.class:bc-fips-1.0.1.jar:bcprov-jdk16-sahdow-1.38.jar:bctls-fips-1.0.4.jar:launchdarkly-java-server-sdk-4.14.1-patched.jar:launchdarkly-java-server-sdk-4.14.1-all.jar:. -Djava.security.properties=./java.security.override LDClientTest

import com.launchdarkly.client.LDClient;
import com.launchdarkly.client.LDUser;

class LDClientTest {
public static void main(String[] args) {
final String key = "my_sdk_key";
LDClient client = new LDClient(key);
System.out.println("Initialized: " + client.initialized());
LDUser user = new LDUser("1234");
System.out.println("Evaluated to: " + client.boolVariation("my.flag", user, true));
}
}

Expected behavior
The LDClient initializes and gets feature flag without issue.

Logs
Exception in thread "okhttp-eventsource-stream-[]-0" java.lang.AssertionError: unable to get selected protocols
at com.launchdarkly.shaded.okhttp3.internal.Util.assertionError(Util.java:504)
at com.launchdarkly.shaded.okhttp3.internal.platform.Jdk9Platform.getSelectedProtocol(Jdk9Platform.java:72)
at com.launchdarkly.shaded.okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:347)
at com.launchdarkly.shaded.okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:284)
at com.launchdarkly.shaded.okhttp3.internal.connection.RealConnection.connect(RealConnection.java:169)
at com.launchdarkly.shaded.okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:258)
at com.launchdarkly.shaded.okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
at com.launchdarkly.shaded.okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
at com.launchdarkly.shaded.okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
at com.launchdarkly.shaded.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at com.launchdarkly.shaded.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at com.launchdarkly.shaded.okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at com.launchdarkly.shaded.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at com.launchdarkly.shaded.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at com.launchdarkly.shaded.okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at com.launchdarkly.shaded.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at com.launchdarkly.shaded.okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:127)
at com.launchdarkly.shaded.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at com.launchdarkly.shaded.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at com.launchdarkly.shaded.okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:257)
at com.launchdarkly.shaded.okhttp3.RealCall.execute(RealCall.java:93)
at com.launchdarkly.shaded.com.launchdarkly.eventsource.EventSource.connect(EventSource.java:270)
at com.launchdarkly.shaded.com.launchdarkly.eventsource.EventSource.access$1300(EventSource.java:54)
at com.launchdarkly.shaded.com.launchdarkly.eventsource.EventSource$2.run(EventSource.java:157)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.launchdarkly.shaded.okhttp3.internal.platform.Jdk9Platform.getSelectedProtocol(Jdk9Platform.java:62)
... 25 more
Caused by: java.lang.UnsupportedOperationException
at javax.net.ssl.SSLSocket.getApplicationProtocol(SSLSocket.java:691)
... 30 more

SDK version
4.14.1, 5.0.3

Language version, developer tools
Azul Zulu 8.46 (OpenJDK 8.0.252) and newer. BouncyCastle cryptography libraries.

OS/platform
Not OS-specific. Issue affects all OS platforms which run Azul Zulu.

Additional context
Can be resolved by explicitly declaring dependency on okhttp 3.14.8 (or newer) in java-server-sdk. java-server-sdk has transitive dependency on okhttp by way of okthttp-eventsource. An alternative would be to update the okhttp dependency in okhttp-eventsource 1.11.1, then update the okhttp-eventsource dependency in java-server-sdk.

Thanks for reporting this. It sounds like it should be a fairly straightforward change and if so, we'll release patch versions for both 4.x and 5.x.

We've just released patches for both 4.x and 5.x. I didn't go through your suggested steps to reproduce the problem before doing this, because updating OkHttp would be a desirable thing to do in any case and it's a known issue that's mentioned in their changelog. Could you let me know when you've had a chance to retest with the new release?

Tested 4.14.2 using the procedure outlined above and in our own internal E2E tests. Works great, thanks for the quick turn-around.