使用OkHttp真正的HTTP请求Robolectric测试抛出java.lang.NullPointerException:没有找到PKCS#12密钥库提供的密码

希思边框:

我使用的是Robolectric 4.3.1testImplementation "org.robolectric:robolectric:4.3.1")创建我的集成测试一个Android源码环境。我的系统使用OkHttpimplementation 'com.squareup.okhttp3:okhttp:3.14.7')真正的HTTP请求。我没有使用MockWebServer

我升级到了Android SDK 10后,我不得不更新我的单元测试的JVM JDK 9,按照Robolectric说明

在Android API 29运行测试,现在严格要求Java9运行或更高版本。如果您看到有关通过Android Studio中运行的API 29测试时,不支持Java版本的错误; 您可以使用“JRE”字段中运行配置对话框来配置新的Java运行时。https://developer.android.com/studio/run/rundebugconfig更多的背景。

不过,现在我的集成测试失败:

java.lang.NullPointerException: No password supplied for PKCS#12 KeyStore.

    at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineLoad(Unknown Source)
    at java.base/java.security.KeyStore.load(KeyStore.java:1479)
    at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:367)
    at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:315)
    at java.base/sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:59)
    at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:51)
    at java.base/javax.net.ssl.TrustManagerFactory.init(TrustManagerFactory.java:278)
    at okhttp3.internal.Util.platformTrustManager(Util.java:640)
    at okhttp3.OkHttpClient.<init>(OkHttpClient.java:228)
    at okhttp3.OkHttpClient.<init>(OkHttpClient.java:202)

我怎样才能再次进行真正的HTTP调用?

希思边框:

TLDR

要解决这个问题,设置javax.net.ssl.trustStoreType系统属性 JKS

-Djavax.net.ssl.trustStoreType=JKS

细节

我发现这个解决办法

尝试很多事情后,我终于找到了一个解决办法:

System.setProperty("javax.net.ssl.trustStore", "NONE")

MockWebServer()

该测试都通过这个额外的配置。

然而,当我尝试过解决办法,所有与失败后我的HTTP调用ConnectException来代替:

java.net.ConnectException: Failed to connect to myhost.com:443
    at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:265)
    at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:183)
    at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
    at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108)
    at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88)
    at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
    at okhttp3.RealCall.execute(RealCall.java:81)

我怀疑是OkHttp正确地拒绝所有TLS连接,因为自从解决方法建议设置不信任他们javax.net.ssl.trustStoreNONE

我也试过指定的Java信任库的默认密码,changeit通过此解决方法

解决方法: -Djavax.net.ssl.trustStorePassword=changeit

但后来我试图实例化时,出现以下异常OkHttpClient

java.lang.AssertionError: No System TLS

    at okhttp3.internal.Util.platformTrustManager(Util.java:648)
    at okhttp3.OkHttpClient.<init>(OkHttpClient.java:228)
    at okhttp3.OkHttpClient.<init>(OkHttpClient.java:202)

这是造成:

Caused by: java.security.KeyStoreException: problem accessing trust store
    at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:75)
    at java.base/javax.net.ssl.TrustManagerFactory.init(TrustManagerFactory.java:278)
    at okhttp3.internal.Util.platformTrustManager(Util.java:640)
    ... 22 more
Caused by: java.io.IOException: stream does not represent a PKCS12 key store
    at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineLoad(Unknown Source)
    at java.base/java.security.KeyStore.load(KeyStore.java:1479)
    at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:367)
    at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:315)
    at java.base/sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:59)
    at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:51)
    ... 24 more

这是一个伟大的线索。我开始使用Android Studio中调试的JDK 9源,我注意到,当我跟跑org.junit.runners.BlockJUnit4ClassRunner,我KeyStore.keystoreSpi是一个sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12,但是当我跑org.robolectric.RobolectricTestRunner我的KeyStore.keystoreSpi是一个org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi$BCPKCS12KeyStore

JEP-229

此功能可改变从JKS到PKCS12默认密钥库类型。默认情况下,新的密钥库将在PKCS12密钥库格式创建。现有的密钥库不会改变,密钥存储应用程序可以继续明确指定他们需要的仓库类型。

现有的应用程序必须不被破坏。密钥库往往是长寿命的,所以我们需要支持跨多个JDK版本的访问。应用程序通过早期JDK版本创建的访问密钥库必须在JDK 9.运行不变同样,应用程序通过JDK 9创建的访问密钥库应该运行在较早的JDK版本不变。

这个要求是通过引入一个能理解JKS和PKCS12两种格式的密钥库中检测机制来实现的。之前它被加载,以确定其类型,然后相应的密钥仓库实现是用来访问它检查密钥库的格式。该机制是默认启用的,但如果需要,可以禁用。

这个密钥库的检测机制支持可回迁到较早的JDK版本。

因此,经典$JAVA_HOME/lib/security/cacerts仍然是一个Java密钥库,我可以验证:

$ file /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/lib/security/cacerts
/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/lib/security/cacerts: Java KeyStore

然而,由于JDK要默认PKCS12密钥库,JDK的DualFormatPKCS12会回落到一个JKS,如果读文件PKCS12失败。BouncyCastle的假设,当javax.net.ssl.trustStoreTypepkcs12那真是我们的意思。

因此,要解决这个问题,设置javax.net.ssl.trustStoreType系统属性 JKS

-Djavax.net.ssl.trustStoreType=JKS

我申请的问题与BouncyCastle的robolectric这一点。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

TOP 榜单

热门标签

归档