Skip to content

Commit 91e20cc

Browse files
authored
fix(spiffeid): make parsing case-insensitive and normalize trust domains (#416)
Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
1 parent 77bef7b commit 91e20cc

4 files changed

Lines changed: 39 additions & 16 deletions

File tree

java-spiffe-core/src/main/java/io/spiffe/spiffeid/SpiffeId.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,25 @@ public static SpiffeId parse(final String id) {
7272
throw new IllegalArgumentException(EMPTY);
7373
}
7474

75-
if (!id.startsWith(SCHEME_PREFIX)) {
75+
int schemeSeparatorIndex = id.indexOf("://");
76+
if (schemeSeparatorIndex <= 0) {
7677
throw new InvalidSpiffeIdException(WRONG_SCHEME);
7778
}
7879

79-
String rest = id.substring(SCHEME_PREFIX.length());
80+
String scheme = id.substring(0, schemeSeparatorIndex);
81+
if (!SPIFFE_SCHEME.equalsIgnoreCase(scheme)) {
82+
throw new InvalidSpiffeIdException(WRONG_SCHEME);
83+
}
84+
85+
String rest = id.substring(schemeSeparatorIndex + 3);
8086

8187
int i = 0;
8288
for (char c : rest.toCharArray()) {
8389
if (c == '/') {
8490
break;
8591
}
86-
if (!isValidTrustDomainChar(c)) {
92+
char normalized = Character.toLowerCase(c);
93+
if (!isValidTrustDomainChar(normalized)) {
8794
throw new InvalidSpiffeIdException(BAD_TRUST_DOMAIN_CHAR);
8895
}
8996
i++;
@@ -100,7 +107,8 @@ public static SpiffeId parse(final String id) {
100107
validatePath(path);
101108
}
102109

103-
return new SpiffeId(new TrustDomain(td), path);
110+
String normalizedTrustDomain = td.toLowerCase();
111+
return new SpiffeId(new TrustDomain(normalizedTrustDomain), path);
104112
}
105113

106114
/**

java-spiffe-core/src/main/java/io/spiffe/spiffeid/TrustDomain.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ public static TrustDomain parse(String idOrName) {
4141
return SpiffeId.parse(idOrName).getTrustDomain();
4242
}
4343

44-
validateTrustDomainName(idOrName);
45-
return new TrustDomain(idOrName);
44+
String normalizedName = idOrName.toLowerCase();
45+
validateTrustDomainName(normalizedName);
46+
return new TrustDomain(normalizedName);
4647
}
4748

4849
/**

java-spiffe-core/src/test/java/io/spiffe/spiffeid/SpiffeIdTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ static Stream<Arguments> provideTestValidSpiffeIds() {
6464
Arguments.of("spiffe://trustdomain/path", TrustDomain.parse("trustdomain"), "/path"),
6565
Arguments.of("spiffe://trustdomain/path1/path2", TrustDomain.parse("trustdomain"), "/path1/path2"),
6666
Arguments.of("spiffe://trustdomain/PATH1/PATH2", TrustDomain.parse("trustdomain"), "/PATH1/PATH2"),
67-
Arguments.of("spiffe://trustdomain/9eebccd2-12bf-40a6-b262-65fe0487d453", TrustDomain.parse("trustdomain"), "/9eebccd2-12bf-40a6-b262-65fe0487d453")
67+
Arguments.of("spiffe://trustdomain/9eebccd2-12bf-40a6-b262-65fe0487d453", TrustDomain.parse("trustdomain"), "/9eebccd2-12bf-40a6-b262-65fe0487d453"),
68+
Arguments.of("SPIFFE://trustdomain/path", TrustDomain.parse("trustdomain"), "/path"),
69+
Arguments.of("SpIfFe://TrUsTdOmAiN/Workload", TrustDomain.parse("trustdomain"), "/Workload")
6870
);
6971
}
7072

@@ -92,7 +94,7 @@ static Stream<Arguments> provideInvalidSpiffeIds() {
9294
Arguments.of("spiffe://user:password@test.org/path/element", "Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores"),
9395
Arguments.of("spiffe:path/element", "Scheme is missing or invalid"),
9496
Arguments.of("spiffe:/path/element", "Scheme is missing or invalid"),
95-
Arguments.of("SPIFFE://path/element", "Scheme is missing or invalid"),
97+
Arguments.of("spiffe://", "Trust domain is missing"),
9698
Arguments.of("spiffe://domain.test/path/elem%5uent", "Path segment characters are limited to letters, numbers, dots, dashes, and underscores"),
9799
Arguments.of("spiffe://trustdomain/path//", "Path cannot contain empty segments"),
98100
Arguments.of("spiffe://trustdomain/./other", "Path cannot contain dot segments"),
@@ -173,9 +175,10 @@ void testParseWithAllChars() {
173175

174176
String td = "spiffe://trustdomain" + c;
175177

176-
if (TD_CHARS.contains(c)) {
178+
char normalizedTdChar = Character.toLowerCase(c);
179+
if (TrustDomain.isValidTrustDomainChar(normalizedTdChar)) {
177180
SpiffeId spiffeId = SpiffeId.parse(td);
178-
assertEquals(spiffeId.toString(), td);
181+
assertEquals("spiffe://trustdomain" + normalizedTdChar, spiffeId.toString());
179182
} else {
180183
try {
181184
SpiffeId.parse(td);

java-spiffe-core/src/test/java/io/spiffe/spiffeid/TrustDomainTest.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import org.junit.jupiter.params.provider.MethodSource;
88

99
import java.util.stream.Stream;
10-
11-
import static io.spiffe.spiffeid.SpiffeIdTest.TD_CHARS;
1210
import static org.junit.jupiter.api.Assertions.assertEquals;
1311
import static org.junit.jupiter.api.Assertions.assertThrows;
1412
import static org.junit.jupiter.api.Assertions.fail;
@@ -22,6 +20,12 @@ void testTrustDomainFromName() {
2220
assertEquals("trustdomain", trustDomain.getName());
2321
}
2422

23+
@Test
24+
void testTrustDomainFromNameMixedCase_isNormalizedToLowercase() {
25+
TrustDomain trustDomain = TrustDomain.parse("TrUsTdOmAiN");
26+
assertEquals("trustdomain", trustDomain.getName());
27+
}
28+
2529
@Test
2630
void testFromIdStringWithoutPath() {
2731
TrustDomain trustDomain = TrustDomain.parse("spiffe://trustdomain");
@@ -41,9 +45,10 @@ void testAllChars() {
4145
char c = (char) i;
4246
String td = "trustdomain" + c;
4347

44-
if (TD_CHARS.contains(c)) {
48+
char normalizedTdChar = Character.toLowerCase(c);
49+
if (TrustDomain.isValidTrustDomainChar(normalizedTdChar)) {
4550
TrustDomain trustDomain = TrustDomain.parse(td);
46-
assertEquals(td, trustDomain.getName());
51+
assertEquals("trustdomain" + normalizedTdChar, trustDomain.getName());
4752
} else {
4853
try {
4954
TrustDomain.parse(td);
@@ -70,8 +75,8 @@ static Stream<Arguments> provideInvalidTrustDomain() {
7075
Arguments.of("", "Trust domain is missing"),
7176
Arguments.of("spiffe://", "Trust domain is missing"),
7277
Arguments.of(null, "idOrName must not be null"),
73-
Arguments.of("Trustdomain", "Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores"),
74-
Arguments.of("spiffe://Domain.test", "Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores"),
78+
Arguments.of("trustdomain!", "Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores"),
79+
Arguments.of("spiffe://domain!.test", "Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores"),
7580
Arguments.of("spiffe://domain.test/spiffe://domain.test/path/element", "Path segment characters are limited to letters, numbers, dots, dashes, and underscores"),
7681
Arguments.of("http://domain.test", "Scheme is missing or invalid"),
7782
Arguments.of("spiffe:// domain.test ", "Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores"),
@@ -112,6 +117,12 @@ void testParseFromSpiffeIdWithPath_extractsTrustDomain() {
112117
assertEquals("example.org", trustDomain.getName());
113118
}
114119

120+
@Test
121+
void testParseFromSpiffeIdWithPath_mixedCaseSchemeAndTrustDomain_normalizesTrustDomain() {
122+
TrustDomain trustDomain = TrustDomain.parse("SpIfFe://ExAmPlE.OrG/foo");
123+
assertEquals("example.org", trustDomain.getName());
124+
}
125+
115126
@Test
116127
void testParseInvalidScheme_spiffeWithSingleSlash_throwsInvalidScheme() {
117128
assertThrows(InvalidSpiffeIdException.class,

0 commit comments

Comments
 (0)