|
37 | 37 | import static org.junit.Assert.assertTrue; |
38 | 38 | import static org.junit.Assert.fail; |
39 | 39 | import static org.mockito.ArgumentMatchers.any; |
40 | | -import static org.mockito.Mockito.mock; |
41 | 40 | import static org.mockito.Mockito.timeout; |
42 | | -import static org.mockito.Mockito.times; |
43 | 41 | import static org.mockito.Mockito.verify; |
44 | 42 | import static org.mockito.Mockito.when; |
45 | 43 |
|
|
139 | 137 | import org.junit.Test; |
140 | 138 | import org.junit.runner.RunWith; |
141 | 139 | import org.junit.runners.JUnit4; |
142 | | -import org.mockito.AdditionalAnswers; |
143 | | -import org.mockito.ArgumentCaptor; |
144 | 140 | import org.mockito.Mock; |
145 | 141 | import org.mockito.junit.MockitoJUnit; |
146 | 142 | import org.mockito.junit.MockitoRule; |
@@ -955,47 +951,58 @@ public void authorityOverrideInCallOptions_matchesServerPeerHost_newStreamCreati |
955 | 951 | } |
956 | 952 | } |
957 | 953 |
|
| 954 | + // Without removing the port number part that {@link X509AuthorityVerifier} does, there will be a |
| 955 | + // java.security.cert.CertificateException: Illegal given domain name: foo.test.google.fr:12345 |
958 | 956 | @Test |
959 | | - public void authorityOverrideInCallOptions_lruCache() |
960 | | - throws IOException, InterruptedException, GeneralSecurityException, ExecutionException, |
961 | | - TimeoutException { |
| 957 | + public void authorityOverrideInCallOptions_portNumberInAuthority_isStrippedForPeerVerification() |
| 958 | + throws IOException, InterruptedException, GeneralSecurityException, ExecutionException, |
| 959 | + TimeoutException { |
962 | 960 | NettyClientHandler.enablePerRpcAuthorityCheck = true; |
963 | 961 | try { |
964 | 962 | startServer(); |
965 | | - ProtocolNegotiator mockNegotiator = |
966 | | - mock(ProtocolNegotiator.class, AdditionalAnswers.delegatesTo(newNegotiator())); |
967 | | - NettyClientTransport transport = newTransport(mockNegotiator); |
| 963 | + NettyClientTransport transport = newTransport(newNegotiator()); |
968 | 964 | SettableFuture<Void> connected = SettableFuture.create(); |
969 | 965 | FakeClientTransportListener fakeClientTransportListener = |
970 | | - new FakeClientTransportListener(connected); |
| 966 | + new FakeClientTransportListener(connected); |
971 | 967 | callMeMaybe(transport.start(fakeClientTransportListener)); |
972 | 968 | connected.get(10, TimeUnit.SECONDS); |
973 | 969 | assertThat(fakeClientTransportListener.isConnected()).isTrue(); |
974 | 970 |
|
975 | | - ArgumentCaptor<String> authorityArgumentCaptor = ArgumentCaptor.forClass(String.class); |
976 | | - new Rpc(transport, new Metadata(), "foo-0.test.google.fr").halfClose() |
977 | | - .waitForResponse(); |
978 | | - // Should use cache. |
979 | | - new Rpc(transport, new Metadata(), "foo-0.test.google.fr").waitForResponse(); |
980 | | - for (int i = 1; i < 100; i++) { |
981 | | - // Should call verifyAuthority each time here and the cache grows with each call. |
982 | | - new Rpc(transport, new Metadata(), "foo-" + i + ".test.google.fr").halfClose() |
983 | | - .waitForResponse(); |
984 | | - } |
985 | | - // Cache is full at this point. Eviction occurs here for foo-0.test.google.fr. |
986 | | - new Rpc(transport, new Metadata(), "foo-100.test.google.fr").halfClose() |
987 | | - .waitForResponse(); |
988 | | - // verifyAuthority call happens for foo-0.test.google.fr. |
989 | | - new Rpc(transport, new Metadata(), "foo-0.test.google.fr").halfClose() |
990 | | - .waitForResponse(); |
991 | | - verify(mockNegotiator, times(102)).verifyAuthority( |
992 | | - authorityArgumentCaptor.capture()); |
993 | | - List<String> authorityValues = authorityArgumentCaptor.getAllValues(); |
994 | | - for (int i = 0; i < 100; i++) { |
995 | | - assertThat(authorityValues.get(i)).isEqualTo("foo-" + i + ".test.google.fr"); |
996 | | - } |
997 | | - assertThat(authorityValues.get(100)).isEqualTo("foo-100.test.google.fr"); |
998 | | - assertThat(authorityValues.get(101)).isEqualTo("foo-0.test.google.fr"); |
| 971 | + new Rpc(transport, new Metadata(), "foo.test.google.fr:12345").waitForResponse(); |
| 972 | + } finally { |
| 973 | + NettyClientHandler.enablePerRpcAuthorityCheck = false;; |
| 974 | + } |
| 975 | + } |
| 976 | + |
| 977 | + @Test |
| 978 | + public void authorityOverrideInCallOptions_portNumberAndIpv6_isStrippedForPeerVerification() |
| 979 | + throws IOException, InterruptedException, GeneralSecurityException, ExecutionException, |
| 980 | + TimeoutException { |
| 981 | + NettyClientHandler.enablePerRpcAuthorityCheck = true; |
| 982 | + try { |
| 983 | + startServer(); |
| 984 | + NettyClientTransport transport = newTransport(newNegotiator()); |
| 985 | + SettableFuture<Void> connected = SettableFuture.create(); |
| 986 | + FakeClientTransportListener fakeClientTransportListener = |
| 987 | + new FakeClientTransportListener(connected); |
| 988 | + callMeMaybe(transport.start(fakeClientTransportListener)); |
| 989 | + connected.get(10, TimeUnit.SECONDS); |
| 990 | + assertThat(fakeClientTransportListener.isConnected()).isTrue(); |
| 991 | + |
| 992 | + new Rpc(transport, new Metadata(), "[2001:db8:3333:4444:5555:6666:1.2.3.4]:12345") |
| 993 | + .waitForResponse(); |
| 994 | + } catch (ExecutionException ex) { |
| 995 | + Status status = ((StatusException) ex.getCause()).getStatus(); |
| 996 | + assertThat(status.getDescription()).isEqualTo("Peer hostname verification during rpc " |
| 997 | + + "failed for authority '[2001:db8:3333:4444:5555:6666:1.2.3.4]:12345'"); |
| 998 | + assertThat(status.getCode()).isEqualTo(Code.UNAVAILABLE); |
| 999 | + assertThat(((InvocationTargetException) ex.getCause().getCause()).getTargetException()) |
| 1000 | + .isInstanceOf(CertificateException.class); |
| 1001 | + // Port number is removed by {@link X509AuthorityVerifier}. |
| 1002 | + assertThat(((InvocationTargetException) ex.getCause().getCause()).getTargetException() |
| 1003 | + .getMessage()).isEqualTo( |
| 1004 | + "No subject alternative names matching IP address 2001:db8:3333:4444:5555:6666:1.2.3.4 " |
| 1005 | + + "found"); |
999 | 1006 | } finally { |
1000 | 1007 | NettyClientHandler.enablePerRpcAuthorityCheck = false;; |
1001 | 1008 | } |
@@ -1182,9 +1189,11 @@ private static class Rpc { |
1182 | 1189 |
|
1183 | 1190 | Rpc(NettyClientTransport transport, Metadata headers, String authorityOverride) { |
1184 | 1191 | stream = transport.newStream( |
1185 | | - METHOD, headers, authorityOverride != null |
1186 | | - ? CallOptions.DEFAULT.withAuthority(authorityOverride) : CallOptions.DEFAULT, |
| 1192 | + METHOD, headers, CallOptions.DEFAULT, |
1187 | 1193 | new ClientStreamTracer[]{ new ClientStreamTracer() {} }); |
| 1194 | + if (authorityOverride != null) { |
| 1195 | + stream.setAuthority(authorityOverride); |
| 1196 | + } |
1188 | 1197 | stream.start(listener); |
1189 | 1198 | stream.request(1); |
1190 | 1199 | stream.writeMessage(new ByteArrayInputStream(MESSAGE.getBytes(UTF_8))); |
|
0 commit comments