Skip to content

Commit 14f3c7c

Browse files
committed
xds: honor requested_server_name from TLS SNI
Read requested_server_name from the TLS SNI on ExtendedSSLSession so RBAC policies can match the value Envoy config provides. Add a regression test covering a deny policy that depends on the requested server name.
1 parent cc841ee commit 14f3c7c

2 files changed

Lines changed: 40 additions & 2 deletions

File tree

xds/src/main/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngine.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@
4141
import java.util.logging.Level;
4242
import java.util.logging.Logger;
4343
import javax.annotation.Nullable;
44+
import javax.net.ssl.ExtendedSSLSession;
4445
import javax.net.ssl.SSLPeerUnverifiedException;
4546
import javax.net.ssl.SSLSession;
47+
import javax.net.ssl.SNIHostName;
48+
import javax.net.ssl.SNIServerName;
4649

4750
/**
4851
* Implementation of gRPC server access control based on envoy RBAC protocol:
@@ -411,6 +414,20 @@ private int getDestinationPort() {
411414
}
412415

413416
private String getRequestedServerName() {
417+
SSLSession sslSession = serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_SSL_SESSION);
418+
if (!(sslSession instanceof ExtendedSSLSession)) {
419+
return "";
420+
}
421+
List<SNIServerName> requestedServerNames =
422+
((ExtendedSSLSession) sslSession).getRequestedServerNames();
423+
if (requestedServerNames == null) {
424+
return "";
425+
}
426+
for (SNIServerName requestedServerName : requestedServerNames) {
427+
if (requestedServerName instanceof SNIHostName) {
428+
return ((SNIHostName) requestedServerName).getAsciiName();
429+
}
430+
}
414431
return "";
415432
}
416433
}

xds/src/test/java/io/grpc/xds/internal/rbac/engine/GrpcAuthorizationEngineTest.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@
5555
import java.util.Arrays;
5656
import java.util.Collections;
5757
import java.util.List;
58+
import javax.net.ssl.ExtendedSSLSession;
5859
import javax.net.ssl.SSLPeerUnverifiedException;
59-
import javax.net.ssl.SSLSession;
60+
import javax.net.ssl.SNIHostName;
61+
import javax.net.ssl.SNIServerName;
6062
import javax.security.auth.x500.X500Principal;
6163
import org.junit.Before;
6264
import org.junit.Rule;
@@ -85,12 +87,13 @@ public class GrpcAuthorizationEngineTest {
8587
@Mock
8688
private ServerCall<Void,Void> serverCall;
8789
@Mock
88-
private SSLSession sslSession;
90+
private ExtendedSSLSession sslSession;
8991

9092
@Before
9193
public void setUp() throws Exception {
9294
X509Certificate[] certs = {TestUtils.loadX509Cert("server1.pem")};
9395
when(sslSession.getPeerCertificates()).thenReturn(certs);
96+
when(sslSession.getRequestedServerNames()).thenReturn(Collections.<SNIServerName>emptyList());
9497
Attributes attributes = Attributes.newBuilder()
9598
.set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, new InetSocketAddress(IP_ADDR2, PORT))
9699
.set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, new InetSocketAddress(IP_ADDR1, PORT))
@@ -354,6 +357,24 @@ public void multiplePolicies() throws Exception {
354357
assertThat(decision.matchingPolicyName()).isEqualTo(POLICY_NAME);
355358
}
356359

360+
@Test
361+
public void requestedServerNameMatcher_matchesTlsSni() {
362+
when(sslSession.getRequestedServerNames()).thenReturn(
363+
Collections.<SNIServerName>singletonList(new SNIHostName("blocked.example")));
364+
GrpcAuthorizationEngine.RequestedServerNameMatcher requestedServerNameMatcher =
365+
GrpcAuthorizationEngine.RequestedServerNameMatcher.create(
366+
StringMatcher.forExact("blocked.example", false));
367+
OrMatcher permission = OrMatcher.create(requestedServerNameMatcher);
368+
OrMatcher principal = OrMatcher.create(AlwaysTrueMatcher.INSTANCE);
369+
PolicyMatcher policyMatcher = PolicyMatcher.create("deny-sni", permission, principal);
370+
371+
GrpcAuthorizationEngine engine = new GrpcAuthorizationEngine(
372+
AuthConfig.create(Collections.singletonList(policyMatcher), Action.DENY));
373+
AuthDecision decision = engine.evaluate(new Metadata(), serverCall);
374+
assertThat(decision.decision()).isEqualTo(Action.DENY);
375+
assertThat(decision.matchingPolicyName()).isEqualTo("deny-sni");
376+
}
377+
357378
@Test
358379
public void matchersEqualHashcode() throws Exception {
359380
PathMatcher pathMatcher = PathMatcher.create(STRING_MATCHER);

0 commit comments

Comments
 (0)