diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 9937deff3..17e8c6747 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -41,7 +41,7 @@ import ( var ( alphaNumericRegexp = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$") databaseNameRegexp = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") - userRegexp = regexp.MustCompile(`^[a-z0-9]([-_a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-_a-z0-9]*[a-z0-9])?)*$`) + userRegexp = regexp.MustCompile(`^[a-z0-9,]+\.?[-_a-z0-9,]+[a-z0-9,]$`) patroniObjectSuffixes = []string{"config", "failover", "sync"} ) @@ -1093,16 +1093,12 @@ func (c *Cluster) initRobotUsers() error { if c.shouldAvoidProtectedOrSystemRole(username, "manifest robot role") { continue } - name := username namespace := c.Namespace + //more than one dot in the username is reported invalid by regexp if strings.Contains(username, ".") { splits := strings.Split(username, ".") - name = splits[1] - if len(splits[0]) > 0 { - namespace = splits[0] - } - username = name + namespace = splits[0] } flags, err := normalizeUserFlags(userFlags) @@ -1115,18 +1111,14 @@ func (c *Cluster) initRobotUsers() error { } newRole := spec.PgUser{ Origin: spec.RoleOriginManifest, - Name: name, + Name: username, Namespace: namespace, Password: util.RandomPassword(constants.PasswordLength), Flags: flags, AdminRole: adminRole, } if currentRole, present := c.pgUsers[username]; present { - if namespace == c.pgUsers[username].Namespace { - c.pgUsers[username] = c.resolveNameConflict(¤tRole, &newRole) - } else { - c.pgUsers[username+"."+namespace] = newRole - } + c.pgUsers[username] = c.resolveNameConflict(¤tRole, &newRole) } else { c.pgUsers[username] = newRole } diff --git a/pkg/cluster/cluster_test.go b/pkg/cluster/cluster_test.go index 7ccad19f1..df46a38f3 100644 --- a/pkg/cluster/cluster_test.go +++ b/pkg/cluster/cluster_test.go @@ -902,7 +902,7 @@ func TestCrossNamespacedSecrets(t *testing.T) { userNamespaceMap := map[string]string{ cluster.Namespace: "db_user", - "appspace": "db_user", + "appspace": "appspace.db_user", } err := cluster.initRobotUsers() @@ -912,7 +912,19 @@ func TestCrossNamespacedSecrets(t *testing.T) { for _, u := range cluster.pgUsers { if u.Name != userNamespaceMap[u.Namespace] { - t.Errorf("%s: Could not create namespaced user in its correct namespaces", testName) + t.Errorf("%s: Could not create namespaced user in its correct namespaces for user %s in namespace %s", testName, u.Name, u.Namespace) + } + } +} + +func TestValidUsernames(t *testing.T) { + testName := "test username validity" + + invalidUsernames := []string{"_", ".", ".user", "appspace.", "appspace.user.extra", "user_", "_user", "-user", "user-"} + + for _, username := range invalidUsernames { + if isValidUsername(username) { + t.Errorf("%s Invalid username is allowed: %s", testName, username) } } } diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index af01bd1b9..98f64449b 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -1581,13 +1581,10 @@ func (c *Cluster) generateSingleUserSecret(namespace string, pgUser spec.PgUser) if username == constants.ConnectionPoolerUserName { lbls = c.connectionPoolerLabels("", false).MatchLabels } - secret_name := username - if pgUser.Namespace != c.Namespace { - secret_name = username + "." + pgUser.Namespace - } + secret := v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: c.credentialSecretName(secret_name), + Name: c.credentialSecretName(username), Namespace: pgUser.Namespace, Labels: lbls, Annotations: c.annotationsSet(nil), diff --git a/pkg/cluster/sync.go b/pkg/cluster/sync.go index 112a0cf1f..43e56d14c 100644 --- a/pkg/cluster/sync.go +++ b/pkg/cluster/sync.go @@ -552,11 +552,13 @@ func (c *Cluster) syncRoles() (err error) { }() for _, u := range c.pgUsers { + pg_role := u.Name if u.Namespace != c.Namespace { - userNames = append(userNames, u.Name+"."+"u.Namespace") - } else { - userNames = append(userNames, u.Name) + // to avoid the conflict of having multiple users of same name + // but each in different namespace. + pg_role = fmt.Sprintf("%s.%s", u.Name, u.Namespace) } + userNames = append(userNames, pg_role) } if needMasterConnectionPooler(&c.Spec) || needReplicaConnectionPooler(&c.Spec) {