Skip to content

Commit 45319e8

Browse files
committed
Improve the key validation in secret indentifier.
1 parent 787fd2c commit 45319e8

File tree

3 files changed

+100
-6
lines changed

3 files changed

+100
-6
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.logstash.secret;
21+
22+
import com.google.common.annotations.VisibleForTesting;
23+
import org.apache.logging.log4j.util.Strings;
24+
25+
import java.util.Arrays;
26+
import java.util.List;
27+
import java.util.Objects;
28+
import java.util.regex.Pattern;
29+
import java.util.regex.Matcher;
30+
import java.util.stream.Collectors;
31+
32+
public class KeyValidator {
33+
34+
@VisibleForTesting
35+
protected static final List<String> RESTRICTED_SYMBOLS = Arrays.asList("?", "..", "/", "\\", "'", "\"", "$", "*", "|", "<", ">", " ");
36+
private static final Pattern RESTRICTED_PATTERN = buildPattern();
37+
38+
private static Pattern buildPattern() {
39+
String pattern = RESTRICTED_SYMBOLS.stream()
40+
.map(Pattern::quote)
41+
.collect(Collectors.joining("|"));
42+
return Pattern.compile(pattern);
43+
}
44+
45+
/**
46+
* Validates the key against the {@link KeyValidator#RESTRICTED_SYMBOLS} list.
47+
* Throws {@link IllegalArgumentException} if the key contains any of them.
48+
* @param key A key to be validated
49+
* @param keyName A key name mapped to the key
50+
*/
51+
public static void validateKey(final String key, final String keyName) {
52+
if (Strings.isBlank(key)) {
53+
throw new IllegalArgumentException(String.format("%s may not be null or blank", keyName));
54+
}
55+
56+
Matcher matcher = RESTRICTED_PATTERN.matcher(key);
57+
if (matcher.find()) {
58+
String foundSymbol = matcher.group();
59+
foundSymbol = Objects.equals(foundSymbol, " ") ? "whitespace" : foundSymbol;
60+
throw new IllegalArgumentException(String.format("%s can not contain %s", keyName, foundSymbol));
61+
}
62+
}
63+
}

logstash-core/src/main/java/org/logstash/secret/SecretIdentifier.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,13 @@ public static SecretIdentifier fromExternalForm(String urn) {
6060
/**
6161
* Minor validation and downcases the parts
6262
*
63-
* @param part The part of the URN to validate
63+
* @param key The key, a part of the URN to validate.
6464
* @param partName The name of the part used for logging.
6565
* @return The validated and transformed part.
6666
*/
67-
private static String validateWithTransform(String part, String partName) {
68-
if (part == null || part.isEmpty()) {
69-
throw new IllegalArgumentException(String.format("%s may not be null or empty", partName));
70-
}
71-
return part.toLowerCase(Locale.US);
67+
private static String validateWithTransform(String key, String partName) {
68+
KeyValidator.validateKey(key, partName);
69+
return key.toLowerCase(Locale.US);
7270
}
7371

7472
@Override
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.logstash.secret;
2+
3+
import org.junit.Test;
4+
import java.util.Objects;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
import static org.junit.Assert.assertThrows;
8+
9+
public class KeyValidatorTest {
10+
11+
@Test(expected = Test.None.class) // no exception expected
12+
public void testValidKeys() {
13+
KeyValidator.validateKey("validKey", "key");
14+
KeyValidator.validateKey("test123", "key");
15+
KeyValidator.validateKey("under_score", "key");
16+
KeyValidator.validateKey("hyphen-key", "key");
17+
KeyValidator.validateKey("uri:standard", "key");
18+
KeyValidator.validateKey("key-with.extension", "key");
19+
}
20+
21+
@Test
22+
public void validateKeyThrowsCorrectMessage() {
23+
KeyValidator.RESTRICTED_SYMBOLS.forEach(symbol -> {
24+
String key = "random" + symbol + "test";
25+
IllegalArgumentException exception = assertThrows(
26+
IllegalArgumentException.class,
27+
() -> KeyValidator.validateKey(key, "key")
28+
);
29+
final String verifyPart = Objects.equals(" ", symbol) ? "whitespace" : symbol;
30+
assertThat(exception.getMessage()).isEqualTo(String.format("key can not contain %s", verifyPart));
31+
});
32+
}
33+
}

0 commit comments

Comments
 (0)