首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用OkHttp进行实际HTTP请求的Robolec计量测试引发java.lang.NullPointerException:没有为PKCS#12 KeyStore提供密码

使用OkHttp进行实际HTTP请求的Robolec计量测试引发java.lang.NullPointerException:没有为PKCS#12 KeyStore提供密码
EN

Stack Overflow用户
提问于 2020-03-01 06:58:08
回答 2查看 3.5K关注 0票数 9

我正在使用Robolectric 4.3.1 (testImplementation "org.robolectric:robolectric:4.3.1")为我的集成测试创建一个Android环境。我的系统使用OkHttp (implementation 'com.squareup.okhttp3:okhttp:3.14.7')来处理实际的HTTP请求。我不使用MockWebServer

升级到Android 10 SDK之后,我不得不将我的单元测试JVM更新为JDK 9,根据罗波里的指示

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

但是,现在我的集成测试失败了:

代码语言:javascript
复制
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调用?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-03-01 06:58:08

TLDR

若要解决此问题,请将javax.net.ssl.trustStoreType系统属性设置为JKS

代码语言:javascript
复制
-Djavax.net.ssl.trustStoreType=JKS

详细信息

我找到了这个解决办法

在尝试了许多事情之后,我终于找到了一个解决办法: System.setProperty("javax.net.ssl.trustStore",“无”) MockWebServer() 测试通过了这个附加的配置。

然而,当我尝试解决这个问题时,我的所有HTTP调用都失败了,而是使用了以下ConnectException

代码语言:javascript
复制
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.trustStore设置为NONE

我还尝试通过这个解决办法为java信任库指定默认密码,这个解决办法

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

但是,在尝试实例化OkHttpClient时,我得到了以下异常

代码语言:javascript
复制
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)

这是由以下原因造成的:

代码语言:javascript
复制
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调试JDK 9源代码,我注意到当我使用org.junit.runners.BlockJUnit4ClassRunner运行时,我的KeyStore.keystoreSpi是一个sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12,但是当我使用org.robolectric.RobolectricTestRunner运行时,它是一个org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi$BCPKCS12KeyStore

根据JEP-229

此特性将默认密钥库类型从JKS更改为PKCS12。默认情况下,将以PKCS12密钥存储格式创建新的密钥存储库。现有的密钥存储库不会更改,密钥存储库应用程序可以继续显式地指定它们所需的密钥存储库类型。 现有的应用程序绝不能中断。密钥存储系统往往寿命较长,因此我们需要支持跨几个JDK版本的访问。访问早期JDK发行版创建的密钥存储的应用程序必须在JDK 9上不受更改地运行。类似地,访问JDK 9创建的密钥存储的应用程序应该在早期JDK发行版上不受更改地运行。 这个需求是通过引入一种同时理解JKS和PKCS12格式的keystore检测机制来实现的。在加载密钥存储库的格式以确定其类型之前,将检查它的格式,然后使用适当的密钥存储库实现来访问它。默认情况下该机制是启用的,但如果需要,可以禁用该机制。 对这个keystore检测机制的支持可以移植到早期的JDK版本中。

因此,经典的$JAVA_HOME/lib/security/cacerts仍然是Java,我可以验证:

代码语言:javascript
复制
$ 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密钥存储库,因此如果在DualFormatPKCS12失败时读取文件,JDK的DualFormatPKCS12将返回到JKS。邦西卡塞尔假定,当javax.net.ssl.trustStoreTypepkcs12时,这就是我们真正的意思。

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

代码语言:javascript
复制
-Djavax.net.ssl.trustStoreType=JKS

我向赏金城堡罗密特提出了这方面的问题。

票数 8
EN

Stack Overflow用户

发布于 2021-12-23 01:10:31

如果Robolectric面临此问题,请将版本升级到4.4,因为在版本4.4中已经解决了这些问题

testImplementation (‘org.robolecture:robolectric:4.4’)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60472729

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档