diff --git a/xds/src/main/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngine.java b/xds/src/main/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngine.java index 3b55b757222..0623a8a39a8 100644 --- a/xds/src/main/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngine.java +++ b/xds/src/main/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngine.java @@ -41,8 +41,11 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; +import javax.net.ssl.ExtendedSSLSession; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIServerName; /** * Implementation of gRPC server access control based on envoy RBAC protocol: @@ -411,6 +414,20 @@ private int getDestinationPort() { } private String getRequestedServerName() { + SSLSession sslSession = serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_SSL_SESSION); + if (!(sslSession instanceof ExtendedSSLSession)) { + return ""; + } + List requestedServerNames = + ((ExtendedSSLSession) sslSession).getRequestedServerNames(); + if (requestedServerNames == null) { + return ""; + } + for (SNIServerName requestedServerName : requestedServerNames) { + if (requestedServerName instanceof SNIHostName) { + return ((SNIHostName) requestedServerName).getAsciiName(); + } + } return ""; } } diff --git a/xds/src/test/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngineTest.java b/xds/src/test/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngineTest.java index 10287c11262..8ac2583b93e 100644 --- a/xds/src/test/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngineTest.java +++ b/xds/src/test/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngineTest.java @@ -55,8 +55,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import javax.net.ssl.ExtendedSSLSession; import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIServerName; import javax.security.auth.x500.X500Principal; import org.junit.Before; import org.junit.Rule; @@ -85,12 +87,13 @@ public class GrpcAuthorizationEngineTest { @Mock private ServerCall serverCall; @Mock - private SSLSession sslSession; + private ExtendedSSLSession sslSession; @Before public void setUp() throws Exception { X509Certificate[] certs = {TestUtils.loadX509Cert("server1.pem")}; when(sslSession.getPeerCertificates()).thenReturn(certs); + when(sslSession.getRequestedServerNames()).thenReturn(Collections.emptyList()); Attributes attributes = Attributes.newBuilder() .set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, new InetSocketAddress(IP_ADDR2, PORT)) .set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, new InetSocketAddress(IP_ADDR1, PORT)) @@ -354,6 +357,24 @@ public void multiplePolicies() throws Exception { assertThat(decision.matchingPolicyName()).isEqualTo(POLICY_NAME); } + @Test + public void requestedServerNameMatcher_matchesTlsSni() { + when(sslSession.getRequestedServerNames()).thenReturn( + Collections.singletonList(new SNIHostName("blocked.example"))); + GrpcAuthorizationEngine.RequestedServerNameMatcher requestedServerNameMatcher = + GrpcAuthorizationEngine.RequestedServerNameMatcher.create( + StringMatcher.forExact("blocked.example", false)); + OrMatcher permission = OrMatcher.create(requestedServerNameMatcher); + OrMatcher principal = OrMatcher.create(AlwaysTrueMatcher.INSTANCE); + PolicyMatcher policyMatcher = PolicyMatcher.create("deny-sni", permission, principal); + + GrpcAuthorizationEngine engine = new GrpcAuthorizationEngine( + AuthConfig.create(Collections.singletonList(policyMatcher), Action.DENY)); + AuthDecision decision = engine.evaluate(new Metadata(), serverCall); + assertThat(decision.decision()).isEqualTo(Action.DENY); + assertThat(decision.matchingPolicyName()).isEqualTo("deny-sni"); + } + @Test public void matchersEqualHashcode() throws Exception { PathMatcher pathMatcher = PathMatcher.create(STRING_MATCHER);