Skip to content

Commit

Permalink
Added flag with default false for the per-rpc authority check and rem…
Browse files Browse the repository at this point in the history
…oved setting sslEndpointAlgorithm.
  • Loading branch information
kannanjgithub committed Dec 19, 2024
1 parent 30b1e14 commit f996474
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 114 deletions.
114 changes: 66 additions & 48 deletions okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,12 @@ class OkHttpClientTransport implements ConnectionClientTransport, TransportExcep
OutboundFlowController.Transport {
private static final Map<ErrorCode, Status> ERROR_CODE_TO_STATUS = buildErrorCodeToStatusMap();
private static final Logger log = Logger.getLogger(OkHttpClientTransport.class.getName());
private static final String GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK =
"GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK";
private final ChannelCredentials channelCredentials;
private Socket sock;
private SSLSession sslSession;
private final Logger logger = Logger.getLogger(OkHttpClientTransport.class.getName());

private static Map<ErrorCode, Status> buildErrorCodeToStatusMap() {
Map<ErrorCode, Status> errorToStatus = new EnumMap<>(ErrorCode.class);
Expand Down Expand Up @@ -262,14 +265,14 @@ protected void handleNotInUse() {
SettableFuture<Void> connectedFuture;

public OkHttpClientTransport(
OkHttpTransportFactory transportFactory,
InetSocketAddress address,
String authority,
@Nullable String userAgent,
Attributes eagAttrs,
@Nullable HttpConnectProxiedSocketAddress proxiedAddr,
Runnable tooManyPingsRunnable,
ChannelCredentials channelCredentials) {
OkHttpTransportFactory transportFactory,
InetSocketAddress address,
String authority,
@Nullable String userAgent,
Attributes eagAttrs,
@Nullable HttpConnectProxiedSocketAddress proxiedAddr,
Runnable tooManyPingsRunnable,
ChannelCredentials channelCredentials) {
this(
transportFactory,
address,
Expand All @@ -284,16 +287,16 @@ public OkHttpClientTransport(
}

private OkHttpClientTransport(
OkHttpTransportFactory transportFactory,
InetSocketAddress address,
String authority,
@Nullable String userAgent,
Attributes eagAttrs,
Supplier<Stopwatch> stopwatchFactory,
Variant variant,
@Nullable HttpConnectProxiedSocketAddress proxiedAddr,
Runnable tooManyPingsRunnable,
ChannelCredentials channelCredentials) {
OkHttpTransportFactory transportFactory,
InetSocketAddress address,
String authority,
@Nullable String userAgent,
Attributes eagAttrs,
Supplier<Stopwatch> stopwatchFactory,
Variant variant,
@Nullable HttpConnectProxiedSocketAddress proxiedAddr,
Runnable tooManyPingsRunnable,
ChannelCredentials channelCredentials) {
this.address = Preconditions.checkNotNull(address, "address");
this.defaultAuthority = authority;
this.maxMessageSize = transportFactory.maxMessageSize;
Expand Down Expand Up @@ -433,48 +436,65 @@ public ClientStream newStream(
if (hostnameVerifier != null && socket instanceof SSLSocket
&& !hostnameVerifier.verify(callOptions.getAuthority(),
((SSLSocket) socket).getSession())) {
return new FailingClientStream(Status.UNAVAILABLE.withDescription(
String.format("HostNameVerifier verification failed for authority '%s'",
callOptions.getAuthority())), tracers);
if (GrpcUtil.getFlag(GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK, false)) {
return new FailingClientStream(Status.UNAVAILABLE.withDescription(
String.format("HostNameVerifier verification failed for authority '%s'",
callOptions.getAuthority())), tracers);
}
logger.warning(String.format("HostNameVerifier verification failed for authority '%s'.",
callOptions.getAuthority()));
}
if (socket instanceof SSLSocket && callOptions.getAuthority() != null
&& channelCredentials != null && channelCredentials instanceof TlsChannelCredentials) {
Status peerVerificationStatus;
Status peerVerificationStatus = null;
if (peerVerificationResults.containsKey(callOptions.getAuthority())) {
peerVerificationStatus = peerVerificationResults.get(callOptions.getAuthority());
} else {
TrustManager x509ExtendedTrustManager;
TrustManager x509ExtendedTrustManager = null;
boolean warningLogged = false;
try {
x509ExtendedTrustManager = getX509ExtendedTrustManager(
(TlsChannelCredentials) channelCredentials);
} catch (GeneralSecurityException e) {
return new FailingClientStream(Status.UNAVAILABLE.withDescription(
"Failure getting X509ExtendedTrustManager from TlsCredentials").withCause(e),
tracers);
if (GrpcUtil.getFlag(GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK, false)) {
return new FailingClientStream(Status.UNAVAILABLE.withDescription(
"Failure getting X509ExtendedTrustManager from TlsCredentials").withCause(e),
tracers);
}
logger.warning(String.format("Failure getting X509ExtendedTrustManager from "
+ "TlsCredentials due to: %s", e.getMessage()));
warningLogged = true;
}
if (x509ExtendedTrustManager == null) {
return new FailingClientStream(Status.UNAVAILABLE.withDescription(
"Can't allow authority override in rpc when X509ExtendedTrustManager is not "
+ "available"), tracers);
}
try {
Certificate[] peerCertificates = sslSession.getPeerCertificates();
X509Certificate[] x509PeerCertificates = new X509Certificate[peerCertificates.length];
for (int i = 0; i < peerCertificates.length; i++) {
x509PeerCertificates[i] = (X509Certificate) peerCertificates[i];
if (GrpcUtil.getFlag(GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK, false)) {
return new FailingClientStream(Status.UNAVAILABLE.withDescription(
"Can't allow authority override in rpc when X509ExtendedTrustManager is not "
+ "available"), tracers);
}
if (!warningLogged) {
logger.warning("Authority override set for rpc when X509ExtendedTrustManager is not "
+ "available.");
}
} else {
try {
Certificate[] peerCertificates = sslSession.getPeerCertificates();
X509Certificate[] x509PeerCertificates = new X509Certificate[peerCertificates.length];
for (int i = 0; i < peerCertificates.length; i++) {
x509PeerCertificates[i] = (X509Certificate) peerCertificates[i];
}
((X509ExtendedTrustManager) x509ExtendedTrustManager).checkServerTrusted(
x509PeerCertificates, "RSA",
new SslSocketWrapper((SSLSocket) socket, callOptions.getAuthority()));
peerVerificationStatus = Status.OK;
} catch (SSLPeerUnverifiedException | CertificateException e) {
peerVerificationStatus = Status.UNAVAILABLE.withDescription(
String.format("Failure in verifying authority '%s' against peer during rpc",
callOptions.getAuthority())).withCause(e);
}
((X509ExtendedTrustManager) x509ExtendedTrustManager).checkServerTrusted(
x509PeerCertificates, "RSA",
new SslSocketWrapper((SSLSocket) socket, callOptions.getAuthority()));
peerVerificationStatus = Status.OK;
} catch (SSLPeerUnverifiedException | CertificateException e) {
peerVerificationStatus = Status.UNAVAILABLE.withDescription(
String.format("Failure in verifying authority '%s' against peer during rpc",
callOptions.getAuthority())).withCause(e);
peerVerificationResults.put(callOptions.getAuthority(), peerVerificationStatus);
}
peerVerificationResults.put(callOptions.getAuthority(), peerVerificationStatus);
}
if (!peerVerificationStatus.isOk()) {
if (peerVerificationStatus != null && !peerVerificationStatus.isOk()) {
return new FailingClientStream(peerVerificationStatus, tracers);
}
}
Expand Down Expand Up @@ -1588,9 +1608,7 @@ public boolean isConnected() {

@Override
public SSLParameters getSSLParameters() {
SSLParameters sslParameters = sslSocket.getSSLParameters();
sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
return sslParameters;
return sslSocket.getSSLParameters();
}
}

Expand Down
30 changes: 24 additions & 6 deletions okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -817,18 +817,36 @@ public void perRpcAuthoritySpecified_hostnameVerification_SslSocket_successCase(
@Test
public void perRpcAuthoritySpecified_hostnameVerification_SslSocket_failureCase()
throws Exception {
System.setProperty("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK", "true");
try {
startTransport(
DEFAULT_START_STREAM_ID, null, true, null,
(hostname, session) -> false, true);
ClientStream clientStream =
clientTransport.newStream(method, new Metadata(),
CallOptions.DEFAULT.withAuthority("some-authority"), tracers);
assertThat(clientStream).isInstanceOf(FailingClientStream.class);
InsightBuilder insightBuilder = new InsightBuilder();
clientStream.appendTimeoutInsight(insightBuilder);
assertThat(insightBuilder.toString()).contains("error=Status{code=UNAVAILABLE, "
+ "description=HostNameVerifier verification failed for authority 'some-authority', "
+ "cause=null}");
shutdownAndVerify();
} finally {
System.clearProperty("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK");
}
}

@Test
public void perRpcAuthoritySpecified_hostnameVerification_SslSocket_flagDisabled()
throws Exception {
startTransport(
DEFAULT_START_STREAM_ID, null, true, null,
(hostname, session) -> false, true);
ClientStream clientStream =
clientTransport.newStream(method, new Metadata(),
CallOptions.DEFAULT.withAuthority("some-authority"), tracers);
assertThat(clientStream).isInstanceOf(FailingClientStream.class);
InsightBuilder insightBuilder = new InsightBuilder();
clientStream.appendTimeoutInsight(insightBuilder);
assertThat(insightBuilder.toString()).contains("error=Status{code=UNAVAILABLE, "
+ "description=HostNameVerifier verification failed for authority 'some-authority', "
+ "cause=null}");
assertThat(clientStream).isInstanceOf(OkHttpClientStream.class);
shutdownAndVerify();
}

Expand Down
Loading

0 comments on commit f996474

Please sign in to comment.