enhance: add configuration to allow custom characters in names (#42417) (#44063)

related: #42417
    
- Add NameValidationAllowedChars and RoleNameValidationAllowedChars
  configuration parameters to specify additional characters allowed
  respectively in (generic) names and a role names
- All validations in validateName method is moved to a the new method
  validateNameWithCustomChars which is called by both validateName
  and ValidateRoleName while specifying characters allowed

Signed-off-by: Jean-Francois Weber-Marx <jfwm@hotmail.com>
Signed-off-by: Jean-Francois Weber-Marx <jf.webermarx@criteo.com>
This commit is contained in:
Jean-Francois Weber-Marx 2025-09-02 03:57:52 +00:00 committed by GitHub
parent 9e2d1963d4
commit 330a871979
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 80 additions and 37 deletions

View File

@ -316,6 +316,10 @@ proxy:
# please adjust in embedded Milvus: false # please adjust in embedded Milvus: false
ginLogging: true ginLogging: true
ginLogSkipPaths: / # skip url path for gin log ginLogSkipPaths: / # skip url path for gin log
nameValidation:
allowedChars: $ # Additional characters allowed in names beyond underscores, letters and numbers. To allow hyphens in names, add '-' here.
roleNameValidation:
allowedChars: $ # Additional characters allowed in role names beyond underscores, letters and numbers. Add '-' to allow hyphens in role names.
maxTaskNum: 1024 # The maximum number of tasks in the task queue of the proxy. maxTaskNum: 1024 # The maximum number of tasks in the task queue of the proxy.
ddlConcurrency: 16 # The concurrent execution number of DDL at proxy. ddlConcurrency: 16 # The concurrent execution number of DDL at proxy.
dclConcurrency: 16 # The concurrent execution number of DCL at proxy. dclConcurrency: 16 # The concurrent execution number of DCL at proxy.

View File

@ -1283,6 +1283,10 @@ func getMaxMvccTsFromChannels(channelsTs map[string]uint64, beginTs typeutil.Tim
} }
func validateName(entity string, nameType string) error { func validateName(entity string, nameType string) error {
return validateNameWithCustomChars(entity, nameType, Params.ProxyCfg.NameValidationAllowedChars.GetValue())
}
func validateNameWithCustomChars(entity string, nameType string, allowedChars string) error {
entity = strings.TrimSpace(entity) entity = strings.TrimSpace(entity)
if entity == "" { if entity == "" {
@ -1305,15 +1309,15 @@ func validateName(entity string, nameType string) error {
for i := 1; i < len(entity); i++ { for i := 1; i < len(entity); i++ {
c := entity[i] c := entity[i]
if c != '_' && c != '$' && !isAlpha(c) && !isNumber(c) { if c != '_' && !isAlpha(c) && !isNumber(c) && !strings.ContainsRune(allowedChars, rune(c)) {
return merr.WrapErrParameterInvalidMsg("%s can only contain numbers, letters, dollars and underscores, found %c at %d", nameType, c, i) return merr.WrapErrParameterInvalidMsg("%s can only contain numbers, letters, underscores, and allowed characters (%s), found %c at %d", nameType, allowedChars, c, i)
} }
} }
return nil return nil
} }
func ValidateRoleName(entity string) error { func ValidateRoleName(entity string) error {
return validateName(entity, "role name") return validateNameWithCustomChars(entity, "role name", Params.ProxyCfg.RoleNameValidationAllowedChars.GetValue())
} }
func IsDefaultRole(roleName string) bool { func IsDefaultRole(roleName string) bool {

View File

@ -708,6 +708,23 @@ func TestValidateName(t *testing.T) {
assert.Nil(t, ValidateObjectName("*")) assert.Nil(t, ValidateObjectName("*"))
} }
func TestValidateRoleName_HyphenToggle(t *testing.T) {
pt := paramtable.Get()
pt.ProxyCfg.RoleNameValidationAllowedChars.SwapTempValue("$-")
assert.Nil(t, ValidateRoleName("Admin-1"))
assert.Nil(t, ValidateRoleName("_a-bc$1"))
assert.NotNil(t, ValidateRoleName("-bad"))
assert.NotNil(t, ValidateRoleName("1leading"))
assert.NotNil(t, ValidateRoleName(""))
assert.NotNil(t, ValidateRoleName("*"))
pt.ProxyCfg.RoleNameValidationAllowedChars.SwapTempValue("$")
assert.Nil(t, ValidateRoleName("Admin_1"))
assert.Nil(t, ValidateRoleName("Admin$1"))
assert.NotNil(t, ValidateRoleName("Admin-1"))
}
func TestIsDefaultRole(t *testing.T) { func TestIsDefaultRole(t *testing.T) {
assert.Equal(t, true, IsDefaultRole(util.RoleAdmin)) assert.Equal(t, true, IsDefaultRole(util.RoleAdmin))
assert.Equal(t, true, IsDefaultRole(util.RolePublic)) assert.Equal(t, true, IsDefaultRole(util.RolePublic))

View File

@ -1642,6 +1642,8 @@ type proxyConfig struct {
GinLogSkipPaths ParamItem `refreshable:"false"` GinLogSkipPaths ParamItem `refreshable:"false"`
MaxUserNum ParamItem `refreshable:"true"` MaxUserNum ParamItem `refreshable:"true"`
MaxRoleNum ParamItem `refreshable:"true"` MaxRoleNum ParamItem `refreshable:"true"`
NameValidationAllowedChars ParamItem `refreshable:"true"`
RoleNameValidationAllowedChars ParamItem `refreshable:"true"`
MaxTaskNum ParamItem `refreshable:"false"` MaxTaskNum ParamItem `refreshable:"false"`
DDLConcurrency ParamItem `refreshable:"true"` DDLConcurrency ParamItem `refreshable:"true"`
DCLConcurrency ParamItem `refreshable:"true"` DCLConcurrency ParamItem `refreshable:"true"`
@ -1855,6 +1857,22 @@ please adjust in embedded Milvus: false`,
} }
p.MaxRoleNum.Init(base.mgr) p.MaxRoleNum.Init(base.mgr)
p.NameValidationAllowedChars = ParamItem{
Key: "proxy.nameValidation.allowedChars",
DefaultValue: "$",
Doc: "Additional characters allowed in names beyond underscores, letters and numbers. To allow hyphens in names, add '-' here.",
Export: true,
}
p.NameValidationAllowedChars.Init(base.mgr)
p.RoleNameValidationAllowedChars = ParamItem{
Key: "proxy.roleNameValidation.allowedChars",
DefaultValue: "$",
Doc: "Additional characters allowed in role names beyond underscores, letters and numbers. Add '-' to allow hyphens in role names.",
Export: true,
}
p.RoleNameValidationAllowedChars.Init(base.mgr)
p.SoPath = ParamItem{ p.SoPath = ParamItem{
Key: "proxy.soPath", Key: "proxy.soPath",
Version: "2.2.0", Version: "2.2.0",