Skip to content

Commit 6449728

Browse files
committed
Address review comments.
1 parent 44f2412 commit 6449728

File tree

4 files changed

+54
-89
lines changed

4 files changed

+54
-89
lines changed

netty/src/main/java/io/grpc/netty/NettyClientTransport.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,11 @@
6060
import io.netty.util.concurrent.GenericFutureListener;
6161
import java.net.SocketAddress;
6262
import java.nio.channels.ClosedChannelException;
63+
import java.util.LinkedHashMap;
6364
import java.util.Map;
6465
import java.util.concurrent.Executor;
6566
import java.util.concurrent.TimeUnit;
67+
import java.util.logging.Level;
6668
import java.util.logging.Logger;
6769
import javax.annotation.Nullable;
6870

@@ -71,8 +73,6 @@
7173
*/
7274
class NettyClientTransport implements ConnectionClientTransport {
7375

74-
private static final boolean enablePerRpcAuthorityCheck =
75-
GrpcUtil.getFlag("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK", false);
7676
private final InternalLogId logId;
7777
private final Map<ChannelOption<?>, ?> channelOptions;
7878
private final SocketAddress remoteAddress;
@@ -108,6 +108,14 @@ class NettyClientTransport implements ConnectionClientTransport {
108108
private final ChannelLogger channelLogger;
109109
private final boolean useGetForSafeMethods;
110110
private final Ticker ticker;
111+
private final Logger logger = Logger.getLogger(NettyClientTransport.class.getName());
112+
private final LinkedHashMap<String, Status> peerVerificationResults =
113+
new LinkedHashMap<String, Status>() {
114+
@Override
115+
protected boolean removeEldestEntry(Map.Entry<String, Status> eldest) {
116+
return size() > 100;
117+
}
118+
};
111119

112120
NettyClientTransport(
113121
SocketAddress address,
@@ -198,9 +206,19 @@ public ClientStream newStream(
198206
return new FailingClientStream(statusExplainingWhyTheChannelIsNull, tracers);
199207
}
200208
if (callOptions.getAuthority() != null) {
201-
Status verificationStatus = negotiator.verifyAuthority(callOptions.getAuthority());
209+
Status verificationStatus = peerVerificationResults.get(callOptions.getAuthority());
210+
if (verificationStatus == null) {
211+
verificationStatus = negotiator.verifyAuthority(callOptions.getAuthority());
212+
if (!verificationStatus.isOk()) {
213+
logger.log(Level.WARNING, String.format("Peer hostname verification during rpc failed "
214+
+ "for authority '%s' for method '%s' with the error \"%s\". This will "
215+
+ "be an error in the future.", callOptions.getAuthority(),
216+
method.getFullMethodName(), verificationStatus.getDescription()),
217+
verificationStatus.getCause());
218+
}
219+
}
202220
if (!verificationStatus.isOk()) {
203-
if (enablePerRpcAuthorityCheck) {
221+
if (GrpcUtil.getFlag("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK", false)) {
204222
return new FailingClientStream(verificationStatus, tracers);
205223
}
206224
}

netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import com.google.common.annotations.VisibleForTesting;
2323
import com.google.common.base.Optional;
24-
import com.google.common.base.Preconditions;
2524
import com.google.errorprone.annotations.ForOverride;
2625
import io.grpc.Attributes;
2726
import io.grpc.CallCredentials;
@@ -84,16 +83,13 @@
8483
import java.security.cert.X509Certificate;
8584
import java.util.Arrays;
8685
import java.util.EnumSet;
87-
import java.util.LinkedHashMap;
8886
import java.util.List;
89-
import java.util.Map;
9087
import java.util.Set;
9188
import java.util.concurrent.Executor;
9289
import java.util.logging.Level;
9390
import java.util.logging.Logger;
9491
import javax.annotation.Nonnull;
9592
import javax.annotation.Nullable;
96-
import javax.annotation.concurrent.GuardedBy;
9793
import javax.net.ssl.SSLEngine;
9894
import javax.net.ssl.SSLException;
9995
import javax.net.ssl.SSLParameters;
@@ -589,31 +585,27 @@ protected void userEventTriggered0(ChannelHandlerContext ctx, Object evt) throws
589585
}
590586

591587
static final class ClientTlsProtocolNegotiator implements ProtocolNegotiator {
592-
private static final Logger logger = Logger.getLogger(ClientTlsProtocolNegotiator.class.getName());
588+
private static final Logger logger =
589+
Logger.getLogger(ClientTlsProtocolNegotiator.class.getName());
593590
private static final Method checkServerTrustedMethod;
591+
594592
static {
595593
Method method = null;
596594
try {
597-
Class<?> x509ExtendedTrustManagerClass = Class.forName("javax.net.ssl.X509ExtendedTrustManager");
595+
Class<?> x509ExtendedTrustManagerClass =
596+
Class.forName("javax.net.ssl.X509ExtendedTrustManager");
598597
method = x509ExtendedTrustManagerClass.getMethod("checkServerTrusted",
599598
X509Certificate[].class, String.class, SSLEngine.class);
600599
} catch (ClassNotFoundException e) {
600+
// Per-rpc authority overriding via call options will be disallowed.
601601
} catch (NoSuchMethodException e) {
602602
// Should never happen.
603-
logger.log(Level.WARNING, "Method checkServerTrusted not found in " +
604-
"javax.net.ssl.X509ExtendedTrustManager", e);
603+
logger.log(Level.WARNING, "Method checkServerTrusted not found in "
604+
+ "javax.net.ssl.X509ExtendedTrustManager", e);
605605
}
606606
checkServerTrustedMethod = method;
607607
}
608608

609-
@GuardedBy("this")
610-
private final LinkedHashMap<String, Status> peerVerificationResults =
611-
new LinkedHashMap<String, Status>() {
612-
@Override
613-
protected boolean removeEldestEntry(Map.Entry<String, Status> eldest) {
614-
return size() > 100;
615-
}
616-
};
617609
private SSLEngine sslEngine;
618610

619611
public ClientTlsProtocolNegotiator(SslContext sslContext,
@@ -656,32 +648,25 @@ public void close() {
656648
}
657649

658650
@Override
659-
public synchronized Status verifyAuthority(@Nonnull String authority) {
651+
public Status verifyAuthority(@Nonnull String authority) {
660652
// sslEngine won't be set when creating ClientTlsHandler from InternalProtocolNegotiators
661653
// for example.
662654
if (sslEngine == null || x509ExtendedTrustManager == null) {
663655
return Status.FAILED_PRECONDITION.withDescription(
664656
"Can't allow authority override in rpc when SslEngine or X509ExtendedTrustManager"
665657
+ " is not available");
666658
}
667-
if (peerVerificationResults.containsKey(authority)) {
668-
return peerVerificationResults.get(authority);
669-
} else {
670-
Status peerVerificationStatus;
671-
try {
672-
verifyAuthorityAllowedForPeerCert(authority);
673-
peerVerificationStatus = Status.OK;
674-
} catch (SSLPeerUnverifiedException | CertificateException | InvocationTargetException |
675-
IllegalAccessException | IllegalStateException e) {
676-
peerVerificationStatus = Status.UNAVAILABLE.withDescription(
677-
String.format("Peer hostname verification during rpc failed for authority '%s'",
678-
authority)).withCause(e);
679-
logger.log(Level.WARNING, "Authority verification failed (this will be an error in the "
680-
+ "future).", e);
681-
}
682-
peerVerificationResults.put(authority, peerVerificationStatus);
683-
return peerVerificationStatus;
659+
Status peerVerificationStatus;
660+
try {
661+
verifyAuthorityAllowedForPeerCert(authority);
662+
peerVerificationStatus = Status.OK;
663+
} catch (SSLPeerUnverifiedException | CertificateException | InvocationTargetException
664+
| IllegalAccessException | IllegalStateException e) {
665+
peerVerificationStatus = Status.UNAVAILABLE.withDescription(
666+
String.format("Peer hostname verification during rpc failed for authority '%s'",
667+
authority)).withCause(e);
684668
}
669+
return peerVerificationStatus;
685670
}
686671

687672
public void setSslEngine(SSLEngine sslEngine) {
@@ -692,7 +677,8 @@ private void verifyAuthorityAllowedForPeerCert(String authority)
692677
throws SSLPeerUnverifiedException, CertificateException, InvocationTargetException,
693678
IllegalAccessException {
694679
if (checkServerTrustedMethod == null) {
695-
throw new IllegalStateException("Method checkServerTrusted not found in javax.net.ssl.X509ExtendedTrustManager");
680+
throw new IllegalStateException("Method checkServerTrusted not found in "
681+
+ "javax.net.ssl.X509ExtendedTrustManager");
696682
}
697683
SSLEngine sslEngineWrapper = new SslEngineWrapper(sslEngine, authority);
698684
// The typecasting of Certificate to X509Certificate should work because this method will only
@@ -702,7 +688,8 @@ private void verifyAuthorityAllowedForPeerCert(String authority)
702688
for (int i = 0; i < peerCertificates.length; i++) {
703689
x509PeerCertificates[i] = (X509Certificate) peerCertificates[i];
704690
}
705-
checkServerTrustedMethod.invoke(x509ExtendedTrustManager, x509PeerCertificates, "RSA", sslEngineWrapper);
691+
checkServerTrustedMethod.invoke(
692+
x509ExtendedTrustManager, x509PeerCertificates, "RSA", sslEngineWrapper);
706693
}
707694

708695
@VisibleForTesting

netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,8 @@ public void authorityOverrideInCallOptions_noX509ExtendedTrustManager_newStreamC
853853
try {
854854
startServer();
855855
InputStream caCert = TlsTesting.loadCert("ca.pem");
856-
X509TrustManager x509ExtendedTrustManager = (X509TrustManager) getX509ExtendedTrustManager(caCert);
856+
X509TrustManager x509ExtendedTrustManager =
857+
(X509TrustManager) getX509ExtendedTrustManager(caCert);
857858
ProtocolNegotiators.FromChannelCredentialsResult result =
858859
ProtocolNegotiators.from(TlsChannelCredentials.newBuilder()
859860
.trustManager(new FakeTrustManager(x509ExtendedTrustManager)).build());
@@ -874,8 +875,9 @@ Rpc.METHOD, new Metadata(), CallOptions.DEFAULT.withAuthority("foo.test.google.i
874875
InsightBuilder insightBuilder = new InsightBuilder();
875876
stream.appendTimeoutInsight(insightBuilder);
876877
assertThat(insightBuilder.toString()).contains(
877-
"Status{code=FAILED_PRECONDITION, description=Can't allow authority override in rpc when "
878-
+ "SslEngine or X509ExtendedTrustManager is not available, cause=null}");
878+
"Status{code=FAILED_PRECONDITION, description=Can't allow authority override in rpc "
879+
+ "when SslEngine or X509ExtendedTrustManager is not available, "
880+
+ "cause=null}");
879881
} finally {
880882
System.clearProperty("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK");
881883
}
@@ -904,9 +906,10 @@ Rpc.METHOD, new Metadata(), CallOptions.DEFAULT.withAuthority("foo.test.google.i
904906
InsightBuilder insightBuilder = new InsightBuilder();
905907
stream.appendTimeoutInsight(insightBuilder);
906908
assertThat(insightBuilder.toString()).contains(
907-
"Status{code=UNAVAILABLE, description=Peer hostname verification during rpc failed for"
908-
+ " authority 'foo.test.google.in'");
909-
assertThat(insightBuilder.toString()).contains("cause=java.security.cert.CertificateException:"
909+
"Status{code=UNAVAILABLE, description=Peer hostname verification during rpc failed "
910+
+ "for authority 'foo.test.google.in'");
911+
assertThat(insightBuilder.toString()).contains(
912+
"Caused by: java.security.cert.CertificateException:"
910913
+ " No subject alternative DNS name matching foo.test.google.in found.");
911914
} finally {
912915
System.clearProperty("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK");

netty/src/test/java/io/grpc/netty/ProtocolNegotiatorsTest.java

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@
2626
import static org.junit.Assert.assertNull;
2727
import static org.junit.Assert.assertTrue;
2828
import static org.mockito.ArgumentMatchers.any;
29-
import static org.mockito.ArgumentMatchers.eq;
3029
import static org.mockito.Mockito.mock;
3130
import static org.mockito.Mockito.timeout;
3231
import static org.mockito.Mockito.times;
3332
import static org.mockito.Mockito.verify;
34-
import static org.mockito.Mockito.when;
3533

3634
import com.google.common.base.Optional;
3735
import io.grpc.Attributes;
@@ -69,7 +67,6 @@
6967
import io.grpc.netty.ProtocolNegotiators.ClientTlsProtocolNegotiator;
7068
import io.grpc.netty.ProtocolNegotiators.HostPort;
7169
import io.grpc.netty.ProtocolNegotiators.ServerTlsHandler;
72-
import io.grpc.netty.ProtocolNegotiators.SslEngineWrapper;
7370
import io.grpc.netty.ProtocolNegotiators.WaitUntilActiveHandler;
7471
import io.grpc.testing.TlsTesting;
7572
import io.grpc.util.CertificateUtils;
@@ -122,7 +119,6 @@
122119
import java.security.KeyStore;
123120
import java.security.KeyStoreException;
124121
import java.security.NoSuchAlgorithmException;
125-
import java.security.cert.Certificate;
126122
import java.security.cert.CertificateException;
127123
import java.security.cert.X509Certificate;
128124
import java.util.ArrayDeque;
@@ -144,7 +140,6 @@
144140
import javax.net.ssl.SSLHandshakeException;
145141
import javax.net.ssl.SSLSession;
146142
import javax.net.ssl.TrustManagerFactory;
147-
import javax.net.ssl.X509ExtendedTrustManager;
148143
import org.junit.After;
149144
import org.junit.Before;
150145
import org.junit.BeforeClass;
@@ -1037,44 +1032,6 @@ private ClientTlsProtocolNegotiator getClientTlsProtocolNegotiator() throws SSLE
10371032
null, Optional.absent(), null);
10381033
}
10391034

1040-
@Test
1041-
public void allowedAuthoritiesForTransport_LruCache() throws SSLException, CertificateException {
1042-
X509ExtendedTrustManager mockX509ExtendedTrustManager = mock(X509ExtendedTrustManager.class);
1043-
ClientTlsProtocolNegotiator negotiator = new ClientTlsProtocolNegotiator(
1044-
GrpcSslContexts.forClient().trustManager(
1045-
TlsTesting.loadCert("ca.pem")).build(),
1046-
null, Optional.absent(), mockX509ExtendedTrustManager);
1047-
SSLEngine mockSslEngine = mock(SSLEngine.class);
1048-
negotiator.setSslEngine(mockSslEngine);
1049-
SSLSession mockSslSession = mock(SSLSession.class);
1050-
when(mockSslEngine.getSession()).thenReturn(mockSslSession);
1051-
when(mockSslSession.getPeerCertificates()).thenReturn(new Certificate[0]);
1052-
1053-
// Fill the cache
1054-
for (int i = 0; i < 100; i++) {
1055-
Status unused = negotiator.verifyAuthority("authority" + i);
1056-
}
1057-
// Should use value from the cache.
1058-
Status unused = negotiator.verifyAuthority("authority0");
1059-
// Should evict authority0.
1060-
unused = negotiator.verifyAuthority("authority100");
1061-
// Should call TrustManager as the cached value has been evicted for this authority value.
1062-
unused = negotiator.verifyAuthority("authority0");
1063-
1064-
ArgumentCaptor<SslEngineWrapper> sslEngineWrapperArgumentCaptor =
1065-
ArgumentCaptor.forClass(SslEngineWrapper.class);
1066-
verify(mockX509ExtendedTrustManager, times(102)).checkServerTrusted(any(), eq("RSA"),
1067-
sslEngineWrapperArgumentCaptor.capture());
1068-
List<SslEngineWrapper> sslEngineWrappersCaptured =
1069-
sslEngineWrapperArgumentCaptor.getAllValues();
1070-
assertThat(sslEngineWrappersCaptured).hasSize(102);
1071-
for (int i = 0; i < 100; i++) {
1072-
assertThat(sslEngineWrappersCaptured.get(i).getPeerHost()).isEqualTo("authority" + i);
1073-
}
1074-
assertThat(sslEngineWrappersCaptured.get(100).getPeerHost()).isEqualTo("authority100");
1075-
assertThat(sslEngineWrappersCaptured.get(101).getPeerHost()).isEqualTo("authority0");
1076-
}
1077-
10781035
@Test
10791036
public void engineLog() {
10801037
ChannelHandler handler = new ServerTlsHandler(grpcHandler, sslContext, null);

0 commit comments

Comments
 (0)