1
0
mirror of https://github.com/square/okhttp.git synced 2025-08-08 23:42:08 +03:00

OpenJSSE Platform support (#5369)

Adds support for OpenJSSE when registered as the first security provider.
This commit is contained in:
Yuri Schimke
2019-08-18 12:03:51 +03:00
committed by GitHub
parent a1994dab34
commit 7cf508a30b
21 changed files with 267 additions and 65 deletions

View File

@@ -140,6 +140,20 @@ jobs:
- runtests: - runtests:
platform: jdk8alpn platform: jdk8alpn
testopenjsse:
docker:
- image: circleci/openjdk:8u171-jdk
environment:
JVM_OPTS: -Xmx1g
TERM: dumb
steps:
- checkout
- runtests:
platform: openjsse
testjdk11: testjdk11:
docker: docker:
- image: circleci/openjdk:11.0.3-jdk-stretch - image: circleci/openjdk:11.0.3-jdk-stretch
@@ -205,6 +219,11 @@ workflows:
filters: filters:
branches: branches:
only: master only: master
- testopenjsse:
filters:
branches:
ignore:
- gh-pages
- testjdk11: - testjdk11:
filters: filters:
branches: branches:
@@ -236,6 +255,9 @@ workflows:
- testjdk8alpn: - testjdk8alpn:
requires: requires:
- compile - compile
- testopenjsse:
requires:
- compile
- testjdk11: - testjdk11:
requires: requires:
- compile - compile

View File

@@ -159,6 +159,10 @@ subprojects { project ->
dependencies { dependencies {
testRuntime "org.conscrypt:conscrypt-openjdk-uber:${versions.conscrypt}" testRuntime "org.conscrypt:conscrypt-openjdk-uber:${versions.conscrypt}"
} }
} else if (platform == "openjsse") {
dependencies {
testRuntime deps.openjsse
}
} }
dependencies { dependencies {

View File

@@ -3,6 +3,7 @@ dependencies {
api deps.junit api deps.junit
api deps.assertj api deps.assertj
api deps.conscrypt api deps.conscrypt
api deps.openjsse
compileOnly deps.jsr305 compileOnly deps.jsr305
} }

View File

@@ -15,12 +15,16 @@
*/ */
package okhttp3; package okhttp3;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import okhttp3.internal.http2.Header; import okhttp3.internal.http2.Header;
import static org.junit.Assume.assumeNoException;
public final class TestUtil { public final class TestUtil {
public static final InetSocketAddress UNREACHABLE_ADDRESS public static final InetSocketAddress UNREACHABLE_ADDRESS
= new InetSocketAddress("198.51.100.1", 8080); = new InetSocketAddress("198.51.100.1", 8080);
@@ -52,4 +56,12 @@ public final class TestUtil {
Thread.sleep(100); Thread.sleep(100);
System.runFinalization(); System.runFinalization();
} }
public static void assumeNetwork() {
try {
InetAddress.getByName("www.google.com");
} catch (UnknownHostException uhe) {
assumeNoException(uhe);
}
}
} }

View File

@@ -18,6 +18,7 @@ package okhttp3.testing
import okhttp3.internal.platform.ConscryptPlatform import okhttp3.internal.platform.ConscryptPlatform
import okhttp3.internal.platform.Jdk8WithJettyBootPlatform import okhttp3.internal.platform.Jdk8WithJettyBootPlatform
import okhttp3.internal.platform.Jdk9Platform import okhttp3.internal.platform.Jdk9Platform
import okhttp3.internal.platform.OpenJSSEPlatform
import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
import org.hamcrest.BaseMatcher import org.hamcrest.BaseMatcher
@@ -34,6 +35,7 @@ import org.junit.Assume.assumeTrue
import org.junit.AssumptionViolatedException import org.junit.AssumptionViolatedException
import org.junit.rules.TestRule import org.junit.rules.TestRule
import org.junit.runners.model.Statement import org.junit.runners.model.Statement
import org.openjsse.net.ssl.OpenJSSE
import java.security.Security import java.security.Security
/** /**
@@ -57,6 +59,8 @@ open class PlatformRule @JvmOverloads constructor(
try { try {
setupPlatform() setupPlatform()
System.err.println("Running with ${Platform.get().javaClass.simpleName}")
base.evaluate() base.evaluate()
} catch (e: AssumptionViolatedException) { } catch (e: AssumptionViolatedException) {
throw e throw e
@@ -95,6 +99,10 @@ open class PlatformRule @JvmOverloads constructor(
expectFailure(platformMatches(CONSCRYPT_PROPERTY)) expectFailure(platformMatches(CONSCRYPT_PROPERTY))
} }
fun expectFailureOnOpenJSSEPlatform() {
expectFailure(platformMatches(OPENJSSE_PROPERTY))
}
fun expectFailureFromJdkVersion(majorVersion: Int) { fun expectFailureFromJdkVersion(majorVersion: Int) {
expectFailure(fromMajor(majorVersion)) expectFailure(fromMajor(majorVersion))
} }
@@ -118,7 +126,7 @@ open class PlatformRule @JvmOverloads constructor(
fun fromMajor(version: Int): Matcher<PlatformVersion> { fun fromMajor(version: Int): Matcher<PlatformVersion> {
return object : TypeSafeMatcher<PlatformVersion>() { return object : TypeSafeMatcher<PlatformVersion>() {
override fun describeTo(description: org.hamcrest.Description) { override fun describeTo(description: Description) {
description.appendText("JDK with version from $version") description.appendText("JDK with version from $version")
} }
@@ -171,6 +179,11 @@ open class PlatformRule @JvmOverloads constructor(
JDK9_PROPERTY)) JDK9_PROPERTY))
} }
fun assumeOpenJSSE() {
assumeThat(getPlatformSystemProperty(), equalTo(
OPENJSSE_PROPERTY))
}
fun assumeJdk8() { fun assumeJdk8() {
assumeThat(getPlatformSystemProperty(), equalTo( assumeThat(getPlatformSystemProperty(), equalTo(
JDK8_PROPERTY)) JDK8_PROPERTY))
@@ -206,6 +219,11 @@ open class PlatformRule @JvmOverloads constructor(
JDK8_ALPN_PROPERTY)) JDK8_ALPN_PROPERTY))
} }
fun assumeNotOpenJSSE() {
assumeThat(getPlatformSystemProperty(), not(
OPENJSSE_PROPERTY))
}
fun assumeNotHttp2Support() { fun assumeNotHttp2Support() {
assumeThat(getPlatformSystemProperty(), equalTo( assumeThat(getPlatformSystemProperty(), equalTo(
JDK8_PROPERTY)) JDK8_PROPERTY))
@@ -221,6 +239,7 @@ open class PlatformRule @JvmOverloads constructor(
const val JDK9_PROPERTY = "jdk9" const val JDK9_PROPERTY = "jdk9"
const val JDK8_ALPN_PROPERTY = "jdk8alpn" const val JDK8_ALPN_PROPERTY = "jdk8alpn"
const val JDK8_PROPERTY = "jdk8" const val JDK8_PROPERTY = "jdk8"
const val OPENJSSE_PROPERTY = "openjsse"
init { init {
if (getPlatformSystemProperty() == CONSCRYPT_PROPERTY && Security.getProviders()[0].name != "Conscrypt") { if (getPlatformSystemProperty() == CONSCRYPT_PROPERTY && Security.getProviders()[0].name != "Conscrypt") {
@@ -238,7 +257,15 @@ open class PlatformRule @JvmOverloads constructor(
if (isAlpnBootEnabled()) { if (isAlpnBootEnabled()) {
System.err.println("Warning: ALPN Boot enabled unintentionally") System.err.println("Warning: ALPN Boot enabled unintentionally")
} }
} else if (getPlatformSystemProperty() == OPENJSSE_PROPERTY && Security.getProviders()[0].name != "OpenJSSE") {
if (!OpenJSSEPlatform.isSupported) {
System.err.println("Warning: OpenJSSE not available")
}
Security.insertProviderAt(OpenJSSE(), 1)
} }
Platform.resetForTests()
} }
@JvmStatic @JvmStatic
@@ -249,6 +276,7 @@ open class PlatformRule @JvmOverloads constructor(
if (property == null) { if (property == null) {
property = when (Platform.get()) { property = when (Platform.get()) {
is ConscryptPlatform -> CONSCRYPT_PROPERTY is ConscryptPlatform -> CONSCRYPT_PROPERTY
is OpenJSSEPlatform -> OPENJSSE_PROPERTY
is Jdk8WithJettyBootPlatform -> CONSCRYPT_PROPERTY is Jdk8WithJettyBootPlatform -> CONSCRYPT_PROPERTY
is Jdk9Platform -> JDK9_PROPERTY is Jdk9Platform -> JDK9_PROPERTY
else -> JDK8_PROPERTY else -> JDK8_PROPERTY
@@ -261,6 +289,9 @@ open class PlatformRule @JvmOverloads constructor(
@JvmStatic @JvmStatic
fun conscrypt() = PlatformRule(CONSCRYPT_PROPERTY) fun conscrypt() = PlatformRule(CONSCRYPT_PROPERTY)
@JvmStatic
fun openjsse() = PlatformRule(OPENJSSE_PROPERTY)
@JvmStatic @JvmStatic
fun jdk9() = PlatformRule(JDK9_PROPERTY) fun jdk9() = PlatformRule(JDK9_PROPERTY)

View File

@@ -26,6 +26,7 @@ dependencies {
api deps.okio api deps.okio
api deps.kotlinStdlib api deps.kotlinStdlib
compileOnly deps.conscrypt compileOnly deps.conscrypt
compileOnly deps.openjsse
compileOnly deps.android compileOnly deps.android
compileOnly deps.jsr305 compileOnly deps.jsr305
compileOnly deps.animalSniffer compileOnly deps.animalSniffer

View File

@@ -542,3 +542,27 @@ inline fun Any.notify() = (this as Object).notify()
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE") @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE")
inline fun Any.notifyAll() = (this as Object).notifyAll() inline fun Any.notifyAll() = (this as Object).notifyAll()
fun <T> readFieldOrNull(instance: Any, fieldType: Class<T>, fieldName: String): T? {
var c: Class<*> = instance.javaClass
while (c != Any::class.java) {
try {
val field = c.getDeclaredField(fieldName)
field.isAccessible = true
val value = field.get(instance)
return if (!fieldType.isInstance(value)) null else fieldType.cast(value)
} catch (_: NoSuchFieldException) {
}
c = c.superclass
}
// Didn't find the field we wanted. As a last gasp attempt,
// try to find the value on a delegate.
if (fieldName != "delegate") {
val delegate = readFieldOrNull(instance, Any::class.java, "delegate")
if (delegate != null) return readFieldOrNull(delegate, fieldType, fieldName)
}
return null
}

View File

@@ -15,7 +15,6 @@
*/ */
package okhttp3.internal.platform package okhttp3.internal.platform
import android.annotation.SuppressLint
import android.os.Build import android.os.Build
import okhttp3.Protocol import okhttp3.Protocol
import okhttp3.internal.platform.android.CloseGuard import okhttp3.internal.platform.android.CloseGuard
@@ -225,7 +224,6 @@ class AndroidPlatform : Platform() {
} }
companion object { companion object {
@SuppressLint("PrivateApi")
val isSupported: Boolean = try { val isSupported: Boolean = try {
// Trigger an early exception over a fatal error, prefer a RuntimeException over Error. // Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl") Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl")

View File

@@ -16,6 +16,7 @@
package okhttp3.internal.platform package okhttp3.internal.platform
import okhttp3.Protocol import okhttp3.Protocol
import okhttp3.internal.readFieldOrNull
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
import java.security.Provider import java.security.Provider
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext
@@ -29,13 +30,9 @@ import javax.net.ssl.X509TrustManager
* Requires org.conscrypt:conscrypt-openjdk-uber >= 2.1.0 on the classpath. * Requires org.conscrypt:conscrypt-openjdk-uber >= 2.1.0 on the classpath.
*/ */
class ConscryptPlatform private constructor() : Platform() { class ConscryptPlatform private constructor() : Platform() {
private val provider: Provider // n.b. We should consider defaulting to OpenJDK 11 trust manager
get() { // https://groups.google.com/forum/#!topic/conscrypt/3vYzbesjOb4
// n.b. We should consider defaulting to OpenJDK 11 trust manager private val provider: Provider = Conscrypt.newProviderBuilder().provideTrustManager(true).build()
// https://groups.google.com/forum/#!topic/conscrypt/3vYzbesjOb4
return Conscrypt.newProviderBuilder().provideTrustManager(true).build()
}
// See release notes https://groups.google.com/forum/#!forum/conscrypt // See release notes https://groups.google.com/forum/#!forum/conscrypt
// for version differences // for version differences

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2019 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3.internal.platform
import okhttp3.Protocol
import java.security.KeyStore
import java.security.Provider
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
/**
* Platform using OpenJSSE (https://github.com/openjsse/openjsse) if installed as the first
* Security Provider.
*
* Requires org.openjsse:openjsse >= 1.1.0 on the classpath.
*/
class OpenJSSEPlatform private constructor() : Platform() {
private val provider: Provider = org.openjsse.net.ssl.OpenJSSE()
// Selects TLSv1.3 so we are specific about our intended version ranges (not just 1.3)
// and because it's a common pattern for VMs to have differences between supported and
// defaulted versions for TLS based on what is requested.
override fun newSSLContext(): SSLContext =
SSLContext.getInstance("TLSv1.3", provider)
override fun platformTrustManager(): X509TrustManager {
val factory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm(), provider)
factory.init(null as KeyStore?)
val trustManagers = factory.trustManagers!!
check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
"Unexpected default trust managers: ${trustManagers.contentToString()}"
}
return trustManagers[0] as X509TrustManager
}
public override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? =
throw UnsupportedOperationException(
"clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with OpenJSSE")
override fun configureTlsExtensions(
sslSocket: SSLSocket,
hostname: String?,
protocols: List<Protocol>
) {
if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) {
val sslParameters = sslSocket.sslParameters
if (sslParameters is org.openjsse.javax.net.ssl.SSLParameters) {
// Enable ALPN.
val names = alpnProtocolNames(protocols)
sslParameters.applicationProtocols = names.toTypedArray()
sslSocket.sslParameters = sslParameters
}
} else {
super.configureTlsExtensions(sslSocket, hostname, protocols)
}
}
override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) {
when (val protocol = sslSocket.applicationProtocol) {
// Handles both un-configured and none selected.
null, "" -> null
else -> protocol
}
} else {
super.getSelectedProtocol(sslSocket)
}
companion object {
val isSupported: Boolean = try {
// Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
Class.forName("org.openjsse.net.ssl.OpenJSSE")
true
} catch (_: ClassNotFoundException) {
false
}
fun buildIfSupported(): OpenJSSEPlatform? = if (isSupported) OpenJSSEPlatform() else null
}
}

View File

@@ -18,6 +18,7 @@ package okhttp3.internal.platform
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Protocol import okhttp3.Protocol
import okhttp3.internal.readFieldOrNull
import okhttp3.internal.tls.BasicCertificateChainCleaner import okhttp3.internal.tls.BasicCertificateChainCleaner
import okhttp3.internal.tls.BasicTrustRootIndex import okhttp3.internal.tls.BasicTrustRootIndex
import okhttp3.internal.tls.CertificateChainCleaner import okhttp3.internal.tls.CertificateChainCleaner
@@ -193,12 +194,18 @@ open class Platform {
fun alpnProtocolNames(protocols: List<Protocol>) = fun alpnProtocolNames(protocols: List<Protocol>) =
protocols.filter { it != Protocol.HTTP_1_0 }.map { it.toString() } protocols.filter { it != Protocol.HTTP_1_0 }.map { it.toString() }
val isConscryptPreferred: Boolean private val isConscryptPreferred: Boolean
get() { get() {
val preferredProvider = Security.getProviders()[0].name val preferredProvider = Security.getProviders()[0].name
return "Conscrypt" == preferredProvider return "Conscrypt" == preferredProvider
} }
private val isOpenJSSEPreferred: Boolean
get() {
val preferredProvider = Security.getProviders()[0].name
return "OpenJSSE" == preferredProvider
}
/** Attempt to match the host runtime to a capable Platform implementation. */ /** Attempt to match the host runtime to a capable Platform implementation. */
private fun findPlatform(): Platform { private fun findPlatform(): Platform {
val android = AndroidPlatform.buildIfSupported() val android = AndroidPlatform.buildIfSupported()
@@ -215,6 +222,14 @@ open class Platform {
} }
} }
if (isOpenJSSEPreferred) {
val openJSSE = OpenJSSEPlatform.buildIfSupported()
if (openJSSE != null) {
return openJSSE
}
}
val jdk9 = Jdk9Platform.buildIfSupported() val jdk9 = Jdk9Platform.buildIfSupported()
if (jdk9 != null) { if (jdk9 != null) {
@@ -239,29 +254,5 @@ open class Platform {
} }
return result.readByteArray() return result.readByteArray()
} }
fun <T> readFieldOrNull(instance: Any, fieldType: Class<T>, fieldName: String): T? {
var c: Class<*> = instance.javaClass
while (c != Any::class.java) {
try {
val field = c.getDeclaredField(fieldName)
field.isAccessible = true
val value = field.get(instance)
return if (!fieldType.isInstance(value)) null else fieldType.cast(value)
} catch (_: NoSuchFieldException) {
}
c = c.superclass
}
// Didn't find the field we wanted. As a last gasp attempt,
// try to find the value on a delegate.
if (fieldName != "delegate") {
val delegate = readFieldOrNull(instance, Any::class.java, "delegate")
if (delegate != null) return readFieldOrNull(delegate, fieldType, fieldName)
}
return null
}
} }
} }

View File

@@ -16,6 +16,7 @@
package okhttp3.internal.platform.android package okhttp3.internal.platform.android
import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform
import okhttp3.internal.readFieldOrNull
import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager import javax.net.ssl.X509TrustManager
@@ -35,11 +36,11 @@ class StandardAndroidSocketAdapter(
override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? { override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? {
val context: Any? = val context: Any? =
Platform.readFieldOrNull(sslSocketFactory, paramClass, readFieldOrNull(sslSocketFactory, paramClass,
"sslParameters") "sslParameters")
val x509TrustManager = Platform.readFieldOrNull( val x509TrustManager = readFieldOrNull(
context!!, X509TrustManager::class.java, "x509TrustManager") context!!, X509TrustManager::class.java, "x509TrustManager")
return x509TrustManager ?: Platform.readFieldOrNull(context, return x509TrustManager ?: readFieldOrNull(context,
X509TrustManager::class.java, X509TrustManager::class.java,
"trustManager") "trustManager")
} }

View File

@@ -40,6 +40,7 @@ import okhttp3.internal.platform.Platform;
import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest; import okhttp3.mockwebserver.RecordedRequest;
import okhttp3.testing.PlatformRule;
import okhttp3.tls.HandshakeCertificates; import okhttp3.tls.HandshakeCertificates;
import okio.Buffer; import okio.Buffer;
import okio.BufferedSink; import okio.BufferedSink;
@@ -65,6 +66,7 @@ public final class CacheTest {
@Rule public MockWebServer server2 = new MockWebServer(); @Rule public MockWebServer server2 = new MockWebServer();
@Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem(); @Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem();
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule(); @Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
@Rule public final PlatformRule platform = new PlatformRule();
private final HandshakeCertificates handshakeCertificates = localhost(); private final HandshakeCertificates handshakeCertificates = localhost();
private OkHttpClient client; private OkHttpClient client;
@@ -72,6 +74,8 @@ public final class CacheTest {
private final CookieManager cookieManager = new CookieManager(); private final CookieManager cookieManager = new CookieManager();
@Before public void setUp() throws Exception { @Before public void setUp() throws Exception {
platform.assumeNotOpenJSSE();
server.setProtocolNegotiationEnabled(false); server.setProtocolNegotiationEnabled(false);
cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem); cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem);
client = clientTestRule.newClientBuilder() client = clientTestRule.newClientBuilder()
@@ -82,7 +86,10 @@ public final class CacheTest {
@After public void tearDown() throws Exception { @After public void tearDown() throws Exception {
ResponseCache.setDefault(null); ResponseCache.setDefault(null);
cache.delete();
if (cache != null) {
cache.delete();
}
} }
/** /**

View File

@@ -117,6 +117,8 @@ public final class CallTest {
private Logger logger = Logger.getLogger(OkHttpClient.class.getName()); private Logger logger = Logger.getLogger(OkHttpClient.class.getName());
@Before public void setUp() { @Before public void setUp() {
platform.assumeNotOpenJSSE();
logger.addHandler(logHandler); logger.addHandler(logHandler);
client = clientTestRule.newClientBuilder() client = clientTestRule.newClientBuilder()
.eventListener(listener) .eventListener(listener)

View File

@@ -15,6 +15,7 @@
*/ */
package okhttp3 package okhttp3
import okhttp3.TestUtil.assumeNetwork
import okhttp3.internal.platform.ConscryptPlatform import okhttp3.internal.platform.ConscryptPlatform
import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform
import okhttp3.testing.PlatformRule import okhttp3.testing.PlatformRule
@@ -22,13 +23,10 @@ import org.assertj.core.api.Assertions.assertThat
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Assume
import org.junit.Before import org.junit.Before
import org.junit.Ignore import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import java.net.InetAddress
import java.net.UnknownHostException
class ConscryptTest { class ConscryptTest {
@Suppress("RedundantVisibilityModifier") @Suppress("RedundantVisibilityModifier")
@@ -49,14 +47,6 @@ class ConscryptTest {
assertThat(Conscrypt.isConscrypt(Platform.get().platformTrustManager())).isTrue() assertThat(Conscrypt.isConscrypt(Platform.get().platformTrustManager())).isTrue()
} }
private fun assumeNetwork() {
try {
InetAddress.getByName("www.google.com")
} catch (uhe: UnknownHostException) {
Assume.assumeNoException(uhe)
}
}
@Test @Test
@Ignore @Ignore
fun testMozilla() { fun testMozilla() {

View File

@@ -54,6 +54,7 @@ public final class DuplexTest {
private OkHttpClient client; private OkHttpClient client;
@Before public void setUp() { @Before public void setUp() {
platform.assumeNotOpenJSSE();
platform.assumeHttp2Support(); platform.assumeHttp2Support();
client = clientTestRule.newClientBuilder() client = clientTestRule.newClientBuilder()
.eventListener(listener) .eventListener(listener)

View File

@@ -86,6 +86,8 @@ public final class EventListenerTest {
private SocksProxy socksProxy; private SocksProxy socksProxy;
@Before public void setUp() { @Before public void setUp() {
platform.assumeNotOpenJSSE();
client = clientTestRule.newClientBuilder() client = clientTestRule.newClientBuilder()
.eventListener(listener) .eventListener(listener)
.build(); .build();

View File

@@ -15,23 +15,22 @@
*/ */
package okhttp3 package okhttp3
import okhttp3.Protocol.HTTP_2 import okhttp3.TestUtil.assumeNetwork
import okhttp3.internal.platform.OpenJSSEPlatform
import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.MockWebServer
import okhttp3.testing.PlatformRule import okhttp3.testing.PlatformRule
import okhttp3.tls.HandshakeCertificates import okhttp3.tls.HandshakeCertificates
import okhttp3.tls.HeldCertificate import okhttp3.tls.HeldCertificate
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.openjsse.net.ssl.OpenJSSE
import org.openjsse.sun.security.ssl.SSLSocketFactoryImpl import org.openjsse.sun.security.ssl.SSLSocketFactoryImpl
import org.openjsse.sun.security.ssl.SSLSocketImpl import org.openjsse.sun.security.ssl.SSLSocketImpl
import java.net.InetAddress import java.net.InetAddress
import java.security.Security
class OpenJSSETest { class OpenJSSETest {
@JvmField @Rule var platform = PlatformRule() @JvmField @Rule var platform = PlatformRule()
@@ -41,17 +40,11 @@ class OpenJSSETest {
@Before @Before
fun setUp() { fun setUp() {
platform.assumeJdk8() platform.assumeOpenJSSE()
Security.insertProviderAt(OpenJSSE(), 1)
client = clientTestRule.newClient() client = clientTestRule.newClient()
} }
@After
fun cleanup() {
Security.removeProvider("OpenJSSE")
}
@Test @Test
fun testTlsv13Works() { fun testTlsv13Works() {
enableTls() enableTls()
@@ -65,7 +58,7 @@ class OpenJSSETest {
response.use { response.use {
assertEquals(200, response.code) assertEquals(200, response.code)
assertEquals(TlsVersion.TLS_1_3, response.handshake?.tlsVersion) assertEquals(TlsVersion.TLS_1_3, response.handshake?.tlsVersion)
assertEquals(Protocol.HTTP_1_1, response.protocol) assertEquals(Protocol.HTTP_2, response.protocol)
assertThat(response.exchange?.connection()?.socket()).isInstanceOf(SSLSocketImpl::class.java) assertThat(response.exchange?.connection()?.socket()).isInstanceOf(SSLSocketImpl::class.java)
} }
@@ -76,14 +69,31 @@ class OpenJSSETest {
val factory = SSLSocketFactoryImpl() val factory = SSLSocketFactoryImpl()
val s = factory.createSocket() as SSLSocketImpl val s = factory.createSocket() as SSLSocketImpl
// A Public API available is available to use in a custom Platform
s.setHandshakeApplicationProtocolSelector { _, _ -> HTTP_2.toString() }
assertEquals(listOf("TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"), s.enabledProtocols.toList()) assertEquals(listOf("TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"), s.enabledProtocols.toList())
} }
@Test
@Ignore
fun testMozilla() {
assumeNetwork()
val request = Request.Builder().url("https://mozilla.org/robots.txt").build()
client.newCall(request).execute().use {
assertThat(it.protocol).isEqualTo(Protocol.HTTP_2)
assertThat(it.handshake!!.tlsVersion).isEqualTo(TlsVersion.TLS_1_3)
}
}
@Test
fun testBuildIfSupported() {
val actual = OpenJSSEPlatform.buildIfSupported()
assertThat(actual).isNotNull
}
private fun enableTls() { private fun enableTls() {
// Generate a self-signed cert for the server to serve and the client to trust. // Generate a self-signed cert for the server to serve and the client to trust.
// can't use localhost with a non OpenJSSE trust manager // can't use TlsUtil.localhost with a non OpenJSSE trust manager
val heldCertificate = HeldCertificate.Builder() val heldCertificate = HeldCertificate.Builder()
.commonName("localhost") .commonName("localhost")
.addSubjectAlternativeName(InetAddress.getByName("localhost").canonicalHostName) .addSubjectAlternativeName(InetAddress.getByName("localhost").canonicalHostName)

View File

@@ -129,6 +129,8 @@ public final class HttpOverHttp2Test {
} }
@Before public void setUp() { @Before public void setUp() {
platform.assumeNotOpenJSSE();
if (protocol == Protocol.HTTP_2) { if (protocol == Protocol.HTTP_2) {
platform.assumeHttp2Support(); platform.assumeHttp2Support();
server.useHttps(handshakeCertificates.sslSocketFactory(), false); server.useHttps(handshakeCertificates.sslSocketFactory(), false);

View File

@@ -65,6 +65,8 @@ public final class ClientAuthTest {
@Before @Before
public void setUp() { public void setUp() {
platform.assumeNotOpenJSSE();
serverRootCa = new HeldCertificate.Builder() serverRootCa = new HeldCertificate.Builder()
.serialNumber(1L) .serialNumber(1L)
.certificateAuthority(1) .certificateAuthority(1)

View File

@@ -42,6 +42,7 @@ import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest; import okhttp3.mockwebserver.RecordedRequest;
import okhttp3.mockwebserver.SocketPolicy; import okhttp3.mockwebserver.SocketPolicy;
import okhttp3.testing.Flaky; import okhttp3.testing.Flaky;
import okhttp3.testing.PlatformRule;
import okhttp3.tls.HandshakeCertificates; import okhttp3.tls.HandshakeCertificates;
import okio.Buffer; import okio.Buffer;
import okio.ByteString; import okio.ByteString;
@@ -65,6 +66,7 @@ public final class WebSocketHttpTest {
@Rule public final MockWebServer webServer = new MockWebServer(); @Rule public final MockWebServer webServer = new MockWebServer();
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule(); @Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
@Rule public final PlatformRule platform = new PlatformRule();
private final HandshakeCertificates handshakeCertificates = localhost(); private final HandshakeCertificates handshakeCertificates = localhost();
private final WebSocketRecorder clientListener = new WebSocketRecorder("client"); private final WebSocketRecorder clientListener = new WebSocketRecorder("client");
@@ -73,6 +75,8 @@ public final class WebSocketHttpTest {
private OkHttpClient client; private OkHttpClient client;
@Before public void setUp() { @Before public void setUp() {
platform.assumeNotOpenJSSE();
client = clientTestRule.newClientBuilder() client = clientTestRule.newClientBuilder()
.writeTimeout(500, TimeUnit.MILLISECONDS) .writeTimeout(500, TimeUnit.MILLISECONDS)
.readTimeout(500, TimeUnit.MILLISECONDS) .readTimeout(500, TimeUnit.MILLISECONDS)