This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 0993bd5723e [fix](auth)Fixed the issue of not adding escape characters
in the regular code, which allowed usernames to use colons (#49459)
0993bd5723e is described below
commit 0993bd5723e86849654f04730df94bf0d5f62281
Author: zhangdong <[email protected]>
AuthorDate: Wed Apr 2 17:29:01 2025 +0800
[fix](auth)Fixed the issue of not adding escape characters in the regular
code, which allowed usernames to use colons (#49459)
### What problem does this PR solve?
Due to incorrect regularization, users are able to create a user named
default_cluster: xxx. When replaying logs, compatibility operations will
automatically remove the default_cluster prefix, which may cause users
to duplicate
It doesn't affect whether escape characters are added or not, except for
USER_NAME_REGEX, because in other regularization, the position of -
doesn't have a special meaning. But for better understanding, all
regular - characters are uniformly prefixed with escape characters,
Issue Number: close #xxx
Related PR: #xxx
Problem Summary:
Fixed the issue of not adding escape characters in the regular code,
which allowed usernames to use colons
### Release note
Fixed the issue of not adding escape characters in the regular code,
which allowed usernames to use colons
---
.../java/org/apache/doris/common/FeNameFormat.java | 30 +-
.../org/apache/doris/common/FeNameFormatTest.java | 330 ++++++++++++++++++---
2 files changed, 307 insertions(+), 53 deletions(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
b/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
index 854ec73eabe..4a174913a72 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
@@ -29,24 +29,24 @@ import org.apache.doris.qe.VariableMgr;
import com.google.common.base.Strings;
public class FeNameFormat {
- private static final String LABEL_REGEX = "^[-_A-Za-z0-9:]{1," +
Config.label_regex_length + "}$";
+ private static final String LABEL_REGEX = "^[\\-_A-Za-z0-9:]{1," +
Config.label_regex_length + "}$";
// if modify the matching length of a regular expression,
// please modify error msg when FeNameFormat.checkCommonName throw
exception in CreateRoutineLoadStmt
- private static final String COMMON_NAME_REGEX =
"^[a-zA-Z][a-zA-Z0-9-_]{0,63}$";
- private static final String UNDERSCORE_COMMON_NAME_REGEX =
"^[_a-zA-Z][a-zA-Z0-9-_]{0,63}$";
- private static final String TABLE_NAME_REGEX = "^[a-zA-Z][a-zA-Z0-9-_]*$";
- private static final String USER_NAME_REGEX = "^[a-zA-Z][a-zA-Z0-9.-_]*$";
- private static final String REPOSITORY_NAME_REGEX =
"^[a-zA-Z][a-zA-Z0-9-_]{0,255}$";
- private static final String COLUMN_NAME_REGEX =
"^[.a-zA-Z0-9_+-/?@#$%^&*\"\\s,:]{1,256}$";
-
- private static final String UNICODE_LABEL_REGEX =
"^[-_A-Za-z0-9:\\p{L}]{1," + Config.label_regex_length + "}$";
- private static final String UNICODE_COMMON_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9-_\\p{L}]{0,63}$";
- private static final String UNICODE_UNDERSCORE_COMMON_NAME_REGEX =
"^[_a-zA-Z\\p{L}][a-zA-Z0-9-_\\p{L}]{0,63}$";
- private static final String UNICODE_TABLE_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9-_\\p{L}]*$";
- private static final String UNICODE_USER_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9.-_\\p{L}]*$";
+ private static final String COMMON_NAME_REGEX =
"^[a-zA-Z][a-zA-Z0-9\\-_]{0,63}$";
+ private static final String UNDERSCORE_COMMON_NAME_REGEX =
"^[_a-zA-Z][a-zA-Z0-9\\-_]{0,63}$";
+ private static final String TABLE_NAME_REGEX =
"^[a-zA-Z][a-zA-Z0-9\\-_]*$";
+ private static final String USER_NAME_REGEX =
"^[a-zA-Z][a-zA-Z0-9.\\-_]*$";
+ private static final String REPOSITORY_NAME_REGEX =
"^[a-zA-Z][a-zA-Z0-9\\-_]{0,255}$";
+ private static final String COLUMN_NAME_REGEX =
"^[.a-zA-Z0-9_+\\-/?@#$%^&*\"\\s,:]{1,256}$";
+
+ private static final String UNICODE_LABEL_REGEX =
"^[\\-_A-Za-z0-9:\\p{L}]{1," + Config.label_regex_length + "}$";
+ private static final String UNICODE_COMMON_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9\\-_\\p{L}]{0,63}$";
+ private static final String UNICODE_UNDERSCORE_COMMON_NAME_REGEX =
"^[_a-zA-Z\\p{L}][a-zA-Z0-9\\-_\\p{L}]{0,63}$";
+ private static final String UNICODE_TABLE_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9\\-_\\p{L}]*$";
+ private static final String UNICODE_USER_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9.\\-_\\p{L}]*$";
private static final String UNICODE_COLUMN_NAME_REGEX
- = "^[.a-zA-Z0-9_+-/?@#$%^&*\"\\s,:\\p{L}]{1,256}$";
- private static final String UNICODE_REPOSITORY_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9-_\\p{L}]{0,255}$";
+ = "^[.a-zA-Z0-9_+\\-/?@#$%^&*\"\\s,:\\p{L}]{1,256}$";
+ private static final String UNICODE_REPOSITORY_NAME_REGEX =
"^[a-zA-Z\\p{L}][a-zA-Z0-9\\-_\\p{L}]{0,255}$";
public static final String FORBIDDEN_PARTITION_NAME = "placeholder_";
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java
b/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java
index 32e2a553b94..e4a3b9c9f3c 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java
@@ -23,26 +23,103 @@ import com.google.common.collect.Lists;
import org.apache.ivy.util.StringUtils;
import org.junit.jupiter.api.Test;
+import java.util.Arrays;
import java.util.List;
public class FeNameFormatTest {
@Test
void testLabelName() {
- // check label use correct regex, begin with '-' is different from
others
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkLabel("-lable"));
+ List<String> alwaysValid = Lists.newArrayList(
+ "abc123", // alphanumeric
+ "A-B_C:D", // contains all allowed special chars
+ "0-1_2:3", // starts with number, contains special chars
+ "a", // single character
+ "X-Y-Z", // hyphens and uppercase
+ "test_123:456", // mixed with underscore and colon
+ "-valid", // starts with hyphen
+ "_valid", // starts with underscore
+ ":valid", // starts with colon
+ StringUtils.repeat("a", Config.label_regex_length) // maximum
length
+ );
+
+ List<String> alwaysInvalid = Lists.newArrayList(
+ "", // empty string
+ " ", // space character
+ "a b", // contains space
+ "a.b", // contains dot
+ "a@b", // contains @
+ "a\nb", // contains newline
+ "a$b", // contains $
+ "a*b", // contains *
+ "a#b", // contains #
+ StringUtils.repeat("a", Config.label_regex_length + 1) //
maximum length
+ );
+
+ List<String> unicodeValid = Lists.newArrayList(
+ "äöü", // German umlauts
+ "北京", // Chinese characters
+ "東京123", // Japanese with numbers
+ "München", // German city name
+ "Beyoncé", // French name
+ "αβγ", // Greek letters
+ "русский", // Russian letters
+ "naïve", // French word
+ "Ḥello", // special diacritic
+ "øre", // Nordic word
+ "café", // French word
+ "ẞig" // German sharp S
+ );
+
+ test(FeNameFormat::checkLabel, alwaysValid, alwaysInvalid,
unicodeValid);
}
@Test
void testTableName() {
- // length 64
- String tblName =
"test_sys_partition_list_basic_test_list_partition_bigint_tb-uniq";
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkTableName(tblName));
- // length 70
- String largeTblName =
"test_sys_partition_list_basic_test_list_partition_bigint_tb_uniq_large";
- ExceptionChecker.expectThrows(AnalysisException.class, () ->
FeNameFormat.checkTableName(largeTblName));
- // check table name use correct regex, not begin with '-'
- ExceptionChecker.expectThrows(AnalysisException.class, () ->
FeNameFormat.checkTableName("-" + tblName));
+ List<String> alwaysValid = Lists.newArrayList(
+ "abc123", // Starts with ASCII letter, contains
alphanumerics + underscores
+ "A_1_b", // Contains allowed symbols (underscore)
+ "Z", // Single ASCII letter
+ "a1b2c3", // Alphanumeric combination
+ "x_y_z", // Contains underscores
+ "test", // Letters only
+ "a_b_c", // Multiple underscores
+ "a_1", // Underscore + number
+ "B2" // Uppercase letter + number
+ );
+
+ List<String> alwaysInvalid = Lists.newArrayList(
+ "1abc", // Starts with digit
+ "@test", // Contains invalid symbol @
+ "", // Empty string
+ "a b", // Contains space
+ "abc!", // Contains invalid symbol !
+ "a\nb", // Contains newline
+ "abc$", // Contains invalid symbol $
+ "-abc", // Starts with hyphen
+ "_abc", // Starts with underscore
+ "a*b", // Contains asterisk
+ "a.b", // Contains dot
+ "a#b" // Contains hash
+ );
+
+ List<String> unicodeValid = Lists.newArrayList(
+ "éclair", // Contains French letter
+ "über", // Contains German umlaut
+ "北京", // Chinese characters
+ "東京123", // Japanese characters + numbers
+ "München", // Contains umlaut
+ "Beyoncé", // Contains French accent
+ "αβγ", // Greek letters
+ "русский", // Cyrillic letters
+ "øre", // Nordic letter
+ "ção", // Portuguese letter
+ "naïve", // Contains diacritic
+ "Ḥello", // Contains special diacritic
+ "ẞig" // German sharp S
+ );
+
+ test(FeNameFormat::checkTableName, alwaysValid, alwaysInvalid,
unicodeValid);
}
@Test
@@ -92,22 +169,223 @@ public class FeNameFormatTest {
"げんご"
);
+ test(FeNameFormat::checkColumnName, alwaysValid, alwaysInvalid,
unicodeValid);
+ }
+
+ @Test
+ void testUserName() {
+ List<String> alwaysValid = Arrays.asList(
+ "a",
+ "abc123",
+ "A-1_b.c",
+ "x.y-z_123",
+ "test",
+ "a.b-c_d",
+ "Z",
+ "a-",
+ "a_",
+ "a."
+ );
+ List<String> alwaysInvalid = Arrays.asList(
+ "1abc", // starts with digit
+ "@test", // contains invalid character @
+ "a b", // contains space
+ "", // empty string
+ "-abc", // starts with hyphen
+ ".abc", // starts with dot
+ "_abc", // starts with underscore
+ "abc!", // contains invalid character !
+ "abc\n", // contains newline
+ "9", // digit only
+ " ", // whitespace only
+ "a\tb", // contains tab
+ "a\nb", // contains newline
+ "a*", // contains asterisk
+ "a(", // contains parenthesis
+ "a:b", // contains colon
+ " ab" // contains space
+ );
+ List<String> unicodeValid = Lists.newArrayList(
+ "éclair", // starts with accented letter
+ "über", // starts with umlaut
+ "北京abc", // starts with Chinese characters
+ "東京123", // starts with Japanese kanji
+ "русский", // starts with Cyrillic letters
+ "αβγ.123", // starts with Greek letters
+ "München", // contains umlaut
+ "Beyoncé", // contains accented letter
+ "naïve" // contains diacritic
+ );
+ test(FeNameFormat::checkUserName, alwaysValid, alwaysInvalid,
unicodeValid);
+ }
+
+ @Test
+ void testCommonName() {
+ List<String> alwaysValid = Arrays.asList(
+ "abc123", // ASCII letters + numbers
+ "A-1_b", // with allowed symbols (-_)
+ "Z", // single ASCII letter
+ "a1b2c3", // alphanumeric
+ "x_y-z", // underscore and hyphen
+ "test", // letters only
+ "a-b-c", // multiple hyphens
+ "a_b", // underscore
+ "a-1", // hyphen + number
+ "B2" // uppercase + number
+ );
+ List<String> alwaysInvalid = Arrays.asList(
+ "1abc", // starts with number
+ "@test", // contains invalid symbol @
+ "", // empty string
+ "a b", // contains space
+ "abc!", // contains invalid symbol !
+ "a\nb", // contains newline
+ "abc$", // contains invalid symbol $
+ "-abc", // starts with hyphen
+ "_abc", // starts with underscore
+ StringUtils.repeat("a", 65), // exceeds length limit (64)
+ "a*b", // contains asterisk
+ "a.b", // contains dot (if not allowed)
+ "a#b" // contains hash symbol
+ );
+ List<String> unicodeValid = Lists.newArrayList(
+ "éclair", // French letters
+ "über", // German umlaut
+ "北京", // Chinese characters
+ "東京123", // Japanese + numbers
+ "München", // German umlaut
+ "Beyoncé", // French accent
+ "αβγ", // Greek letters
+ "русский", // Cyrillic letters
+ "øre", // Nordic letter
+ "ção", // Portuguese letter
+ "naïve", // French diacritic
+ "Ḥello", // special diacritic
+ "ẞig" // German sharp S
+ );
+ test(FeNameFormatTest::checkCommonName, alwaysValid, alwaysInvalid,
unicodeValid);
+ }
+
+ @Test
+ void testOutfileName() {
+ List<String> alwaysValid = Arrays.asList(
+ "_valid", // starts with underscore
+ "a1_b-c", // letters, numbers, hyphens, underscores
+ "ValidName", // standard camel case
+ "x_123", // underscore + numbers
+ "A_B_C", // multiple underscores
+ "z", // single letter
+ "_9value", // starts with _, contains number
+ "a-b", // simple hyphenated
+ "MAX_LENGTH" // uppercase with underscores
+ );
+ List<String> alwaysInvalid = Arrays.asList(
+ "1invalid", // starts with number
+ "@test", // invalid starting character
+ "", // empty string
+ "has space", // contains space
+ "a.b", // contains dot
+ "a*b", // contains asterisk
+ "a\nb", // contains newline
+ "-invalid", // starts with hyphen
+ "a#b", // contains hash
+ StringUtils.repeat("a", 65), // exceeds length limit (64)
+ "a>b", // contains angle bracket
+ "a$b" // contains dollar sign
+ );
+ List<String> unicodeValid = Lists.newArrayList(
+ "_éclair", // starts with _, contains French letter
+ "über", // German umlaut
+ "_北京", // starts with _, Chinese characters
+ "東京123", // Japanese + numbers
+ "München", // German umlaut
+ "Beyoncé", // French accent
+ "αβγ", // Greek letters
+ "_русский", // starts with _, Cyrillic letters
+ "naïve", // French diacritic
+ "Ḥello", // special diacritic
+ "ẞig", // German sharp S
+ "øre", // Nordic letter
+ "_ção" // starts with _, Portuguese letter
+ );
+ test(FeNameFormatTest::checkOutfileSuccessFileName, alwaysValid,
alwaysInvalid, unicodeValid);
+ }
+
+ @Test
+ void checkRepositoryName() {
+ List<String> alwaysValid = Arrays.asList(
+ "validName", // Standard ASCII letters
+ "A1_b2", // Letters, numbers, underscore
+ "Product123", // CamelCase with numbers
+ "x_y_z", // Multiple underscores
+ "test", // Lowercase only
+ "MAX_LENGTH", // Uppercase with underscores
+ "a1-b2", // Hyphen included
+ "Z", // Single character
+ StringUtils.repeat("a", 256) // Maximum length (255 chars)
+ );
+ List<String> alwaysInvalid = Arrays.asList(
+ "", // Empty string
+ " ", // Space character
+ "1stInvalid", // Starts with number
+ "@username", // Invalid starting character
+ "name with space", // Contains space
+ "a.b", // Contains dot
+ "a*b", // Contains asterisk
+ "a\nb", // Contains newline
+ "a$b", // Contains dollar sign
+ "a#b", // Contains hash
+ StringUtils.repeat("a", 257), // Exceeds length limit (255)
+ "-invalid" // Starts with hyphen
+ );
+ List<String> unicodeValid = Lists.newArrayList(
+ "München", // German umlaut
+ "Beyoncé", // French accent
+ "東京太郎", // Japanese characters
+ "北京123", // Chinese with numbers
+ "αβγ", // Greek letters
+ "русский", // Cyrillic letters
+ "naïve", // French diacritic
+ "øre", // Nordic letter
+ "café", // French word
+ "Ḥello", // Special diacritic
+ "ẞig", // German sharp S
+ "SãoPaulo" // Portuguese
+ );
+ test(FeNameFormat::checkRepositoryName, alwaysValid, alwaysInvalid,
unicodeValid);
+ }
+
+ private static void checkOutfileSuccessFileName(String name) throws
AnalysisException {
+ FeNameFormat.checkOutfileSuccessFileName("fakeType", name);
+ }
+
+ private static void checkCommonName(String name) throws AnalysisException {
+ FeNameFormat.checkCommonName("fakeType", name);
+ }
+
+ @FunctionalInterface
+ public interface NameValidator {
+ void accept(String name) throws AnalysisException;
+ }
+
+ private void test(NameValidator validator, List<String> alwaysValid,
List<String> alwaysInvalid,
+ List<String> unicodeValid) {
boolean defaultUnicode =
VariableMgr.getDefaultSessionVariable().enableUnicodeNameSupport;
List<Boolean> enableUnicode = Lists.newArrayList(false, true);
try {
for (Boolean unicode : enableUnicode) {
VariableMgr.getDefaultSessionVariable().setEnableUnicodeNameSupport(unicode);
for (String s : alwaysValid) {
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkColumnName(s));
+ ExceptionChecker.expectThrowsNoException(() ->
validator.accept(s));
}
for (String s : alwaysInvalid) {
- ExceptionChecker.expectThrows(AnalysisException.class, ()
-> FeNameFormat.checkColumnName(s));
+ ExceptionChecker.expectThrows(AnalysisException.class, ()
-> validator.accept(s));
}
for (String s : unicodeValid) {
if (unicode) {
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkColumnName(s));
+ ExceptionChecker.expectThrowsNoException(() ->
validator.accept(s));
} else {
- ExceptionChecker.expectThrows(AnalysisException.class,
() -> FeNameFormat.checkColumnName(s));
+ ExceptionChecker.expectThrows(AnalysisException.class,
() -> validator.accept(s));
}
}
}
@@ -115,28 +393,4 @@ public class FeNameFormatTest {
VariableMgr.getDefaultSessionVariable().setEnableUnicodeNameSupport(defaultUnicode);
}
}
-
- @Test
- void testUserName() {
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkUserName("a.b"));
- // check user name use correct regex, not begin with '.'
- ExceptionChecker.expectThrows(AnalysisException.class, () ->
FeNameFormat.checkUserName(".a.b"));
- }
-
- @Test
- void testCommonName() {
- String commonName =
"test_sys_partition_list_basic_test_list_partition_bigint_tb-uniq";
-
- // check common name use correct regex, length 65
- ExceptionChecker.expectThrows(AnalysisException.class, () ->
FeNameFormat.checkCommonName("fakeType", commonName + "t"));
- ExceptionChecker.expectThrows(AnalysisException.class, () ->
FeNameFormat.checkCommonName("fakeType", "_commonName"));
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkCommonName("fakeType", "common-Name"));
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkCommonName("fakeType", "commonName-"));
- }
-
- @Test
- void testOutfileName() {
- // check success file name prefix
- ExceptionChecker.expectThrowsNoException(() ->
FeNameFormat.checkOutfileSuccessFileName("fakeType", "_success"));
- }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]