Skip to content

Commit 8870995

Browse files
committed
Remove FakeX509ExtendedTrustManager and rename tests
The checkServerTrustedCalled wasn't actually testing what it tried to; it would become true simply because of the TLS handshake. That led to searching for a proper way to test it and renaming the tests so it was clearer what was and wasn't tested which led to further test tweaks.
1 parent 52f4a4a commit 8870995

File tree

1 file changed

+70
-62
lines changed

1 file changed

+70
-62
lines changed

okhttp/src/test/java/io/grpc/okhttp/TlsTest.java

Lines changed: 70 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ public void basicTls_succeeds() throws Exception {
112112
}
113113

114114
@Test
115-
public void perRpcAuthorityOverride_hostnameVerification_success()
116-
throws Exception {
115+
public void perRpcAuthorityOverride_hostnameVerifier_goodAuthority_succeeds() throws Exception {
117116
OkHttpClientTransport.enablePerRpcAuthorityCheck = true;
118117
try {
119118
ServerCredentials serverCreds;
@@ -133,15 +132,15 @@ public void perRpcAuthorityOverride_hostnameVerification_success()
133132
ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds));
134133

135134
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
136-
CallOptions.DEFAULT.withAuthority("foo.test.google.fr"),
135+
CallOptions.DEFAULT.withAuthority("good.test.google.fr"),
137136
SimpleRequest.getDefaultInstance());
138137
} finally {
139138
OkHttpClientTransport.enablePerRpcAuthorityCheck = false;
140139
}
141140
}
142141

143142
@Test
144-
public void perRpcAuthorityOverride_hostnameVerification_failure_rpcFails()
143+
public void perRpcAuthorityOverride_hostnameVerifier_badAuthority_fails()
145144
throws Exception {
146145
OkHttpClientTransport.enablePerRpcAuthorityCheck = true;
147146
try {
@@ -177,7 +176,7 @@ public void perRpcAuthorityOverride_hostnameVerification_failure_rpcFails()
177176
}
178177

179178
@Test
180-
public void perRpcAuthorityOverride_hostnameVerification_failure_flagDisabled_rpcSucceeds()
179+
public void perRpcAuthorityOverride_hostnameVerifier_badAuthority_flagDisabled_succeeds()
181180
throws Exception {
182181
ServerCredentials serverCreds;
183182
try (InputStream serverCert = TlsTesting.loadCert("server1.pem");
@@ -201,8 +200,7 @@ public void perRpcAuthorityOverride_hostnameVerification_failure_flagDisabled_rp
201200
}
202201

203202
@Test
204-
public void perRpcAuthorityOverride_noTlsCredentialsUsedToBuildChannel_disallowsRpc()
205-
throws Exception {
203+
public void perRpcAuthorityOverride_noTlsCredentialsUsedToBuildChannel_fails() throws Exception {
206204
OkHttpClientTransport.enablePerRpcAuthorityCheck = true;
207205
try {
208206
ServerCredentials serverCreds;
@@ -238,14 +236,8 @@ public void perRpcAuthorityOverride_noTlsCredentialsUsedToBuildChannel_disallows
238236
}
239237
}
240238

241-
/**
242-
* Test to verify that checkServerTrusted is been called for the per-rpc authority
243-
* verification. Could not verify this indirectly using an invalid authority in the test because
244-
* the SSLParameters.setEndpointIdentificationAlgorithm (an Android 24+ API) is not set to HTTPS
245-
* during the handshake and doesn't verify hostname during rpc call either.
246-
*/
247239
@Test
248-
public void perRpcAuthorityOverride_checkServerTrustedIsCalled() throws Exception {
240+
public void perRpcAuthorityOverride_trustManager_permitted_succeeds() throws Exception {
249241
OkHttpClientTransport.enablePerRpcAuthorityCheck = true;
250242
try {
251243
ServerCredentials serverCreds;
@@ -255,28 +247,27 @@ public void perRpcAuthorityOverride_checkServerTrustedIsCalled() throws Exceptio
255247
.keyManager(serverCert, serverPrivateKey)
256248
.build();
257249
}
258-
FakeX509ExtendedTrustManager fakeX509ExtendedTrustManager =
259-
getFakeX509ExtendedTrustManager();
260-
ChannelCredentials channelCreds = TlsChannelCredentials.newBuilder()
261-
.trustManager(fakeX509ExtendedTrustManager)
262-
.build();
250+
ChannelCredentials channelCreds;
251+
try (InputStream caCert = TlsTesting.loadCert("ca.pem")) {
252+
X509ExtendedTrustManager regularTrustManager =
253+
(X509ExtendedTrustManager) getX509ExtendedTrustManager(caCert).get();
254+
channelCreds = TlsChannelCredentials.newBuilder()
255+
.trustManager(new HostnameCheckingX509ExtendedTrustManager(regularTrustManager))
256+
.build();
257+
}
263258
Server server = grpcCleanupRule.register(server(serverCreds));
264259
ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds));
265260

266261
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
267-
CallOptions.DEFAULT.withAuthority("foo.test.google.fr"),
262+
CallOptions.DEFAULT.withAuthority("good.test.google.fr"),
268263
SimpleRequest.getDefaultInstance());
269-
assertThat(fakeX509ExtendedTrustManager.checkServerTrustedCalled).isTrue();
270264
} finally {
271265
OkHttpClientTransport.enablePerRpcAuthorityCheck = false;
272266
}
273267
}
274268

275-
/**
276-
* Uses a fake Trust Manager to fail authority verification.
277-
*/
278269
@Test
279-
public void perRpcAuthorityOverride_peerVerificationFails_rpcFails() throws Exception {
270+
public void perRpcAuthorityOverride_trustManager_denied_fails() throws Exception {
280271
OkHttpClientTransport.enablePerRpcAuthorityCheck = true;
281272
try {
282273
ServerCredentials serverCreds;
@@ -297,13 +288,9 @@ public void perRpcAuthorityOverride_peerVerificationFails_rpcFails() throws Exce
297288
Server server = grpcCleanupRule.register(server(serverCreds));
298289
ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds));
299290

300-
// Regular RPC succeeds
301-
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
302-
CallOptions.DEFAULT, SimpleRequest.getDefaultInstance());
303291
try {
304-
// But with an authority it fails
305292
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
306-
CallOptions.DEFAULT.withAuthority("moo.test.google.fr"),
293+
CallOptions.DEFAULT.withAuthority("bad.test.google.fr"),
307294
SimpleRequest.getDefaultInstance());
308295
fail("Expected exception for authority verification failure.");
309296
} catch (StatusRuntimeException ex) {
@@ -316,7 +303,7 @@ public void perRpcAuthorityOverride_peerVerificationFails_rpcFails() throws Exce
316303
}
317304

318305
@Test
319-
public void perRpcAuthorityOverride_peerVerificationFails_featureDisabled_rpcSucceeds()
306+
public void perRpcAuthorityOverride_trustManager_denied_flagDisabled_succeeds()
320307
throws Exception {
321308
ServerCredentials serverCreds;
322309
try (InputStream serverCert = TlsTesting.loadCert("server1.pem");
@@ -337,17 +324,18 @@ public void perRpcAuthorityOverride_peerVerificationFails_featureDisabled_rpcSuc
337324
ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds));
338325

339326
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
340-
CallOptions.DEFAULT.withAuthority("foo.test.google.fr"),
327+
CallOptions.DEFAULT.withAuthority("bad.test.google.fr"),
341328
SimpleRequest.getDefaultInstance());
342329
}
343330

344331
/**
345332
* This test simulates the absence of X509ExtendedTrustManager while still using the
346333
* real trust manager for the connection handshake to happen. When the TrustManager is not an
347-
* X509ExtendedTrustManager, the per-rpc authority check is skipped.
334+
* X509ExtendedTrustManager, the per-rpc check ignores the trust manager. However, the
335+
* HostnameVerifier is still used, so only valid authorities are permitted.
348336
*/
349337
@Test
350-
public void perRpcAuthorityOverride_tlsCreds_notX509ExtendedTrustManager_authorityNotChecked()
338+
public void perRpcAuthorityOverride_notX509ExtendedTrustManager_goodAuthority_succeeds()
351339
throws Exception {
352340
OkHttpClientTransport.enablePerRpcAuthorityCheck = true;
353341
try {
@@ -370,16 +358,55 @@ public void perRpcAuthorityOverride_tlsCreds_notX509ExtendedTrustManager_authori
370358
ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds));
371359

372360
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
373-
CallOptions.DEFAULT.withAuthority("moo.test.google.fr"),
361+
CallOptions.DEFAULT.withAuthority("foo.test.google.fr"),
374362
SimpleRequest.getDefaultInstance());
375363
} finally {
376364
OkHttpClientTransport.enablePerRpcAuthorityCheck = false;
377365
}
378366
}
379367

380368
@Test
381-
public void perRpcAuthorityOverride_tlsCreds_noX509ExtendedTrustManager_flagDisabled()
369+
public void perRpcAuthorityOverride_notX509ExtendedTrustManager_badAuthority_fails()
382370
throws Exception {
371+
OkHttpClientTransport.enablePerRpcAuthorityCheck = true;
372+
try {
373+
ServerCredentials serverCreds;
374+
try (InputStream serverCert = TlsTesting.loadCert("server1.pem");
375+
InputStream serverPrivateKey = TlsTesting.loadCert("server1.key")) {
376+
serverCreds = TlsServerCredentials.newBuilder()
377+
.keyManager(serverCert, serverPrivateKey)
378+
.build();
379+
}
380+
ChannelCredentials channelCreds;
381+
try (InputStream caCert = TlsTesting.loadCert("ca.pem")) {
382+
X509TrustManager x509ExtendedTrustManager =
383+
(X509TrustManager) getX509ExtendedTrustManager(caCert).get();
384+
channelCreds = TlsChannelCredentials.newBuilder()
385+
.trustManager(new FakeTrustManager(x509ExtendedTrustManager))
386+
.build();
387+
}
388+
Server server = grpcCleanupRule.register(server(serverCreds));
389+
ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds));
390+
391+
try {
392+
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
393+
CallOptions.DEFAULT.withAuthority("disallowed.name.com"),
394+
SimpleRequest.getDefaultInstance());
395+
fail("Expected exception for authority verification failure.");
396+
} catch (StatusRuntimeException ex) {
397+
assertThat(ex.getStatus().getCode()).isEqualTo(Status.Code.UNAVAILABLE);
398+
assertThat(ex.getStatus().getDescription())
399+
.isEqualTo("HostNameVerifier verification failed for authority 'disallowed.name.com'");
400+
}
401+
} finally {
402+
OkHttpClientTransport.enablePerRpcAuthorityCheck = false;
403+
}
404+
}
405+
406+
@Test
407+
public void
408+
perRpcAuthorityOverride_notX509ExtendedTrustManager_badAuthority_flagDisabled_succeeds()
409+
throws Exception {
383410
ServerCredentials serverCreds;
384411
try (InputStream serverCert = TlsTesting.loadCert("server1.pem");
385412
InputStream serverPrivateKey = TlsTesting.loadCert("server1.key")) {
@@ -399,7 +426,7 @@ public void perRpcAuthorityOverride_tlsCreds_noX509ExtendedTrustManager_flagDisa
399426
ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds));
400427

401428
ClientCalls.blockingUnaryCall(channel, SimpleServiceGrpc.getUnaryRpcMethod(),
402-
CallOptions.DEFAULT.withAuthority("foo.test.google.fr"),
429+
CallOptions.DEFAULT.withAuthority("disallowed.name.com"),
403430
SimpleRequest.getDefaultInstance());
404431
}
405432

@@ -620,15 +647,11 @@ public X509Certificate[] getAcceptedIssuers() {
620647
}
621648
}
622649

623-
private FakeX509ExtendedTrustManager getFakeX509ExtendedTrustManager()
624-
throws GeneralSecurityException, IOException {
625-
try (InputStream caCert = TlsTesting.loadCert("ca.pem")) {
626-
X509ExtendedTrustManager x509ExtendedTrustManager =
627-
(X509ExtendedTrustManager) getX509ExtendedTrustManager(caCert).get();
628-
return new FakeX509ExtendedTrustManager(x509ExtendedTrustManager);
629-
}
630-
}
631-
650+
/**
651+
* Checks against a limited set of hostnames. In production, EndpointIdentificationAlgorithm is
652+
* unset so the default trust manager will not fail based on the hostname. This class is used to
653+
* test user-provided trust managers that may have their own behavior.
654+
*/
632655
private static class HostnameCheckingX509ExtendedTrustManager
633656
extends ForwardingX509ExtendedTrustManager {
634657
public HostnameCheckingX509ExtendedTrustManager(X509ExtendedTrustManager tm) {
@@ -639,28 +662,13 @@ public HostnameCheckingX509ExtendedTrustManager(X509ExtendedTrustManager tm) {
639662
public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
640663
throws CertificateException {
641664
String peer = ((SSLSocket) socket).getHandshakeSession().getPeerHost();
642-
if (!TestUtils.TEST_SERVER_HOST.equals(peer)) {
665+
if (!"foo.test.google.fr".equals(peer) && !"good.test.google.fr".equals(peer)) {
643666
throw new CertificateException("Peer verification failed.");
644667
}
645668
super.checkServerTrusted(chain, authType, socket);
646669
}
647670
}
648671

649-
private static class FakeX509ExtendedTrustManager extends ForwardingX509ExtendedTrustManager {
650-
private boolean checkServerTrustedCalled;
651-
652-
private FakeX509ExtendedTrustManager(X509ExtendedTrustManager delegate) {
653-
super(delegate);
654-
}
655-
656-
@Override
657-
public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
658-
throws CertificateException {
659-
this.checkServerTrustedCalled = true;
660-
super.checkServerTrusted(chain, authType, socket);
661-
}
662-
}
663-
664672
@IgnoreJRERequirement
665673
private static class ForwardingX509ExtendedTrustManager extends X509ExtendedTrustManager {
666674
private final X509ExtendedTrustManager delegate;

0 commit comments

Comments
 (0)