我正在使用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。
但是,现在我的集成测试失败了:
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调用?
发布于 2020-03-01 06:58:08
TLDR
若要解决此问题,请将javax.net.ssl.trustStoreType系统属性设置为JKS
-Djavax.net.ssl.trustStoreType=JKS详细信息
我找到了这个解决办法
在尝试了许多事情之后,我终于找到了一个解决办法: System.setProperty("javax.net.ssl.trustStore",“无”) 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.trustStore设置为NONE。
我还尝试通过这个解决办法为java信任库指定默认密码,这个解决办法。
解决办法:
-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调试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,我可以验证:
$ 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.trustStoreType是pkcs12时,这就是我们真正的意思。
因此,要解决此问题,请将javax.net.ssl.trustStoreType系统属性设置为JKS
-Djavax.net.ssl.trustStoreType=JKS发布于 2021-12-23 01:10:31
如果Robolectric面临此问题,请将版本升级到4.4,因为在版本4.4中已经解决了这些问题
testImplementation (‘org.robolecture:robolectric:4.4’)
https://stackoverflow.com/questions/60472729
复制相似问题