Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
jvmTest.okhttp3.internal.tls.ClientAuthTest Maven / Gradle / Ivy
/*
* Copyright (C) 2016 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.tls;
import java.io.IOException;
import java.net.SocketException;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
import mockwebserver3.MockResponse;
import mockwebserver3.MockWebServer;
import mockwebserver3.junit5.internal.MockWebServerExtension;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClientTestRule;
import okhttp3.RecordingEventListener;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.internal.http2.ConnectionShutdownException;
import okhttp3.testing.Flaky;
import okhttp3.testing.PlatformRule;
import okhttp3.tls.HandshakeCertificates;
import okhttp3.tls.HeldCertificate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import static java.util.Arrays.asList;
import static okhttp3.tls.internal.TlsUtil.newKeyManager;
import static okhttp3.tls.internal.TlsUtil.newTrustManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
@Tag("Slowish")
@ExtendWith(MockWebServerExtension.class)
public final class ClientAuthTest {
@RegisterExtension public final PlatformRule platform = new PlatformRule();
@RegisterExtension public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
private MockWebServer server;
private HeldCertificate serverRootCa;
private HeldCertificate serverIntermediateCa;
private HeldCertificate serverCert;
private HeldCertificate clientRootCa;
private HeldCertificate clientIntermediateCa;
private HeldCertificate clientCert;
@BeforeEach
public void setUp(MockWebServer server) {
this.server = server;
platform.assumeNotOpenJSSE();
platform.assumeNotBouncyCastle();
serverRootCa = new HeldCertificate.Builder()
.serialNumber(1L)
.certificateAuthority(1)
.commonName("root")
.addSubjectAlternativeName("root_ca.com")
.build();
serverIntermediateCa = new HeldCertificate.Builder()
.signedBy(serverRootCa)
.certificateAuthority(0)
.serialNumber(2L)
.commonName("intermediate_ca")
.addSubjectAlternativeName("intermediate_ca.com")
.build();
serverCert = new HeldCertificate.Builder()
.signedBy(serverIntermediateCa)
.serialNumber(3L)
.commonName("Local Host")
.addSubjectAlternativeName(server.getHostName())
.build();
clientRootCa = new HeldCertificate.Builder()
.serialNumber(1L)
.certificateAuthority(1)
.commonName("root")
.addSubjectAlternativeName("root_ca.com")
.build();
clientIntermediateCa = new HeldCertificate.Builder()
.signedBy(serverRootCa)
.certificateAuthority(0)
.serialNumber(2L)
.commonName("intermediate_ca")
.addSubjectAlternativeName("intermediate_ca.com")
.build();
clientCert = new HeldCertificate.Builder()
.signedBy(clientIntermediateCa)
.serialNumber(4L)
.commonName("Jethro Willis")
.addSubjectAlternativeName("jethrowillis.com")
.build();
}
@Test public void clientAuthForWants() throws Exception {
OkHttpClient client = buildClient(clientCert, clientIntermediateCa.certificate());
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.requestClientAuth();
server.enqueue(new MockResponse().setBody("abc"));
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
Response response = call.execute();
assertThat(response.handshake().peerPrincipal()).isEqualTo(
new X500Principal("CN=Local Host"));
assertThat(response.handshake().localPrincipal()).isEqualTo(
new X500Principal("CN=Jethro Willis"));
assertThat(response.body().string()).isEqualTo("abc");
}
@Test public void clientAuthForNeeds() throws Exception {
OkHttpClient client = buildClient(clientCert, clientIntermediateCa.certificate());
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.requireClientAuth();
server.enqueue(new MockResponse().setBody("abc"));
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
Response response = call.execute();
assertThat(response.handshake().peerPrincipal()).isEqualTo(
new X500Principal("CN=Local Host"));
assertThat(response.handshake().localPrincipal()).isEqualTo(
new X500Principal("CN=Jethro Willis"));
assertThat(response.body().string()).isEqualTo("abc");
}
@Test public void clientAuthSkippedForNone() throws Exception {
OkHttpClient client = buildClient(clientCert, clientIntermediateCa.certificate());
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.noClientAuth();
server.enqueue(new MockResponse().setBody("abc"));
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
Response response = call.execute();
assertThat(response.handshake().peerPrincipal()).isEqualTo(
new X500Principal("CN=Local Host"));
assertThat(response.handshake().localPrincipal()).isNull();
assertThat(response.body().string()).isEqualTo("abc");
}
@Test public void missingClientAuthSkippedForWantsOnly() throws Exception {
OkHttpClient client = buildClient(null, clientIntermediateCa.certificate());
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.requestClientAuth();
server.enqueue(new MockResponse().setBody("abc"));
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
Response response = call.execute();
assertThat(response.handshake().peerPrincipal()).isEqualTo(
new X500Principal("CN=Local Host"));
assertThat(response.handshake().localPrincipal()).isNull();
assertThat(response.body().string()).isEqualTo("abc");
}
@Test @Flaky
public void missingClientAuthFailsForNeeds() throws Exception {
// Fails with 11.0.1 https://github.com/square/okhttp/issues/4598
// StreamReset stream was reset: PROT...
OkHttpClient client = buildClient(null, clientIntermediateCa.certificate());
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.requireClientAuth();
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
try {
call.execute();
fail();
} catch (SSLHandshakeException expected) {
// JDK 11+
} catch (SSLException expected) {
// javax.net.ssl.SSLException: readRecord
} catch (SocketException expected) {
// Conscrypt, JDK 8 (>= 292), JDK 9
} catch (IOException expected) {
assertThat(expected.getMessage()).isEqualTo("exhausted all routes");
}
}
@Test public void commonNameIsNotTrusted() throws Exception {
serverCert = new HeldCertificate.Builder()
.signedBy(serverIntermediateCa)
.serialNumber(3L)
.commonName(server.getHostName())
.addSubjectAlternativeName("different-host.com")
.build();
OkHttpClient client = buildClient(clientCert, clientIntermediateCa.certificate());
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.requireClientAuth();
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
try {
call.execute();
fail();
} catch (SSLPeerUnverifiedException expected) {
}
}
@Test public void invalidClientAuthFails() throws Throwable {
// Fails with https://github.com/square/okhttp/issues/4598
// StreamReset stream was reset: PROT...
HeldCertificate clientCert2 = new HeldCertificate.Builder()
.serialNumber(4L)
.commonName("Jethro Willis")
.build();
OkHttpClient client = buildClient(clientCert2);
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.requireClientAuth();
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
try {
call.execute();
fail();
} catch (SSLHandshakeException expected) {
// JDK 11+
} catch (SSLException expected) {
// javax.net.ssl.SSLException: readRecord
} catch (SocketException expected) {
// Conscrypt, JDK 8 (>= 292), JDK 9
} catch (ConnectionShutdownException expected) {
// It didn't fail until it reached the application layer.
} catch (IOException expected) {
assertThat(expected.getMessage()).isEqualTo("exhausted all routes");
}
}
@Test public void invalidClientAuthEvents() throws Throwable {
server.enqueue(new MockResponse().setBody("abc"));
clientCert = new HeldCertificate.Builder()
.signedBy(clientIntermediateCa)
.serialNumber(4L)
.commonName("Jethro Willis")
.addSubjectAlternativeName("jethrowillis.com")
.validityInterval(1, 2)
.build();
OkHttpClient client = buildClient(clientCert, clientIntermediateCa.certificate());
RecordingEventListener listener = new RecordingEventListener();
client = client.newBuilder()
.eventListener(listener)
.build();
SSLSocketFactory socketFactory = buildServerSslSocketFactory();
server.useHttps(socketFactory, false);
server.requireClientAuth();
Call call = client.newCall(new Request.Builder().url(server.url("/")).build());
try {
call.execute();
fail();
} catch (IOException expected) {
}
// Observed Events are variable
// JDK 14
// CallStart, ProxySelectStart, ProxySelectEnd, DnsStart, DnsEnd, ConnectStart, SecureConnectStart,
// SecureConnectEnd, ConnectEnd, ConnectionAcquired, RequestHeadersStart, RequestHeadersEnd,
// ResponseFailed, ConnectionReleased, CallFailed
// JDK 8
// CallStart, ProxySelectStart, ProxySelectEnd, DnsStart, DnsEnd, ConnectStart, SecureConnectStart,
// ConnectFailed, CallFailed
// Gradle - JDK 11
// CallStart, ProxySelectStart, ProxySelectEnd, DnsStart, DnsEnd, ConnectStart, SecureConnectStart,
// SecureConnectEnd, ConnectFailed, CallFailed
List recordedEventTypes = listener.recordedEventTypes();
assertThat(recordedEventTypes).startsWith(
"CallStart", "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "SecureConnectStart");
assertThat(recordedEventTypes).endsWith("CallFailed");
}
private OkHttpClient buildClient(
HeldCertificate heldCertificate, X509Certificate... intermediates) {
HandshakeCertificates.Builder builder = new HandshakeCertificates.Builder()
.addTrustedCertificate(serverRootCa.certificate());
if (heldCertificate != null) {
builder.heldCertificate(heldCertificate, intermediates);
}
HandshakeCertificates handshakeCertificates = builder.build();
return clientTestRule.newClientBuilder()
.sslSocketFactory(
handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager())
.build();
}
private SSLSocketFactory buildServerSslSocketFactory() {
// The test uses JDK default SSL Context instead of the Platform provided one
// as Conscrypt seems to have some differences, we only want to test client side here.
try {
X509KeyManager keyManager = newKeyManager(
null, serverCert, serverIntermediateCa.certificate());
X509TrustManager trustManager = newTrustManager(null,
asList(serverRootCa.certificate(), clientRootCa.certificate()), Collections.emptyList());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] {keyManager}, new TrustManager[] {trustManager},
new SecureRandom());
return sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new AssertionError(e);
}
}
}