mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 18:48:08 +00:00 
			
		
		
		
	plugins/database: Allow both {{name}} and {{username}} in MySQL & Postgres (#8240)
* Allow {{name}} or {{username}} in psql templates
* Fix default rotation bug; allow {{user}} and {{username}}
			
			
This commit is contained in:
		| @@ -53,153 +53,219 @@ func TestMySQL_Initialize(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestMySQL_CreateUser(t *testing.T) { | ||||
| 	cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret") | ||||
| 	defer cleanup() | ||||
| 	t.Run("missing creation statements", func(t *testing.T) { | ||||
| 		db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 	} | ||||
| 		usernameConfig := dbplugin.UsernameConfig{ | ||||
| 			DisplayName: "test-long-displayname", | ||||
| 			RoleName:    "test-long-rolename", | ||||
| 		} | ||||
|  | ||||
| 	db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 		username, password, err := db.CreateUser(context.Background(), dbplugin.Statements{}, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 		if err == nil { | ||||
| 			t.Fatalf("expected err, got nil") | ||||
| 		} | ||||
| 		if username != "" { | ||||
| 			t.Fatalf("expected empty username, got [%s]", username) | ||||
| 		} | ||||
| 		if password != "" { | ||||
| 			t.Fatalf("expected empty password, got [%s]", password) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	usernameConfig := dbplugin.UsernameConfig{ | ||||
| 		DisplayName: "test-long-displayname", | ||||
| 		RoleName:    "test-long-rolename", | ||||
| 	} | ||||
| 	t.Run("non-legacy", func(t *testing.T) { | ||||
| 		// Shared test container for speed - there should not be any overlap between the tests | ||||
| 		cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret") | ||||
| 		defer cleanup() | ||||
|  | ||||
| 	// Test with no configured Creation Statement | ||||
| 	_, _, err = db.CreateUser(context.Background(), dbplugin.Statements{}, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err == nil { | ||||
| 		t.Fatal("Expected error when no creation statement is provided") | ||||
| 	} | ||||
| 		connectionDetails := map[string]interface{}{ | ||||
| 			"connection_url": connURL, | ||||
| 		} | ||||
|  | ||||
| 	statements := dbplugin.Statements{ | ||||
| 		Creation: []string{testMySQLRoleWildCard}, | ||||
| 	} | ||||
| 		db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
| 		_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("err: %s", err) | ||||
| 		} | ||||
|  | ||||
| 	username, password, err := db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 		testCreateUser(t, db, connURL) | ||||
| 	}) | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 	t.Run("legacy", func(t *testing.T) { | ||||
| 		// Shared test container for speed - there should not be any overlap between the tests | ||||
| 		cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, true, "secret") | ||||
| 		defer cleanup() | ||||
|  | ||||
| 	// Test a second time to make sure usernames don't collide | ||||
| 	username, password, err = db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 		connectionDetails := map[string]interface{}{ | ||||
| 			"connection_url": connURL, | ||||
| 		} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	// Test with a manually prepare statement | ||||
| 	statements.Creation = []string{testMySQLRolePreparedStmt} | ||||
|  | ||||
| 	username, password, err = db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 		db := new(credsutil.NoneLength, LegacyMetadataLen, LegacyUsernameLen) | ||||
| 		_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("err: %s", err) | ||||
| 		} | ||||
|  | ||||
| 		testCreateUser(t, db, connURL) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestMySQL_CreateUser_Legacy(t *testing.T) { | ||||
| 	cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, true, "secret") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| func testCreateUser(t *testing.T, db *MySQL, connURL string) { | ||||
| 	type testCase struct { | ||||
| 		createStmts []string | ||||
| 	} | ||||
|  | ||||
| 	db := new(credsutil.NoneLength, LegacyMetadataLen, LegacyUsernameLen) | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	tests := map[string]testCase{ | ||||
| 		"create name": { | ||||
| 			createStmts: []string{` | ||||
| 				CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| 				GRANT SELECT ON *.* TO '{{name}}'@'%';`, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"create username": { | ||||
| 			createStmts: []string{` | ||||
| 				CREATE USER '{{username}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| 				GRANT SELECT ON *.* TO '{{username}}'@'%';`, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"prepared statement name": { | ||||
| 			createStmts: []string{` | ||||
| 				CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| 				set @grants=CONCAT("GRANT SELECT ON ", "*", ".* TO '{{name}}'@'%'"); | ||||
| 				PREPARE grantStmt from @grants; | ||||
| 				EXECUTE grantStmt; | ||||
| 				DEALLOCATE PREPARE grantStmt; | ||||
| 				`, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"prepared statement username": { | ||||
| 			createStmts: []string{` | ||||
| 				CREATE USER '{{username}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| 				set @grants=CONCAT("GRANT SELECT ON ", "*", ".* TO '{{username}}'@'%'"); | ||||
| 				PREPARE grantStmt from @grants; | ||||
| 				EXECUTE grantStmt; | ||||
| 				DEALLOCATE PREPARE grantStmt; | ||||
| 				`, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	usernameConfig := dbplugin.UsernameConfig{ | ||||
| 		DisplayName: "test-long-displayname", | ||||
| 		RoleName:    "test-long-rolename", | ||||
| 	} | ||||
| 	for name, test := range tests { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			usernameConfig := dbplugin.UsernameConfig{ | ||||
| 				DisplayName: "test-long-displayname", | ||||
| 				RoleName:    "test-long-rolename", | ||||
| 			} | ||||
|  | ||||
| 	// Test with no configured Creation Statement | ||||
| 	_, _, err = db.CreateUser(context.Background(), dbplugin.Statements{}, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err == nil { | ||||
| 		t.Fatal("Expected error when no creation statement is provided") | ||||
| 	} | ||||
| 			statements := dbplugin.Statements{ | ||||
| 				Creation: test.createStmts, | ||||
| 			} | ||||
|  | ||||
| 	statements := dbplugin.Statements{ | ||||
| 		Creation: []string{testMySQLRoleWildCard}, | ||||
| 	} | ||||
| 			username, password, err := db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	username, password, err := db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 			if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 				t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 			// Test a second time to make sure usernames don't collide | ||||
| 			username, password, err = db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	// Test a second time to make sure usernames don't collide | ||||
| 	username, password, err = db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 			if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 				t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMySQL_RotateRootCredentials(t *testing.T) { | ||||
| 	cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	connURL = strings.Replace(connURL, "root:secret", `{{username}}:{{password}}`, -1) | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 		"username":       "root", | ||||
| 		"password":       "secret", | ||||
| 	type testCase struct { | ||||
| 		statements []string | ||||
| 	} | ||||
|  | ||||
| 	db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	tests := map[string]testCase{ | ||||
| 		"empty statements": { | ||||
| 			statements: nil, | ||||
| 		}, | ||||
| 		"default username": { | ||||
| 			statements: []string{defaultMySQLRotateCredentialsSQL}, | ||||
| 		}, | ||||
| 		"default name": { | ||||
| 			statements: []string{` | ||||
| 				ALTER USER '{{username}}'@'%' IDENTIFIED BY '{{password}}';`, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	if !db.Initialized { | ||||
| 		t.Fatal("Database should be initialized") | ||||
| 	} | ||||
| 	for name, test := range tests { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret") | ||||
| 			defer cleanup() | ||||
|  | ||||
| 	newConf, err := db.RotateRootCredentials(context.Background(), nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %v", err) | ||||
| 	} | ||||
| 	if newConf["password"] == "secret" { | ||||
| 		t.Fatal("password was not updated") | ||||
| 	} | ||||
| 			connURL = strings.Replace(connURL, "root:secret", `{{username}}:{{password}}`, -1) | ||||
|  | ||||
| 	err = db.Close() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 			connectionDetails := map[string]interface{}{ | ||||
| 				"connection_url": connURL, | ||||
| 				"username":       "root", | ||||
| 				"password":       "secret", | ||||
| 			} | ||||
|  | ||||
| 			// Give a timeout just in case the test decides to be problematic | ||||
| 			ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | ||||
| 			defer cancel() | ||||
|  | ||||
| 			db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
| 			_, err := db.Init(ctx, connectionDetails, true) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
|  | ||||
| 			if !db.Initialized { | ||||
| 				t.Fatal("Database should be initialized") | ||||
| 			} | ||||
|  | ||||
| 			newConf, err := db.RotateRootCredentials(ctx, test.statements) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %v", err) | ||||
| 			} | ||||
| 			if newConf["password"] == "secret" { | ||||
| 				t.Fatal("password was not updated") | ||||
| 			} | ||||
|  | ||||
| 			err = db.Close() | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMySQL_RevokeUser(t *testing.T) { | ||||
| 	type testCase struct { | ||||
| 		revokeStmts []string | ||||
| 	} | ||||
|  | ||||
| 	tests := map[string]testCase{ | ||||
| 		"empty statements": { | ||||
| 			revokeStmts: nil, | ||||
| 		}, | ||||
| 		"default name": { | ||||
| 			revokeStmts: []string{defaultMysqlRevocationStmts}, | ||||
| 		}, | ||||
| 		"default username": { | ||||
| 			revokeStmts: []string{` | ||||
| 				REVOKE ALL PRIVILEGES, GRANT OPTION FROM '{{username}}'@'%';  | ||||
| 				DROP USER '{{username}}'@'%'`, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	// Shared test container for speed - there should not be any overlap between the tests | ||||
| 	cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret") | ||||
| 	defer cleanup() | ||||
|  | ||||
| @@ -207,117 +273,142 @@ func TestMySQL_RevokeUser(t *testing.T) { | ||||
| 		"connection_url": connURL, | ||||
| 	} | ||||
|  | ||||
| 	// Give a timeout just in case the test decides to be problematic | ||||
| 	initCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | ||||
| 	defer cancel() | ||||
|  | ||||
| 	db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	_, err := db.Init(initCtx, connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	statements := dbplugin.Statements{ | ||||
| 		Creation: []string{testMySQLRoleWildCard}, | ||||
| 	} | ||||
| 	for name, test := range tests { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			statements := dbplugin.Statements{ | ||||
| 				Creation: []string{` | ||||
| 					CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| 					GRANT SELECT ON *.* TO '{{name}}'@'%';`, | ||||
| 				}, | ||||
| 				Revocation: test.revokeStmts, | ||||
| 			} | ||||
|  | ||||
| 	usernameConfig := dbplugin.UsernameConfig{ | ||||
| 		DisplayName: "test", | ||||
| 		RoleName:    "test", | ||||
| 	} | ||||
| 			usernameConfig := dbplugin.UsernameConfig{ | ||||
| 				DisplayName: "test", | ||||
| 				RoleName:    "test", | ||||
| 			} | ||||
|  | ||||
| 	username, password, err := db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 			// Give a timeout just in case the test decides to be problematic | ||||
| 			ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | ||||
| 			defer cancel() | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 			username, password, err := db.CreateUser(ctx, statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	// Test default revoke statements | ||||
| 	err = db.RevokeUser(context.Background(), statements, username) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 			if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 				t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err == nil { | ||||
| 		t.Fatal("Credentials were not revoked") | ||||
| 	} | ||||
| 			err = db.RevokeUser(context.Background(), statements, username) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	statements.Creation = []string{testMySQLRoleWildCard} | ||||
| 	username, password, err = db.CreateUser(context.Background(), statements, usernameConfig, time.Now().Add(time.Minute)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	// Test custom revoke statements | ||||
| 	statements.Revocation = []string{testMySQLRevocationSQL} | ||||
| 	err = db.RevokeUser(context.Background(), statements, username) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err == nil { | ||||
| 		t.Fatal("Credentials were not revoked") | ||||
| 			if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err == nil { | ||||
| 				t.Fatal("Credentials were not revoked") | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMySQL_SetCredentials(t *testing.T) { | ||||
| 	cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret") | ||||
| 	defer cleanup() | ||||
|  | ||||
| 	// create the database user and verify we can access | ||||
| 	dbUser := "vaultstatictest" | ||||
| 	createTestMySQLUser(t, connURL, dbUser, "password", testRoleStaticCreate) | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, "password"); err != nil { | ||||
| 		t.Fatalf("Could not connect with credentials: %s", err) | ||||
| 	type testCase struct { | ||||
| 		rotateStmts []string | ||||
| 	} | ||||
|  | ||||
| 	connectionDetails := map[string]interface{}{ | ||||
| 		"connection_url": connURL, | ||||
| 	tests := map[string]testCase{ | ||||
| 		"empty statements": { | ||||
| 			rotateStmts: nil, | ||||
| 		}, | ||||
| 		"custom statement name": { | ||||
| 			rotateStmts: []string{` | ||||
| 				ALTER USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';`}, | ||||
| 		}, | ||||
| 		"custom statement username": { | ||||
| 			rotateStmts: []string{` | ||||
| 				ALTER USER '{{username}}'@'%' IDENTIFIED BY '{{password}}';`}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
| 	_, err := db.Init(context.Background(), connectionDetails, true) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 	for name, test := range tests { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret") | ||||
| 			defer cleanup() | ||||
|  | ||||
| 	newPassword, err := db.GenerateCredentials(context.Background()) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 			// create the database user and verify we can access | ||||
| 			dbUser := "vaultstatictest" | ||||
| 			initPassword := "password" | ||||
|  | ||||
| 	userConfig := dbplugin.StaticUserConfig{ | ||||
| 		Username: dbUser, | ||||
| 		Password: newPassword, | ||||
| 	} | ||||
| 			createStatements := ` | ||||
| 				CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| 				GRANT SELECT ON *.* TO '{{name}}'@'%';` | ||||
|  | ||||
| 	statements := dbplugin.Statements{ | ||||
| 		Rotation: []string{testRoleStaticRotate}, | ||||
| 	} | ||||
| 			createTestMySQLUser(t, connURL, dbUser, initPassword, createStatements) | ||||
| 			if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, "password"); err != nil { | ||||
| 				t.Fatalf("Could not connect with credentials: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	_, _, err = db.SetCredentials(context.Background(), statements, userConfig) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 			connectionDetails := map[string]interface{}{ | ||||
| 				"connection_url": connURL, | ||||
| 			} | ||||
|  | ||||
| 	// verify new password works | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, newPassword); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 	} | ||||
| 			// Give a timeout just in case the test decides to be problematic | ||||
| 			ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | ||||
| 			defer cancel() | ||||
|  | ||||
| 	// call SetCredentials again, password will change | ||||
| 	newPassword, _ = db.GenerateCredentials(context.Background()) | ||||
| 	userConfig.Password = newPassword | ||||
| 	_, _, err = db.SetCredentials(context.Background(), statements, userConfig) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("err: %s", err) | ||||
| 	} | ||||
| 			db := new(MetadataLen, MetadataLen, UsernameLen) | ||||
| 			_, err := db.Init(ctx, connectionDetails, true) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
|  | ||||
| 	if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, newPassword); err != nil { | ||||
| 		t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 			newPassword, err := db.GenerateCredentials(ctx) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("unable to generate password: %s", err) | ||||
| 			} | ||||
|  | ||||
| 			userConfig := dbplugin.StaticUserConfig{ | ||||
| 				Username: dbUser, | ||||
| 				Password: newPassword, | ||||
| 			} | ||||
|  | ||||
| 			statements := dbplugin.Statements{ | ||||
| 				Rotation: test.rotateStmts, | ||||
| 			} | ||||
|  | ||||
| 			username, password, err := db.SetCredentials(ctx, statements, userConfig) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("err: %s", err) | ||||
| 			} | ||||
| 			if username != userConfig.Username { | ||||
| 				t.Fatalf("expected username [%s], got [%s]", userConfig.Username, username) | ||||
| 			} | ||||
| 			if password != userConfig.Password { | ||||
| 				t.Fatalf("expected password [%s] got [%s]", userConfig.Password, password) | ||||
| 			} | ||||
|  | ||||
| 			// verify new password works | ||||
| 			if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, newPassword); err != nil { | ||||
| 				t.Fatalf("Could not connect with new credentials: %s", err) | ||||
| 			} | ||||
|  | ||||
| 			// verify old password doesn't work | ||||
| 			if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, initPassword); err == nil { | ||||
| 				t.Fatalf("Should not be able to connect with initial credentials") | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -399,28 +490,3 @@ func createTestMySQLUser(t *testing.T, connURL, username, password, query string | ||||
| 		stmt.Close() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const testMySQLRolePreparedStmt = ` | ||||
| CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| set @grants=CONCAT("GRANT SELECT ON ", "*", ".* TO '{{name}}'@'%'"); | ||||
| PREPARE grantStmt from @grants; | ||||
| EXECUTE grantStmt; | ||||
| DEALLOCATE PREPARE grantStmt; | ||||
| ` | ||||
| const testMySQLRoleWildCard = ` | ||||
| CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| GRANT SELECT ON *.* TO '{{name}}'@'%'; | ||||
| ` | ||||
| const testMySQLRevocationSQL = ` | ||||
| REVOKE ALL PRIVILEGES, GRANT OPTION FROM '{{name}}'@'%';  | ||||
| DROP USER '{{name}}'@'%'; | ||||
| ` | ||||
|  | ||||
| const testRoleStaticCreate = ` | ||||
| CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| GRANT SELECT ON *.* TO '{{name}}'@'%'; | ||||
| ` | ||||
|  | ||||
| const testRoleStaticRotate = ` | ||||
| ALTER USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; | ||||
| ` | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Michael Golowka
					Michael Golowka