Skip to content

Commit 9dbf83a

Browse files
committed
Bring up to date with latest XFCC implementation
1 parent 10fa8cc commit 9dbf83a

File tree

5 files changed

+75
-15
lines changed

5 files changed

+75
-15
lines changed

grpc-contrib/src/main/java/com/salesforce/grpc/contrib/xfcc/XForwardedClientCert.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import io.grpc.Context;
1111

1212
import java.util.ArrayList;
13+
import java.util.Collection;
14+
import java.util.Collections;
1315
import java.util.List;
1416

1517
/**
@@ -24,7 +26,8 @@ public class XForwardedClientCert {
2426

2527
private String by = "";
2628
private String hash = "";
27-
private String san = "";
29+
private String sanUri = "";
30+
private List<String> sanDns = new ArrayList<>();
2831
private String subject = "";
2932

3033
void setBy(String by) {
@@ -35,14 +38,18 @@ void setHash(String hash) {
3538
this.hash = hash;
3639
}
3740

38-
void setSan(String san) {
39-
this.san = san;
41+
void setSanUri(String sanUri) {
42+
this.sanUri = sanUri;
4043
}
4144

4245
void setSubject(String subject) {
4346
this.subject = subject;
4447
}
4548

49+
void addSanDns(String sanDns) {
50+
this.sanDns.add(sanDns);
51+
}
52+
4653
/**
4754
* @return The Subject Alternative Name (SAN) of the current proxy’s certificate.
4855
*/
@@ -51,17 +58,24 @@ public String getBy() {
5158
}
5259

5360
/**
54-
* @return The SHA 256 diguest of the current client certificate.
61+
* @return The SHA 256 digest of the current client certificate.
5562
*/
5663
public String getHash() {
5764
return hash;
5865
}
5966

6067
/**
61-
* @return The SAN field (URI type) of the current client certificate.
68+
* @return The URI type Subject Alternative Name field of the current client certificate.
69+
*/
70+
public String getSanUri() {
71+
return sanUri;
72+
}
73+
74+
/**
75+
* @return The DNS type Subject Alternative Name field(s) of the current client certificate.
6276
*/
63-
public String getSan() {
64-
return san;
77+
public Collection<String> getSanDns() {
78+
return Collections.unmodifiableCollection(sanDns);
6579
}
6680

6781
/**
@@ -80,8 +94,8 @@ public String toString() {
8094
if (!hash.isEmpty()) {
8195
kvp.add("Hash=" + enquote(hash));
8296
}
83-
if (!san.isEmpty()) {
84-
kvp.add("SAN=" + enquote(san));
97+
if (!sanUri.isEmpty()) {
98+
kvp.add("URI=" + enquote(sanUri));
8599
}
86100
if (!subject.isEmpty()) {
87101
kvp.add("Subject=" + enquote(subject));

grpc-contrib/src/main/java/com/salesforce/grpc/contrib/xfcc/XfccParser.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ static List<XForwardedClientCert> parse(String header) {
3737
if (l.get(0).toLowerCase().equals("hash")) {
3838
cert.setHash(dequote(l.get(1)));
3939
}
40-
if (l.get(0).toLowerCase().equals("san")) {
41-
cert.setSan(dequote(l.get(1)));
40+
// Use "SAN:" instead of "URI:" for backward compatibility with previous mesh proxy releases.
41+
if (l.get(0).toLowerCase().equals("san") || l.get(0).toLowerCase().equals("uri")) {
42+
cert.setSanUri(dequote(l.get(1)));
43+
}
44+
if (l.get(0).toLowerCase().equals("dns")) {
45+
cert.addSanDns(dequote(l.get(1)));
4246
}
4347
if (l.get(0).toLowerCase().equals("subject")) {
4448
cert.setSubject(dequote(l.get(1)));

grpc-contrib/src/main/java/com/salesforce/grpc/contrib/xfcc/XfccServerInterceptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/**
1616
* {@code XfccServerInterceptor} parses the {@code x-forwarded-client-cert} (XFCC) header populated by TLS-terminating
17-
* reverse proxies. For example, Istio and Linkerd. If present, the parsed XFCC header is appended to the
17+
* reverse proxies. For example: Envoy, Istio, and Linkerd. If present, the parsed XFCC header is appended to the
1818
* gRPC {@code Context}.
1919
*
2020
* @see <a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/http_conn_man/headers.html#config-http-conn-man-headers-x-forwarded-client-cert">Envoy XFCC Header</a>

grpc-contrib/src/test/java/com/salesforce/grpc/contrib/xfcc/XfccMarshallerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public void parseSimpleHeaderWorks() {
2525
assertThat(certs.size()).isEqualTo(1);
2626
assertThat(certs.get(0).getBy()).isEqualTo("http://frontend.lyft.com");
2727
assertThat(certs.get(0).getHash()).isEqualTo("468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688");
28-
assertThat(certs.get(0).getSan()).isEqualTo("http://testclient.lyft.com");
28+
assertThat(certs.get(0).getSanUri()).isEqualTo("http://testclient.lyft.com");
2929
assertThat(certs.get(0).getSubject()).isEmpty();
3030
}
3131
@Test

grpc-contrib/src/test/java/com/salesforce/grpc/contrib/xfcc/XfccParserTest.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,59 @@
1616

1717
public class XfccParserTest {
1818
@Test
19-
public void parseSimpleHeaderWorks() {
19+
public void parseLegacySanHeaderWorks() {
2020
String header = "By=http://frontend.lyft.com;Hash=468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688;" +
2121
"SAN=http://testclient.lyft.com";
2222
List<XForwardedClientCert> certs = XfccParser.parse(header);
2323

2424
assertThat(certs.size()).isEqualTo(1);
2525
assertThat(certs.get(0).getBy()).isEqualTo("http://frontend.lyft.com");
2626
assertThat(certs.get(0).getHash()).isEqualTo("468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688");
27-
assertThat(certs.get(0).getSan()).isEqualTo("http://testclient.lyft.com");
27+
assertThat(certs.get(0).getSanUri()).isEqualTo("http://testclient.lyft.com");
2828
assertThat(certs.get(0).getSubject()).isEmpty();
29+
assertThat(certs.get(0).getSanDns()).isEmpty();
2930
}
31+
32+
@Test
33+
public void parseSimpleHeaderWorks() {
34+
String header = "Hash=ebb216c5155a5fd8c8f082a07362b3c7b1a8ee2f98c20f6142b49fe5c2db90bd;DNS=test-tls-in;DNS=second-san;" +
35+
"DNS=third-san;Subject=\"OU=0:test-tls-in,CN=localhost\"";
36+
List<XForwardedClientCert> certs = XfccParser.parse(header);
37+
38+
assertThat(certs.size()).isEqualTo(1);
39+
assertThat(certs.get(0).getBy()).isEmpty();
40+
assertThat(certs.get(0).getHash()).isEqualTo("ebb216c5155a5fd8c8f082a07362b3c7b1a8ee2f98c20f6142b49fe5c2db90bd");
41+
assertThat(certs.get(0).getSanUri()).isEmpty();
42+
assertThat(certs.get(0).getSubject()).isEqualTo("OU=0:test-tls-in,CN=localhost");
43+
assertThat(certs.get(0).getSanDns()).containsExactly("test-tls-in", "second-san", "third-san");
44+
}
45+
46+
@Test
47+
public void parseUriSanHeaderWorks() {
48+
String header = "By=http://frontend.lyft.com;Hash=468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688;Subject=\"/C=US/ST=CA/L=San Francisco/OU=Lyft/CN=Test Client\";URI=http://testclient.lyft.com";
49+
List<XForwardedClientCert> certs = XfccParser.parse(header);
50+
51+
assertThat(certs.size()).isEqualTo(1);
52+
assertThat(certs.get(0).getBy()).isEqualTo("http://frontend.lyft.com");
53+
assertThat(certs.get(0).getHash()).isEqualTo("468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688");
54+
assertThat(certs.get(0).getSanUri()).isEqualTo("http://testclient.lyft.com");
55+
assertThat(certs.get(0).getSubject()).isEqualTo("/C=US/ST=CA/L=San Francisco/OU=Lyft/CN=Test Client");
56+
assertThat(certs.get(0).getSanDns()).isEmpty();
57+
}
58+
59+
@Test
60+
public void parseUriAndDnsSanHeaderWorks() {
61+
String header = "By=http://frontend.lyft.com;Hash=468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688;Subject=\"/C=US/ST=CA/L=San Francisco/OU=Lyft/CN=Test Client\";URI=http://testclient.lyft.com;DNS=lyft.com;DNS=www.lyft.com";
62+
List<XForwardedClientCert> certs = XfccParser.parse(header);
63+
64+
assertThat(certs.size()).isEqualTo(1);
65+
assertThat(certs.get(0).getBy()).isEqualTo("http://frontend.lyft.com");
66+
assertThat(certs.get(0).getHash()).isEqualTo("468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688");
67+
assertThat(certs.get(0).getSanUri()).isEqualTo("http://testclient.lyft.com");
68+
assertThat(certs.get(0).getSubject()).isEqualTo("/C=US/ST=CA/L=San Francisco/OU=Lyft/CN=Test Client");
69+
assertThat(certs.get(0).getSanDns()).containsExactly("lyft.com", "www.lyft.com");
70+
}
71+
3072
@Test
3173
public void parseCompoundHeaderWorks() {
3274
String header = "By=http://frontend.lyft.com;Hash=468ed33be74eee6556d90c0149c1309e9ba61d6425303443c0748a02dd8de688;SAN=http://testclient.lyft.com," +

0 commit comments

Comments
 (0)