From 7667847bfe8751c2b54658afed551b32037cb709 Mon Sep 17 00:00:00 2001
From: Oleksii Kliukin <oleksii.kliukin@zalando.de>
Date: Fri, 15 Sep 2017 13:57:48 +0200
Subject: [PATCH] Feature/validate role options (#101)

Be more rigorous about validating user flags.

Only accept CREATE ROLE flags that doesn't have any params (i.e.
not ADMIN or CONNECTION LIMIT). Check that both flag and NOflag
are not used at the same time.
---
 pkg/cluster/util.go         | 37 +++++++++++++++++++++++++++++--------
 pkg/util/constants/roles.go |  2 ++
 2 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/pkg/cluster/util.go b/pkg/cluster/util.go
index e9b18c18..2a144288 100644
--- a/pkg/cluster/util.go
+++ b/pkg/cluster/util.go
@@ -21,25 +21,46 @@ func isValidUsername(username string) bool {
 	return userRegexp.MatchString(username)
 }
 
-func normalizeUserFlags(userFlags []string) (flags []string, err error) {
+func isValidFlag(flag string) bool {
+	for _, validFlag := range []string{constants.RoleFlagSuperuser, constants.RoleFlagLogin, constants.RoleFlagCreateDB,
+		constants.RoleFlagInherit, constants.RoleFlagReplication, constants.RoleFlagByPassRLS} {
+		if flag == validFlag || flag == "NO"+validFlag {
+			return true
+		}
+	}
+	return false
+}
+
+func invertFlag(flag string) string {
+	if flag[:2] == "NO" {
+		return flag[2:]
+	}
+	return "NO" + flag
+}
+
+func normalizeUserFlags(userFlags []string) ([]string, error) {
 	uniqueFlags := make(map[string]bool)
 	addLogin := true
 
 	for _, flag := range userFlags {
 		if !alphaNumericRegexp.MatchString(flag) {
-			err = fmt.Errorf("user flag '%v' is not alphanumeric", flag)
-			return
+			return nil, fmt.Errorf("user flag %q is not alphanumeric", flag)
 		}
+
 		flag = strings.ToUpper(flag)
 		if _, ok := uniqueFlags[flag]; !ok {
+			if !isValidFlag(flag) {
+				return nil, fmt.Errorf("user flag %q is not valid", flag)
+			}
+			invFlag := invertFlag(flag)
+			if uniqueFlags[invFlag] {
+				return nil, fmt.Errorf("conflicting user flags: %q and %q", flag, invFlag)
+			}
 			uniqueFlags[flag] = true
 		}
 	}
-	if uniqueFlags[constants.RoleFlagLogin] && uniqueFlags[constants.RoleFlagNoLogin] {
-		return nil, fmt.Errorf("conflicting or redundant flags: LOGIN and NOLOGIN")
-	}
 
-	flags = []string{}
+	flags := []string{}
 	for k := range uniqueFlags {
 		if k == constants.RoleFlagNoLogin || k == constants.RoleFlagLogin {
 			addLogin = false
@@ -55,7 +76,7 @@ func normalizeUserFlags(userFlags []string) (flags []string, err error) {
 		flags = append(flags, constants.RoleFlagLogin)
 	}
 
-	return
+	return flags, nil
 }
 
 func specPatch(spec interface{}) ([]byte, error) {
diff --git a/pkg/util/constants/roles.go b/pkg/util/constants/roles.go
index 3b249092..5f81cb3d 100644
--- a/pkg/util/constants/roles.go
+++ b/pkg/util/constants/roles.go
@@ -12,4 +12,6 @@ const (
 	RoleFlagNoLogin        = "NOLOGIN"
 	RoleFlagCreateRole     = "CREATEROLE"
 	RoleFlagCreateDB       = "CREATEDB"
+	RoleFlagReplication    = "REPLICATION"
+	RoleFlagByPassRLS      = "BYPASSRLS"
 )
-- 
GitLab