2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2017-04-13 20:48:32 +00:00
|
|
|
package postgresql
|
|
|
|
|
|
|
|
import (
|
2017-12-14 22:03:11 +00:00
|
|
|
"context"
|
2017-04-13 20:48:32 +00:00
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
2022-09-22 19:00:56 +00:00
|
|
|
"os"
|
2017-04-13 20:48:32 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-05-29 18:21:23 +00:00
|
|
|
"github.com/hashicorp/vault/helper/testhelpers/postgresql"
|
2022-05-23 19:49:18 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/database/dbplugin/v5"
|
2020-10-15 19:20:12 +00:00
|
|
|
dbtesting "github.com/hashicorp/vault/sdk/database/dbplugin/v5/testing"
|
2022-09-22 19:00:56 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/database/helper/dbutil"
|
2023-04-24 18:25:50 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/docker"
|
2021-02-04 23:05:56 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/template"
|
2023-03-21 19:12:53 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2021-02-04 23:05:56 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2017-04-13 20:48:32 +00:00
|
|
|
)
|
|
|
|
|
2020-05-29 18:21:23 +00:00
|
|
|
func getPostgreSQL(t *testing.T, options map[string]interface{}) (*PostgreSQL, func()) {
|
2021-09-27 15:38:39 +00:00
|
|
|
cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster")
|
2017-04-13 20:48:32 +00:00
|
|
|
|
|
|
|
connectionDetails := map[string]interface{}{
|
2020-05-29 18:21:23 +00:00
|
|
|
"connection_url": connURL,
|
|
|
|
}
|
|
|
|
for k, v := range options {
|
|
|
|
connectionDetails[k] = v
|
2017-04-13 20:48:32 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 19:20:12 +00:00
|
|
|
req := dbplugin.InitializeRequest{
|
2020-10-07 18:58:11 +00:00
|
|
|
Config: connectionDetails,
|
|
|
|
VerifyConnection: true,
|
2017-04-13 20:48:32 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
db := new()
|
|
|
|
dbtesting.AssertInitialize(t, db, req)
|
|
|
|
|
2018-03-21 19:05:56 +00:00
|
|
|
if !db.Initialized {
|
2019-03-19 13:32:45 +00:00
|
|
|
t.Fatal("Database should be initialized")
|
2017-04-13 20:48:32 +00:00
|
|
|
}
|
2020-05-29 18:21:23 +00:00
|
|
|
return db, cleanup
|
|
|
|
}
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-05-29 18:21:23 +00:00
|
|
|
func TestPostgreSQL_Initialize(t *testing.T) {
|
|
|
|
db, cleanup := getPostgreSQL(t, map[string]interface{}{
|
|
|
|
"max_open_connections": 5,
|
|
|
|
})
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
if err := db.Close(); err != nil {
|
2017-04-13 20:48:32 +00:00
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
2020-05-29 18:21:23 +00:00
|
|
|
}
|
2017-06-15 01:59:27 +00:00
|
|
|
|
2020-05-29 18:21:23 +00:00
|
|
|
func TestPostgreSQL_InitializeWithStringVals(t *testing.T) {
|
|
|
|
db, cleanup := getPostgreSQL(t, map[string]interface{}{
|
2017-06-15 01:59:27 +00:00
|
|
|
"max_open_connections": "5",
|
2020-05-29 18:21:23 +00:00
|
|
|
})
|
|
|
|
defer cleanup()
|
2017-06-15 01:59:27 +00:00
|
|
|
|
2020-05-29 18:21:23 +00:00
|
|
|
if err := db.Close(); err != nil {
|
2017-06-15 01:59:27 +00:00
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
2017-04-13 20:48:32 +00:00
|
|
|
}
|
|
|
|
|
2022-05-23 19:49:18 +00:00
|
|
|
func TestPostgreSQL_Initialize_ConnURLWithDSNFormat(t *testing.T) {
|
|
|
|
cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster")
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
dsnConnURL, err := dbutil.ParseURL(connURL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
connectionDetails := map[string]interface{}{
|
|
|
|
"connection_url": dsnConnURL,
|
|
|
|
}
|
|
|
|
|
|
|
|
req := dbplugin.InitializeRequest{
|
|
|
|
Config: connectionDetails,
|
|
|
|
VerifyConnection: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
db := new()
|
|
|
|
dbtesting.AssertInitialize(t, db, req)
|
|
|
|
|
|
|
|
if !db.Initialized {
|
|
|
|
t.Fatal("Database should be initialized")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-21 19:12:53 +00:00
|
|
|
// TestPostgreSQL_PasswordAuthentication tests that the default "password_authentication" is "none", and that
|
|
|
|
// an error is returned if an invalid "password_authentication" is provided.
|
|
|
|
func TestPostgreSQL_PasswordAuthentication(t *testing.T) {
|
|
|
|
cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster")
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
dsnConnURL, err := dbutil.ParseURL(connURL)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
db := new()
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
t.Run("invalid-password-authentication", func(t *testing.T) {
|
|
|
|
connectionDetails := map[string]interface{}{
|
|
|
|
"connection_url": dsnConnURL,
|
|
|
|
"password_authentication": "invalid-password-authentication",
|
|
|
|
}
|
|
|
|
|
|
|
|
req := dbplugin.InitializeRequest{
|
|
|
|
Config: connectionDetails,
|
|
|
|
VerifyConnection: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := db.Initialize(ctx, req)
|
|
|
|
assert.EqualError(t, err, "'invalid-password-authentication' is not a valid password authentication type")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("default-is-none", func(t *testing.T) {
|
|
|
|
connectionDetails := map[string]interface{}{
|
|
|
|
"connection_url": dsnConnURL,
|
|
|
|
}
|
|
|
|
|
|
|
|
req := dbplugin.InitializeRequest{
|
|
|
|
Config: connectionDetails,
|
|
|
|
VerifyConnection: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
_ = dbtesting.AssertInitialize(t, db, req)
|
|
|
|
assert.Equal(t, passwordAuthenticationPassword, db.passwordAuthentication)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestPostgreSQL_PasswordAuthentication_SCRAMSHA256 tests that password_authentication works when set to scram-sha-256.
|
|
|
|
// When sending an encrypted password, the raw password should still successfully authenticate the user.
|
|
|
|
func TestPostgreSQL_PasswordAuthentication_SCRAMSHA256(t *testing.T) {
|
|
|
|
cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster")
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
dsnConnURL, err := dbutil.ParseURL(connURL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
connectionDetails := map[string]interface{}{
|
|
|
|
"connection_url": dsnConnURL,
|
|
|
|
"password_authentication": string(passwordAuthenticationSCRAMSHA256),
|
|
|
|
}
|
|
|
|
|
|
|
|
req := dbplugin.InitializeRequest{
|
|
|
|
Config: connectionDetails,
|
|
|
|
VerifyConnection: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
db := new()
|
|
|
|
resp := dbtesting.AssertInitialize(t, db, req)
|
|
|
|
assert.Equal(t, string(passwordAuthenticationSCRAMSHA256), resp.Config["password_authentication"])
|
|
|
|
|
|
|
|
if !db.Initialized {
|
|
|
|
t.Fatal("Database should be initialized")
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
newUserRequest := dbplugin.NewUserRequest{
|
|
|
|
Statements: dbplugin.Statements{
|
|
|
|
Commands: []string{
|
|
|
|
`
|
|
|
|
CREATE ROLE "{{name}}" WITH
|
|
|
|
LOGIN
|
|
|
|
PASSWORD '{{password}}'
|
|
|
|
VALID UNTIL '{{expiration}}';
|
|
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "{{name}}";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
|
|
|
}
|
|
|
|
newUserResponse, err := db.NewUser(ctx, newUserRequest)
|
|
|
|
|
|
|
|
assertCredsExist(t, db.ConnectionURL, newUserResponse.Username, newUserRequest.Password)
|
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func TestPostgreSQL_NewUser(t *testing.T) {
|
2020-02-03 20:57:28 +00:00
|
|
|
type testCase struct {
|
2020-10-15 19:20:12 +00:00
|
|
|
req dbplugin.NewUserRequest
|
2020-10-07 18:58:11 +00:00
|
|
|
expectErr bool
|
|
|
|
credsAssertion credsAssertion
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tests := map[string]testCase{
|
2020-10-07 18:58:11 +00:00
|
|
|
"no creation statements": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
|
|
|
// No statements
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: true,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^$"),
|
|
|
|
assertCredsDoNotExist,
|
|
|
|
),
|
2020-10-07 18:58:11 +00:00
|
|
|
},
|
2020-02-03 20:57:28 +00:00
|
|
|
"admin name": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2021-04-08 16:43:39 +00:00
|
|
|
Commands: []string{
|
|
|
|
`
|
2020-10-07 18:58:11 +00:00
|
|
|
CREATE ROLE "{{name}}" WITH
|
|
|
|
LOGIN
|
|
|
|
PASSWORD '{{password}}'
|
|
|
|
VALID UNTIL '{{expiration}}';
|
|
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "{{name}}";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^v-test-test-[a-zA-Z0-9]{20}-[0-9]{10}$"),
|
|
|
|
assertCredsExist,
|
|
|
|
),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
|
|
|
"admin username": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2021-04-08 16:43:39 +00:00
|
|
|
Commands: []string{
|
|
|
|
`
|
2020-10-07 18:58:11 +00:00
|
|
|
CREATE ROLE "{{username}}" WITH
|
|
|
|
LOGIN
|
|
|
|
PASSWORD '{{password}}'
|
|
|
|
VALID UNTIL '{{expiration}}';
|
|
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "{{username}}";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^v-test-test-[a-zA-Z0-9]{20}-[0-9]{10}$"),
|
|
|
|
assertCredsExist,
|
|
|
|
),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
|
|
|
"read only name": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2021-04-08 16:43:39 +00:00
|
|
|
Commands: []string{
|
|
|
|
`
|
2020-10-07 18:58:11 +00:00
|
|
|
CREATE ROLE "{{name}}" WITH
|
|
|
|
LOGIN
|
|
|
|
PASSWORD '{{password}}'
|
|
|
|
VALID UNTIL '{{expiration}}';
|
|
|
|
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";
|
|
|
|
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "{{name}}";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^v-test-test-[a-zA-Z0-9]{20}-[0-9]{10}$"),
|
|
|
|
assertCredsExist,
|
|
|
|
),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
|
|
|
"read only username": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2021-04-08 16:43:39 +00:00
|
|
|
Commands: []string{
|
|
|
|
`
|
2020-10-07 18:58:11 +00:00
|
|
|
CREATE ROLE "{{username}}" WITH
|
|
|
|
LOGIN
|
|
|
|
PASSWORD '{{password}}'
|
|
|
|
VALID UNTIL '{{expiration}}';
|
|
|
|
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{username}}";
|
|
|
|
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "{{username}}";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^v-test-test-[a-zA-Z0-9]{20}-[0-9]{10}$"),
|
|
|
|
assertCredsExist,
|
|
|
|
),
|
2020-03-17 19:45:25 +00:00
|
|
|
},
|
|
|
|
// https://github.com/hashicorp/vault/issues/6098
|
|
|
|
"reproduce GH-6098": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: []string{
|
|
|
|
// NOTE: "rolname" in the following line is not a typo.
|
|
|
|
"DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname='my_role') THEN CREATE ROLE my_role; END IF; END $$",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
2020-03-17 19:45:25 +00:00
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^v-test-test-[a-zA-Z0-9]{20}-[0-9]{10}$"),
|
|
|
|
assertCredsDoNotExist,
|
|
|
|
),
|
2020-03-17 19:45:25 +00:00
|
|
|
},
|
|
|
|
"reproduce issue with template": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: []string{
|
|
|
|
`DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname='my_role') THEN CREATE ROLE "{{username}}"; END IF; END $$`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^v-test-test-[a-zA-Z0-9]{20}-[0-9]{10}$"),
|
|
|
|
assertCredsDoNotExist,
|
|
|
|
),
|
2020-10-07 18:58:11 +00:00
|
|
|
},
|
|
|
|
"large block statements": {
|
2020-10-15 19:20:12 +00:00
|
|
|
req: dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: newUserLargeBlockStatements,
|
|
|
|
},
|
|
|
|
Password: "somesecurepassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Minute),
|
2020-03-17 19:45:25 +00:00
|
|
|
},
|
2021-02-04 23:05:56 +00:00
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCreds(
|
|
|
|
assertUsernameRegex("^v-test-test-[a-zA-Z0-9]{20}-[0-9]{10}$"),
|
|
|
|
assertCredsExist,
|
|
|
|
),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shared test container for speed - there should not be any overlap between the tests
|
2020-05-29 18:21:23 +00:00
|
|
|
db, cleanup := getPostgreSQL(t, nil)
|
2017-04-13 20:48:32 +00:00
|
|
|
defer cleanup()
|
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
// Give a timeout just in case the test decides to be problematic
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
|
|
defer cancel()
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
resp, err := db.NewUser(ctx, test.req)
|
|
|
|
if test.expectErr && err == nil {
|
|
|
|
t.Fatalf("err expected, got nil")
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
if !test.expectErr && err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
2020-03-17 19:45:25 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
test.credsAssertion(t, db.ConnectionURL, resp.Username, test.req.Password)
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
// Ensure that the role doesn't expire immediately
|
|
|
|
time.Sleep(2 * time.Second)
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
test.credsAssertion(t, db.ConnectionURL, resp.Username, test.req.Password)
|
2020-02-03 20:57:28 +00:00
|
|
|
})
|
2017-04-13 20:48:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func TestUpdateUser_Password(t *testing.T) {
|
2020-02-03 20:57:28 +00:00
|
|
|
type testCase struct {
|
2020-10-07 18:58:11 +00:00
|
|
|
statements []string
|
|
|
|
expectErr bool
|
|
|
|
credsAssertion credsAssertion
|
2018-03-21 19:05:56 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
tests := map[string]testCase{
|
2020-10-07 18:58:11 +00:00
|
|
|
"default statements": {
|
|
|
|
statements: nil,
|
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCredsExist,
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2020-10-07 18:58:11 +00:00
|
|
|
"explicit default statements": {
|
|
|
|
statements: []string{defaultChangePasswordStatement},
|
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCredsExist,
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2020-10-07 18:58:11 +00:00
|
|
|
"name instead of username": {
|
|
|
|
statements: []string{`ALTER ROLE "{{name}}" WITH PASSWORD '{{password}}';`},
|
|
|
|
expectErr: false,
|
|
|
|
credsAssertion: assertCredsExist,
|
|
|
|
},
|
|
|
|
"bad statements": {
|
|
|
|
statements: []string{`asdofyas8uf77asoiajv`},
|
|
|
|
expectErr: true,
|
|
|
|
credsAssertion: assertCredsDoNotExist,
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2018-03-21 19:05:56 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
// Shared test container for speed - there should not be any overlap between the tests
|
2020-05-29 18:21:23 +00:00
|
|
|
db, cleanup := getPostgreSQL(t, nil)
|
2017-04-13 20:48:32 +00:00
|
|
|
defer cleanup()
|
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2020-10-07 18:58:11 +00:00
|
|
|
initialPass := "myreallysecurepassword"
|
2020-10-15 19:20:12 +00:00
|
|
|
createReq := dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: []string{createAdminUser},
|
|
|
|
},
|
|
|
|
Password: initialPass,
|
|
|
|
Expiration: time.Now().Add(2 * time.Second),
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
createResp := dbtesting.AssertNewUser(t, db, createReq)
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
assertCredsExist(t, db.ConnectionURL, createResp.Username, initialPass)
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
newPass := "somenewpassword"
|
2020-10-15 19:20:12 +00:00
|
|
|
updateReq := dbplugin.UpdateUserRequest{
|
2020-10-07 18:58:11 +00:00
|
|
|
Username: createResp.Username,
|
2020-10-15 19:20:12 +00:00
|
|
|
Password: &dbplugin.ChangePassword{
|
2020-10-07 18:58:11 +00:00
|
|
|
NewPassword: newPass,
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: test.statements,
|
|
|
|
},
|
|
|
|
},
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
_, err := db.UpdateUser(ctx, updateReq)
|
|
|
|
if test.expectErr && err == nil {
|
|
|
|
t.Fatalf("err expected, got nil")
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
if !test.expectErr && err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
test.credsAssertion(t, db.ConnectionURL, createResp.Username, newPass)
|
2020-02-03 20:57:28 +00:00
|
|
|
})
|
2017-04-13 20:48:32 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
|
|
|
|
t.Run("user does not exist", func(t *testing.T) {
|
|
|
|
newPass := "somenewpassword"
|
2020-10-15 19:20:12 +00:00
|
|
|
updateReq := dbplugin.UpdateUserRequest{
|
2020-10-07 18:58:11 +00:00
|
|
|
Username: "missing-user",
|
2020-10-15 19:20:12 +00:00
|
|
|
Password: &dbplugin.ChangePassword{
|
2020-10-07 18:58:11 +00:00
|
|
|
NewPassword: newPass,
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{},
|
2020-10-07 18:58:11 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
_, err := db.UpdateUser(ctx, updateReq)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("err expected, got nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
assertCredsDoNotExist(t, db.ConnectionURL, updateReq.Username, newPass)
|
|
|
|
})
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2017-04-13 20:48:32 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func TestUpdateUser_Expiration(t *testing.T) {
|
2020-02-03 20:57:28 +00:00
|
|
|
type testCase struct {
|
2020-10-07 18:58:11 +00:00
|
|
|
initialExpiration time.Time
|
|
|
|
newExpiration time.Time
|
|
|
|
expectedExpiration time.Time
|
|
|
|
statements []string
|
|
|
|
expectErr bool
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
now := time.Now()
|
2020-02-03 20:57:28 +00:00
|
|
|
tests := map[string]testCase{
|
2020-10-07 18:58:11 +00:00
|
|
|
"no statements": {
|
|
|
|
initialExpiration: now.Add(1 * time.Minute),
|
|
|
|
newExpiration: now.Add(5 * time.Minute),
|
|
|
|
expectedExpiration: now.Add(5 * time.Minute),
|
|
|
|
statements: nil,
|
|
|
|
expectErr: false,
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2020-10-07 18:58:11 +00:00
|
|
|
"default statements with name": {
|
|
|
|
initialExpiration: now.Add(1 * time.Minute),
|
|
|
|
newExpiration: now.Add(5 * time.Minute),
|
|
|
|
expectedExpiration: now.Add(5 * time.Minute),
|
|
|
|
statements: []string{defaultExpirationStatement},
|
|
|
|
expectErr: false,
|
|
|
|
},
|
|
|
|
"default statements with username": {
|
|
|
|
initialExpiration: now.Add(1 * time.Minute),
|
|
|
|
newExpiration: now.Add(5 * time.Minute),
|
|
|
|
expectedExpiration: now.Add(5 * time.Minute),
|
|
|
|
statements: []string{`ALTER ROLE "{{username}}" VALID UNTIL '{{expiration}}';`},
|
|
|
|
expectErr: false,
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2020-10-07 18:58:11 +00:00
|
|
|
"bad statements": {
|
|
|
|
initialExpiration: now.Add(1 * time.Minute),
|
|
|
|
newExpiration: now.Add(5 * time.Minute),
|
|
|
|
expectedExpiration: now.Add(1 * time.Minute),
|
|
|
|
statements: []string{"ladshfouay09sgj"},
|
|
|
|
expectErr: true,
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
// Shared test container for speed - there should not be any overlap between the tests
|
|
|
|
db, cleanup := getPostgreSQL(t, nil)
|
|
|
|
defer cleanup()
|
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2020-10-07 18:58:11 +00:00
|
|
|
password := "myreallysecurepassword"
|
|
|
|
initialExpiration := test.initialExpiration.Truncate(time.Second)
|
2020-10-15 19:20:12 +00:00
|
|
|
createReq := dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: []string{createAdminUser},
|
|
|
|
},
|
|
|
|
Password: password,
|
|
|
|
Expiration: initialExpiration,
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
createResp := dbtesting.AssertNewUser(t, db, createReq)
|
2020-02-03 20:57:28 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
assertCredsExist(t, db.ConnectionURL, createResp.Username, password)
|
2020-02-03 20:57:28 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
actualExpiration := getExpiration(t, db, createResp.Username)
|
|
|
|
if actualExpiration.IsZero() {
|
|
|
|
t.Fatalf("Initial expiration is zero but should be set")
|
|
|
|
}
|
|
|
|
if !actualExpiration.Equal(initialExpiration) {
|
|
|
|
t.Fatalf("Actual expiration: %s Expected expiration: %s", actualExpiration, initialExpiration)
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
newExpiration := test.newExpiration.Truncate(time.Second)
|
2020-10-15 19:20:12 +00:00
|
|
|
updateReq := dbplugin.UpdateUserRequest{
|
2020-10-07 18:58:11 +00:00
|
|
|
Username: createResp.Username,
|
2020-10-15 19:20:12 +00:00
|
|
|
Expiration: &dbplugin.ChangeExpiration{
|
2020-10-07 18:58:11 +00:00
|
|
|
NewExpiration: newExpiration,
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: test.statements,
|
|
|
|
},
|
|
|
|
},
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
_, err := db.UpdateUser(ctx, updateReq)
|
|
|
|
if test.expectErr && err == nil {
|
|
|
|
t.Fatalf("err expected, got nil")
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
if !test.expectErr && err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
expectedExpiration := test.expectedExpiration.Truncate(time.Second)
|
|
|
|
actualExpiration = getExpiration(t, db, createResp.Username)
|
|
|
|
if !actualExpiration.Equal(expectedExpiration) {
|
|
|
|
t.Fatalf("Actual expiration: %s Expected expiration: %s", actualExpiration, expectedExpiration)
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
})
|
2017-04-13 20:48:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func getExpiration(t testing.TB, db *PostgreSQL, username string) time.Time {
|
|
|
|
t.Helper()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
query := fmt.Sprintf("select valuntil from pg_catalog.pg_user where usename = '%s'", username)
|
|
|
|
conn, err := db.getConnection(ctx)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to get connection to database: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := conn.PrepareContext(ctx, query)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to prepare statement: %s", err)
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
|
|
|
rows, err := stmt.QueryContext(ctx)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to execute query to get expiration: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !rows.Next() {
|
|
|
|
return time.Time{} // No expiration
|
|
|
|
}
|
|
|
|
rawExp := ""
|
|
|
|
err = rows.Scan(&rawExp)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to get raw expiration: %s", err)
|
|
|
|
}
|
|
|
|
if rawExp == "" {
|
|
|
|
return time.Time{} // No expiration
|
|
|
|
}
|
|
|
|
exp, err := time.Parse(time.RFC3339, rawExp)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to parse expiration %q: %s", rawExp, err)
|
|
|
|
}
|
|
|
|
return exp
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeleteUser(t *testing.T) {
|
2020-02-03 20:57:28 +00:00
|
|
|
type testCase struct {
|
2020-10-07 18:58:11 +00:00
|
|
|
revokeStmts []string
|
|
|
|
expectErr bool
|
|
|
|
credsAssertion credsAssertion
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tests := map[string]testCase{
|
2020-10-07 18:58:11 +00:00
|
|
|
"no statements": {
|
2020-02-03 20:57:28 +00:00
|
|
|
revokeStmts: nil,
|
2020-10-07 18:58:11 +00:00
|
|
|
expectErr: false,
|
|
|
|
// Wait for a short time before failing because postgres takes a moment to finish deleting the user
|
|
|
|
credsAssertion: waitUntilCredsDoNotExist(2 * time.Second),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2020-10-07 18:58:11 +00:00
|
|
|
"statements with name": {
|
|
|
|
revokeStmts: []string{`
|
|
|
|
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "{{name}}";
|
|
|
|
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM "{{name}}";
|
|
|
|
REVOKE USAGE ON SCHEMA public FROM "{{name}}";
|
|
|
|
|
|
|
|
DROP ROLE IF EXISTS "{{name}}";`},
|
|
|
|
expectErr: false,
|
|
|
|
// Wait for a short time before failing because postgres takes a moment to finish deleting the user
|
|
|
|
credsAssertion: waitUntilCredsDoNotExist(2 * time.Second),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2020-10-07 18:58:11 +00:00
|
|
|
"statements with username": {
|
2020-02-03 20:57:28 +00:00
|
|
|
revokeStmts: []string{`
|
|
|
|
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "{{username}}";
|
|
|
|
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM "{{username}}";
|
|
|
|
REVOKE USAGE ON SCHEMA public FROM "{{username}}";
|
2020-10-07 18:58:11 +00:00
|
|
|
|
|
|
|
DROP ROLE IF EXISTS "{{username}}";`},
|
|
|
|
expectErr: false,
|
|
|
|
// Wait for a short time before failing because postgres takes a moment to finish deleting the user
|
|
|
|
credsAssertion: waitUntilCredsDoNotExist(2 * time.Second),
|
|
|
|
},
|
|
|
|
"bad statements": {
|
|
|
|
revokeStmts: []string{`8a9yhfoiasjff`},
|
|
|
|
expectErr: true,
|
|
|
|
// Wait for a short time before checking because postgres takes a moment to finish deleting the user
|
|
|
|
credsAssertion: assertCredsExistAfter(100 * time.Millisecond),
|
2020-02-03 20:57:28 +00:00
|
|
|
},
|
2023-01-10 21:27:00 +00:00
|
|
|
"multiline": {
|
|
|
|
revokeStmts: []string{`
|
|
|
|
DO $$ BEGIN
|
|
|
|
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "{{username}}";
|
|
|
|
REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM "{{username}}";
|
|
|
|
REVOKE USAGE ON SCHEMA public FROM "{{username}}";
|
|
|
|
DROP ROLE IF EXISTS "{{username}}";
|
|
|
|
END $$;
|
|
|
|
`},
|
|
|
|
expectErr: false,
|
|
|
|
// Wait for a short time before checking because postgres takes a moment to finish deleting the user
|
|
|
|
credsAssertion: waitUntilCredsDoNotExist(2 * time.Second),
|
|
|
|
},
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shared test container for speed - there should not be any overlap between the tests
|
2020-05-29 18:21:23 +00:00
|
|
|
db, cleanup := getPostgreSQL(t, nil)
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
defer cleanup()
|
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2020-10-07 18:58:11 +00:00
|
|
|
password := "myreallysecurepassword"
|
2020-10-15 19:20:12 +00:00
|
|
|
createReq := dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: dbplugin.UsernameMetadata{
|
2020-10-07 18:58:11 +00:00
|
|
|
DisplayName: "test",
|
|
|
|
RoleName: "test",
|
|
|
|
},
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: []string{createAdminUser},
|
|
|
|
},
|
|
|
|
Password: password,
|
|
|
|
Expiration: time.Now().Add(2 * time.Second),
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
createResp := dbtesting.AssertNewUser(t, db, createReq)
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
assertCredsExist(t, db.ConnectionURL, createResp.Username, password)
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
|
2020-10-15 19:20:12 +00:00
|
|
|
deleteReq := dbplugin.DeleteUserRequest{
|
2020-10-07 18:58:11 +00:00
|
|
|
Username: createResp.Username,
|
2020-10-15 19:20:12 +00:00
|
|
|
Statements: dbplugin.Statements{
|
2020-10-07 18:58:11 +00:00
|
|
|
Commands: test.revokeStmts,
|
|
|
|
},
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
defer cancel()
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
_, err := db.DeleteUser(ctx, deleteReq)
|
|
|
|
if test.expectErr && err == nil {
|
|
|
|
t.Fatalf("err expected, got nil")
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
if !test.expectErr && err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
|
|
|
|
test.credsAssertion(t, db.ConnectionURL, createResp.Username, password)
|
2020-02-03 20:57:28 +00:00
|
|
|
})
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
}
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
type credsAssertion func(t testing.TB, connURL, username, password string)
|
2020-02-03 20:57:28 +00:00
|
|
|
|
2021-02-04 23:05:56 +00:00
|
|
|
func assertCreds(assertions ...credsAssertion) credsAssertion {
|
|
|
|
return func(t testing.TB, connURL, username, password string) {
|
|
|
|
t.Helper()
|
|
|
|
for _, assertion := range assertions {
|
|
|
|
assertion(t, connURL, username, password)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertUsernameRegex(rawRegex string) credsAssertion {
|
|
|
|
return func(t testing.TB, _, username, _ string) {
|
|
|
|
t.Helper()
|
|
|
|
require.Regexp(t, rawRegex, username)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func assertCredsExist(t testing.TB, connURL, username, password string) {
|
|
|
|
t.Helper()
|
|
|
|
err := testCredsExist(t, connURL, username, password)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("user does not exist: %s", err)
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
}
|
2020-02-03 20:57:28 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func assertCredsDoNotExist(t testing.TB, connURL, username, password string) {
|
|
|
|
t.Helper()
|
|
|
|
err := testCredsExist(t, connURL, username, password)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("user should not exist but does")
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
}
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func waitUntilCredsDoNotExist(timeout time.Duration) credsAssertion {
|
|
|
|
return func(t testing.TB, connURL, username, password string) {
|
|
|
|
t.Helper()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
ticker := time.NewTicker(10 * time.Millisecond)
|
|
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
t.Fatalf("Timed out waiting for user %s to be deleted", username)
|
|
|
|
case <-ticker.C:
|
|
|
|
err := testCredsExist(t, connURL, username, password)
|
|
|
|
if err != nil {
|
|
|
|
// Happy path
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-03 20:57:28 +00:00
|
|
|
}
|
2020-10-07 18:58:11 +00:00
|
|
|
}
|
2020-02-03 20:57:28 +00:00
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
func assertCredsExistAfter(timeout time.Duration) credsAssertion {
|
|
|
|
return func(t testing.TB, connURL, username, password string) {
|
|
|
|
t.Helper()
|
|
|
|
time.Sleep(timeout)
|
|
|
|
assertCredsExist(t, connURL, username, password)
|
Combined Database Backend: Static Accounts (#6834)
* Add priority queue to sdk
* fix issue of storing pointers and now copy
* update to use copy structure
* Remove file, put Item struct def. into other file
* add link
* clean up docs
* refactor internal data structure to hide heap method implementations. Other cleanup after feedback
* rename PushItem and PopItem to just Push/Pop, after encapsulating the heap methods
* updates after feedback
* refactoring/renaming
* guard against pushing a nil item
* minor updates after feedback
* Add SetCredentials, GenerateCredentials gRPC methods to combined database backend gPRC
* Initial Combined database backend implementation of static accounts and automatic rotation
* vendor updates
* initial implementation of static accounts with Combined database backend, starting with PostgreSQL implementation
* add lock and setup of rotation queue
* vendor the queue
* rebase on new method signature of queue
* remove mongo tests for now
* update default role sql
* gofmt after rebase
* cleanup after rebasing to remove checks for ErrNotFound error
* rebase cdcr-priority-queue
* vendor dependencies with 'go mod vendor'
* website database docs for Static Role support
* document the rotate-role API endpoint
* postgres specific static role docs
* use constants for paths
* updates from review
* remove dead code
* combine and clarify error message for older plugins
* Update builtin/logical/database/backend.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups from feedback
* code and comment cleanups
* move db.RLock higher to protect db.GenerateCredentials call
* Return output with WALID if we failed to delete the WAL
* Update builtin/logical/database/path_creds_create.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* updates after running 'make fmt'
* update after running 'make proto'
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update comment and remove and rearrange some dead code
* Update website/source/api/secret/databases/index.html.md
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* cleanups after review
* Update sdk/database/dbplugin/grpc_transport.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* code cleanup after feedback
* remove PasswordLastSet; it's not used
* document GenerateCredentials and SetCredentials
* Update builtin/logical/database/path_rotate_credentials.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* wrap pop and popbykey in backend methods to protect against nil cred rotation queue
* use strings.HasPrefix instead of direct equality check for path
* Forgot to commit this
* updates after feedback
* re-purpose an outdated test to now check that static and dynamic roles cannot share a name
* check for unique name across dynamic and static roles
* refactor loadStaticWALs to return a map of name/setCredentialsWAL struct to consolidate where we're calling set credentials
* remove commented out code
* refactor to have loadstaticwals filter out wals for roles that no longer exist
* return error if nil input given
* add nil check for input into setStaticAccount
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* add constant for queue tick time in seconds, used for comparrison in updates
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Jim Kalafut <jim@kalafut.net>
* code cleanup after review
* remove misplaced code comment
* remove commented out code
* create a queue in the Factory method, even if it's never used
* update path_roles to use a common set of fields, with specific overrides for dynamic/static roles by type
* document new method
* move rotation things into a specific file
* rename test file and consolidate some static account tests
* Update builtin/logical/database/path_roles.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* Update builtin/logical/database/rotation.go
Co-Authored-By: Brian Kassouf <briankassouf@users.noreply.github.com>
* update code comments, method names, and move more methods into rotation.go
* update comments to be capitalized
* remove the item from the queue before we try to destroy it
* findStaticWAL returns an error
* use lowercase keys when encoding WAL entries
* small cleanups
* remove vestigial static account check
* remove redundant DeleteWAL call in populate queue
* if we error on loading role, push back to queue with 10 second backoff
* poll in initqueue to make sure the backend is setup and can write/delete data
* add revoke_user_on_delete flag to allow users to opt-in to revoking the static database user on delete of the Vault role. Default false
* add code comments on read-only loop
* code comment updates
* re-push if error returned from find static wal
* add locksutil and acquire locks when pop'ing from the queue
* grab exclusive locks for updating static roles
* Add SetCredentials and GenerateCredentials stubs to mockPlugin
* add a switch in initQueue to listen for cancelation
* remove guard on zero time, it should have no affect
* create a new context in Factory to pass on and use for closing the backend queue
* restore master copy of vendor dir
2019-06-19 19:45:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-13 20:48:32 +00:00
|
|
|
func testCredsExist(t testing.TB, connURL, username, password string) error {
|
2018-03-21 19:05:56 +00:00
|
|
|
t.Helper()
|
2017-04-13 20:48:32 +00:00
|
|
|
// Log in with the new creds
|
|
|
|
connURL = strings.Replace(connURL, "postgres:secret", fmt.Sprintf("%s:%s", username, password), 1)
|
2022-05-23 19:49:18 +00:00
|
|
|
db, err := sql.Open("pgx", connURL)
|
2017-04-13 20:48:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer db.Close()
|
|
|
|
return db.Ping()
|
|
|
|
}
|
|
|
|
|
2020-02-03 20:57:28 +00:00
|
|
|
const createAdminUser = `
|
2017-04-13 20:48:32 +00:00
|
|
|
CREATE ROLE "{{name}}" WITH
|
|
|
|
LOGIN
|
|
|
|
PASSWORD '{{password}}'
|
|
|
|
VALID UNTIL '{{expiration}}';
|
|
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "{{name}}";
|
|
|
|
`
|
|
|
|
|
2020-10-07 18:58:11 +00:00
|
|
|
var newUserLargeBlockStatements = []string{
|
2017-04-13 20:48:32 +00:00
|
|
|
`
|
|
|
|
DO $$
|
|
|
|
BEGIN
|
|
|
|
IF NOT EXISTS (SELECT * FROM pg_catalog.pg_roles WHERE rolname='foo-role') THEN
|
|
|
|
CREATE ROLE "foo-role";
|
|
|
|
CREATE SCHEMA IF NOT EXISTS foo AUTHORIZATION "foo-role";
|
|
|
|
ALTER ROLE "foo-role" SET search_path = foo;
|
|
|
|
GRANT TEMPORARY ON DATABASE "postgres" TO "foo-role";
|
|
|
|
GRANT ALL PRIVILEGES ON SCHEMA foo TO "foo-role";
|
|
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo TO "foo-role";
|
|
|
|
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA foo TO "foo-role";
|
|
|
|
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA foo TO "foo-role";
|
|
|
|
END IF;
|
|
|
|
END
|
|
|
|
$$
|
|
|
|
`,
|
|
|
|
`CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';`,
|
|
|
|
`GRANT "foo-role" TO "{{name}}";`,
|
|
|
|
`ALTER ROLE "{{name}}" SET search_path = foo;`,
|
|
|
|
`GRANT CONNECT ON DATABASE "postgres" TO "{{name}}";`,
|
|
|
|
}
|
|
|
|
|
2020-03-17 19:45:25 +00:00
|
|
|
func TestContainsMultilineStatement(t *testing.T) {
|
|
|
|
type testCase struct {
|
|
|
|
Input string
|
|
|
|
Expected bool
|
|
|
|
}
|
|
|
|
|
|
|
|
testCases := map[string]*testCase{
|
|
|
|
"issue 6098 repro": {
|
|
|
|
Input: `DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname='my_role') THEN CREATE ROLE my_role; END IF; END $$`,
|
|
|
|
Expected: true,
|
|
|
|
},
|
|
|
|
"multiline with template fields": {
|
|
|
|
Input: `DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname="{{name}}") THEN CREATE ROLE {{name}}; END IF; END $$`,
|
|
|
|
Expected: true,
|
|
|
|
},
|
|
|
|
"docs example": {
|
|
|
|
Input: `CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
|
|
|
|
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";`,
|
|
|
|
Expected: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for tName, tCase := range testCases {
|
|
|
|
t.Run(tName, func(t *testing.T) {
|
|
|
|
if containsMultilineStatement(tCase.Input) != tCase.Expected {
|
|
|
|
t.Fatalf("%q should be %t for multiline input", tCase.Input, tCase.Expected)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExtractQuotedStrings(t *testing.T) {
|
|
|
|
type testCase struct {
|
|
|
|
Input string
|
|
|
|
Expected []string
|
|
|
|
}
|
|
|
|
|
|
|
|
testCases := map[string]*testCase{
|
|
|
|
"no quotes": {
|
|
|
|
Input: `Five little monkeys jumping on the bed`,
|
|
|
|
Expected: []string{},
|
|
|
|
},
|
|
|
|
"two of both quote types": {
|
|
|
|
Input: `"Five" little 'monkeys' "jumping on" the' 'bed`,
|
|
|
|
Expected: []string{`"Five"`, `"jumping on"`, `'monkeys'`, `' '`},
|
|
|
|
},
|
|
|
|
"one single quote": {
|
|
|
|
Input: `Five little monkeys 'jumping on the bed`,
|
|
|
|
Expected: []string{},
|
|
|
|
},
|
|
|
|
"empty string": {
|
|
|
|
Input: ``,
|
|
|
|
Expected: []string{},
|
|
|
|
},
|
|
|
|
"templated field": {
|
|
|
|
Input: `DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname="{{name}}") THEN CREATE ROLE {{name}}; END IF; END $$`,
|
|
|
|
Expected: []string{`"{{name}}"`},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for tName, tCase := range testCases {
|
|
|
|
t.Run(tName, func(t *testing.T) {
|
|
|
|
results, err := extractQuotedStrings(tCase.Input)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if len(results) != len(tCase.Expected) {
|
|
|
|
t.Fatalf("%s isn't equal to %s", results, tCase.Expected)
|
|
|
|
}
|
|
|
|
for i := range results {
|
|
|
|
if results[i] != tCase.Expected[i] {
|
|
|
|
t.Fatalf(`expected %q but received %q`, tCase.Expected, results[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-02-04 23:05:56 +00:00
|
|
|
|
|
|
|
func TestUsernameGeneration(t *testing.T) {
|
|
|
|
type testCase struct {
|
|
|
|
data dbplugin.UsernameMetadata
|
|
|
|
expectedRegex string
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := map[string]testCase{
|
|
|
|
"simple display and role names": {
|
|
|
|
data: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "token",
|
|
|
|
RoleName: "myrole",
|
|
|
|
},
|
|
|
|
expectedRegex: `v-token-myrole-[a-zA-Z0-9]{20}-[0-9]{10}`,
|
|
|
|
},
|
|
|
|
"display name has dash": {
|
|
|
|
data: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "token-foo",
|
|
|
|
RoleName: "myrole",
|
|
|
|
},
|
|
|
|
expectedRegex: `v-token-fo-myrole-[a-zA-Z0-9]{20}-[0-9]{10}`,
|
|
|
|
},
|
|
|
|
"display name has underscore": {
|
|
|
|
data: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "token_foo",
|
|
|
|
RoleName: "myrole",
|
|
|
|
},
|
|
|
|
expectedRegex: `v-token_fo-myrole-[a-zA-Z0-9]{20}-[0-9]{10}`,
|
|
|
|
},
|
|
|
|
"display name has period": {
|
|
|
|
data: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "token.foo",
|
|
|
|
RoleName: "myrole",
|
|
|
|
},
|
|
|
|
expectedRegex: `v-token.fo-myrole-[a-zA-Z0-9]{20}-[0-9]{10}`,
|
|
|
|
},
|
|
|
|
"role name has dash": {
|
|
|
|
data: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "token",
|
|
|
|
RoleName: "myrole-foo",
|
|
|
|
},
|
|
|
|
expectedRegex: `v-token-myrole-f-[a-zA-Z0-9]{20}-[0-9]{10}`,
|
|
|
|
},
|
|
|
|
"role name has underscore": {
|
|
|
|
data: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "token",
|
|
|
|
RoleName: "myrole_foo",
|
|
|
|
},
|
|
|
|
expectedRegex: `v-token-myrole_f-[a-zA-Z0-9]{20}-[0-9]{10}`,
|
|
|
|
},
|
|
|
|
"role name has period": {
|
|
|
|
data: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "token",
|
|
|
|
RoleName: "myrole.foo",
|
|
|
|
},
|
|
|
|
expectedRegex: `v-token-myrole.f-[a-zA-Z0-9]{20}-[0-9]{10}`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(fmt.Sprintf("new-%s", name), func(t *testing.T) {
|
|
|
|
up, err := template.NewTemplate(
|
|
|
|
template.Template(defaultUserNameTemplate),
|
|
|
|
)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
for i := 0; i < 1000; i++ {
|
|
|
|
username, err := up.Generate(test.data)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Regexp(t, test.expectedRegex, username)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewUser_CustomUsername(t *testing.T) {
|
2021-09-27 15:38:39 +00:00
|
|
|
cleanup, connURL := postgresql.PrepareTestContainer(t, "13.4-buster")
|
2021-02-04 23:05:56 +00:00
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
type testCase struct {
|
|
|
|
usernameTemplate string
|
|
|
|
newUserData dbplugin.UsernameMetadata
|
|
|
|
expectedRegex string
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := map[string]testCase{
|
|
|
|
"default template": {
|
|
|
|
usernameTemplate: "",
|
|
|
|
newUserData: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "displayname",
|
|
|
|
RoleName: "longrolename",
|
|
|
|
},
|
|
|
|
expectedRegex: "^v-displayn-longrole-[a-zA-Z0-9]{20}-[0-9]{10}$",
|
|
|
|
},
|
|
|
|
"explicit default template": {
|
|
|
|
usernameTemplate: defaultUserNameTemplate,
|
|
|
|
newUserData: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "displayname",
|
|
|
|
RoleName: "longrolename",
|
|
|
|
},
|
|
|
|
expectedRegex: "^v-displayn-longrole-[a-zA-Z0-9]{20}-[0-9]{10}$",
|
|
|
|
},
|
|
|
|
"unique template": {
|
|
|
|
usernameTemplate: "foo-bar",
|
|
|
|
newUserData: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "displayname",
|
|
|
|
RoleName: "longrolename",
|
|
|
|
},
|
|
|
|
expectedRegex: "^foo-bar$",
|
|
|
|
},
|
|
|
|
"custom prefix": {
|
|
|
|
usernameTemplate: "foobar-{{.DisplayName | truncate 8}}-{{.RoleName | truncate 8}}-{{random 20}}-{{unix_time}}",
|
|
|
|
newUserData: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "displayname",
|
|
|
|
RoleName: "longrolename",
|
|
|
|
},
|
|
|
|
expectedRegex: "^foobar-displayn-longrole-[a-zA-Z0-9]{20}-[0-9]{10}$",
|
|
|
|
},
|
|
|
|
"totally custom template": {
|
|
|
|
usernameTemplate: "foobar_{{random 10}}-{{.RoleName | uppercase}}.{{unix_time}}x{{.DisplayName | truncate 5}}",
|
|
|
|
newUserData: dbplugin.UsernameMetadata{
|
|
|
|
DisplayName: "displayname",
|
|
|
|
RoleName: "longrolename",
|
|
|
|
},
|
|
|
|
expectedRegex: `^foobar_[a-zA-Z0-9]{10}-LONGROLENAME\.[0-9]{10}xdispl$`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
initReq := dbplugin.InitializeRequest{
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"connection_url": connURL,
|
|
|
|
"username_template": test.usernameTemplate,
|
|
|
|
},
|
|
|
|
VerifyConnection: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
db := new()
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
_, err := db.Initialize(ctx, initReq)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
newUserReq := dbplugin.NewUserRequest{
|
|
|
|
UsernameConfig: test.newUserData,
|
|
|
|
Statements: dbplugin.Statements{
|
2021-04-08 16:43:39 +00:00
|
|
|
Commands: []string{
|
|
|
|
`
|
2021-02-04 23:05:56 +00:00
|
|
|
CREATE ROLE "{{name}}" WITH
|
|
|
|
LOGIN
|
|
|
|
PASSWORD '{{password}}'
|
|
|
|
VALID UNTIL '{{expiration}}';
|
|
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "{{name}}";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Password: "myReally-S3curePassword",
|
|
|
|
Expiration: time.Now().Add(1 * time.Hour),
|
|
|
|
}
|
|
|
|
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
newUserResp, err := db.NewUser(ctx, newUserReq)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Regexp(t, test.expectedRegex, newUserResp.Username)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-09-22 19:00:56 +00:00
|
|
|
|
|
|
|
// This is a long-running integration test which tests the functionality of Postgres's multi-host
|
|
|
|
// connection strings. It uses two Postgres containers preconfigured with Replication Manager
|
|
|
|
// provided by Bitnami. This test currently does not run in CI and must be run manually. This is
|
|
|
|
// due to the test length, as it requires multiple sleep calls to ensure cluster setup and
|
|
|
|
// primary node failover occurs before the test steps continue.
|
|
|
|
//
|
|
|
|
// To run the test, set the environment variable POSTGRES_MULTIHOST_NET to the value of
|
|
|
|
// a docker network you've preconfigured, e.g.
|
|
|
|
// 'docker network create -d bridge postgres-repmgr'
|
|
|
|
// 'export POSTGRES_MULTIHOST_NET=postgres-repmgr'
|
|
|
|
func TestPostgreSQL_Repmgr(t *testing.T) {
|
|
|
|
_, exists := os.LookupEnv("POSTGRES_MULTIHOST_NET")
|
|
|
|
if !exists {
|
|
|
|
t.Skipf("POSTGRES_MULTIHOST_NET not set, skipping test")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run two postgres-repmgr containers in a replication cluster
|
|
|
|
db0, runner0, url0, container0 := testPostgreSQL_Repmgr_Container(t, "psql-repl-node-0")
|
|
|
|
_, _, url1, _ := testPostgreSQL_Repmgr_Container(t, "psql-repl-node-1")
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
time.Sleep(10 * time.Second)
|
|
|
|
|
|
|
|
// Write a read role to the cluster
|
|
|
|
_, err := db0.NewUser(ctx, dbplugin.NewUserRequest{
|
|
|
|
Statements: dbplugin.Statements{
|
|
|
|
Commands: []string{
|
|
|
|
`CREATE ROLE "ro" NOINHERIT;
|
|
|
|
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "ro";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open a connection to both databases using the multihost connection string
|
|
|
|
connectionDetails := map[string]interface{}{
|
|
|
|
"connection_url": fmt.Sprintf("postgresql://{{username}}:{{password}}@%s,%s/postgres?target_session_attrs=read-write", getHost(url0), getHost(url1)),
|
|
|
|
"username": "postgres",
|
|
|
|
"password": "secret",
|
|
|
|
}
|
|
|
|
req := dbplugin.InitializeRequest{
|
|
|
|
Config: connectionDetails,
|
|
|
|
VerifyConnection: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
db := new()
|
|
|
|
dbtesting.AssertInitialize(t, db, req)
|
|
|
|
if !db.Initialized {
|
|
|
|
t.Fatal("Database should be initialized")
|
|
|
|
}
|
|
|
|
defer db.Close()
|
|
|
|
|
|
|
|
// Add a user to the cluster, then stop the primary container
|
|
|
|
if err = testPostgreSQL_Repmgr_AddUser(ctx, db); err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
|
|
|
}
|
|
|
|
postgresql.StopContainer(t, ctx, runner0, container0)
|
|
|
|
|
|
|
|
// Try adding a new user immediately - expect failure as the database
|
|
|
|
// cluster is still switching primaries
|
|
|
|
err = testPostgreSQL_Repmgr_AddUser(ctx, db)
|
|
|
|
if !strings.HasSuffix(err.Error(), "ValidateConnect failed (read only connection)") {
|
|
|
|
t.Fatalf("expected error was not received, got: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(20 * time.Second)
|
|
|
|
|
|
|
|
// Try adding a new user again which should succeed after the sleep
|
|
|
|
// as the primary failover should have finished. Then, restart
|
|
|
|
// the first container which should become a secondary DB.
|
|
|
|
if err = testPostgreSQL_Repmgr_AddUser(ctx, db); err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
|
|
|
}
|
|
|
|
postgresql.RestartContainer(t, ctx, runner0, container0)
|
|
|
|
|
|
|
|
time.Sleep(10 * time.Second)
|
|
|
|
|
|
|
|
// A final new user to add, which should succeed after the secondary joins.
|
|
|
|
if err = testPostgreSQL_Repmgr_AddUser(ctx, db); err != nil {
|
|
|
|
t.Fatalf("no error expected, got: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := db.Close(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testPostgreSQL_Repmgr_Container(t *testing.T, name string) (*PostgreSQL, *docker.Runner, string, string) {
|
|
|
|
envVars := []string{
|
|
|
|
"REPMGR_NODE_NAME=" + name,
|
|
|
|
"REPMGR_NODE_NETWORK_NAME=" + name,
|
|
|
|
}
|
|
|
|
|
|
|
|
runner, cleanup, connURL, containerID := postgresql.PrepareTestContainerRepmgr(t, name, "13.4.0", envVars)
|
|
|
|
t.Cleanup(cleanup)
|
|
|
|
|
|
|
|
connectionDetails := map[string]interface{}{
|
|
|
|
"connection_url": connURL,
|
|
|
|
}
|
|
|
|
req := dbplugin.InitializeRequest{
|
|
|
|
Config: connectionDetails,
|
|
|
|
VerifyConnection: true,
|
|
|
|
}
|
|
|
|
db := new()
|
|
|
|
dbtesting.AssertInitialize(t, db, req)
|
|
|
|
if !db.Initialized {
|
|
|
|
t.Fatal("Database should be initialized")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := db.Close(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return db, runner, connURL, containerID
|
|
|
|
}
|
|
|
|
|
|
|
|
func testPostgreSQL_Repmgr_AddUser(ctx context.Context, db *PostgreSQL) error {
|
|
|
|
_, err := db.NewUser(ctx, dbplugin.NewUserRequest{
|
|
|
|
Statements: dbplugin.Statements{
|
|
|
|
Commands: []string{
|
|
|
|
`CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}' INHERIT;
|
|
|
|
GRANT ro TO "{{name}}";`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func getHost(url string) string {
|
|
|
|
splitCreds := strings.Split(url, "@")[1]
|
|
|
|
|
|
|
|
return strings.Split(splitCreds, "/")[0]
|
|
|
|
}
|