From cd87bb05ba0188d31c10a8467fe67c59e657a43b Mon Sep 17 00:00:00 2001 From: Milena Zlaticanin Date: Tue, 8 Jun 2021 15:09:46 -0500 Subject: [PATCH 1/3] Add username_template to influxdb --- plugins/database/influxdb/influxdb.go | 40 +++++++++++++----- plugins/database/influxdb/influxdb_test.go | 49 ++++++++++++++++++++-- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/plugins/database/influxdb/influxdb.go b/plugins/database/influxdb/influxdb.go index c8d0cc157c43..bd6f06301d3f 100644 --- a/plugins/database/influxdb/influxdb.go +++ b/plugins/database/influxdb/influxdb.go @@ -3,11 +3,11 @@ package influxdb import ( "context" "fmt" + "github.com/hashicorp/vault/sdk/helper/template" "strings" multierror "github.com/hashicorp/go-multierror" dbplugin "github.com/hashicorp/vault/sdk/database/dbplugin/v5" - "github.com/hashicorp/vault/sdk/database/helper/credsutil" "github.com/hashicorp/vault/sdk/database/helper/dbutil" "github.com/hashicorp/vault/sdk/helper/strutil" influx "github.com/influxdata/influxdb/client/v2" @@ -18,6 +18,8 @@ const ( defaultUserDeletionIFQL = `DROP USER "{{username}}";` defaultRootCredentialRotationIFQL = `SET PASSWORD FOR "{{username}}" = '{{password}}';` influxdbTypeName = "influxdb" + + defaultUserNameTemplate = `{{ printf "v_%s_%s_%s_%s" (.DisplayName | truncate 15) (.RoleName | truncate 15) (random 20) (unix_time) | truncate 100 | replace "-" "_" | lowercase }}` ) var _ dbplugin.Database = &Influxdb{} @@ -25,6 +27,8 @@ var _ dbplugin.Database = &Influxdb{} // Influxdb is an implementation of Database interface type Influxdb struct { *influxdbConnectionProducer + + usernameProducer template.StringTemplate } // New returns a new Cassandra instance @@ -58,6 +62,29 @@ func (i *Influxdb) getConnection(ctx context.Context) (influx.Client, error) { return cli.(influx.Client), nil } +func (i *Influxdb) Initialize(ctx context.Context, req dbplugin.InitializeRequest) (resp dbplugin.InitializeResponse, err error) { + usernameTemplate, err := strutil.GetString(req.Config, "username_template") + if err != nil { + return dbplugin.InitializeResponse{}, fmt.Errorf("failed to retrieve username_template: %w", err) + } + if usernameTemplate == "" { + usernameTemplate = defaultUserNameTemplate + } + + up, err := template.NewTemplate(template.Template(usernameTemplate)) + if err != nil { + return dbplugin.InitializeResponse{}, fmt.Errorf("unable to initialize username template: %w", err) + } + i.usernameProducer = up + + _, err = i.usernameProducer.Generate(dbplugin.UsernameMetadata{}) + if err != nil { + return dbplugin.InitializeResponse{}, fmt.Errorf("invalid username template: %w", err) + } + + return i.influxdbConnectionProducer.Initialize(ctx, req) +} + // NewUser generates the username/password on the underlying Influxdb secret backend as instructed by // the statements provided. func (i *Influxdb) NewUser(ctx context.Context, req dbplugin.NewUserRequest) (resp dbplugin.NewUserResponse, err error) { @@ -79,17 +106,10 @@ func (i *Influxdb) NewUser(ctx context.Context, req dbplugin.NewUserRequest) (re rollbackIFQL = []string{defaultUserDeletionIFQL} } - username, err := credsutil.GenerateUsername( - credsutil.DisplayName(req.UsernameConfig.DisplayName, 15), - credsutil.RoleName(req.UsernameConfig.RoleName, 15), - credsutil.MaxLength(100), - credsutil.Separator("_"), - credsutil.ToLower(), - ) + username, err := i.usernameProducer.Generate(req.UsernameConfig) if err != nil { - return dbplugin.NewUserResponse{}, fmt.Errorf("failed to generate username: %w", err) + return dbplugin.NewUserResponse{}, err } - username = strings.Replace(username, "-", "_", -1) for _, stmt := range creationIFQL { for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") { diff --git a/plugins/database/influxdb/influxdb_test.go b/plugins/database/influxdb/influxdb_test.go index 5328996927d4..ea652bed8a56 100644 --- a/plugins/database/influxdb/influxdb_test.go +++ b/plugins/database/influxdb/influxdb_test.go @@ -3,6 +3,7 @@ package influxdb import ( "context" "fmt" + "github.com/stretchr/testify/require" "net/url" "os" "reflect" @@ -220,7 +221,7 @@ func makeConfig(rootConfig map[string]interface{}, keyValues ...interface{}) map return config } -func TestInfluxdb_CreateUser(t *testing.T) { +func TestInfluxdb_CreateUser_DefaultUsernameTemplate(t *testing.T) { cleanup, config := prepareInfluxdbTestContainer(t) defer cleanup() @@ -234,8 +235,8 @@ func TestInfluxdb_CreateUser(t *testing.T) { password := "nuozxby98523u89bdfnkjl" newUserReq := dbplugin.NewUserRequest{ UsernameConfig: dbplugin.UsernameMetadata{ - DisplayName: "test", - RoleName: "test", + DisplayName: "token", + RoleName: "mylongrolenamewithmanycharacters", }, Statements: dbplugin.Statements{ Commands: []string{createUserStatements}, @@ -250,6 +251,46 @@ func TestInfluxdb_CreateUser(t *testing.T) { } assertCredsExist(t, config.URL().String(), resp.Username, password) + + require.Regexp(t, `^v_token_mylongrolenamew_[a-z0-9]{20}_[0-9]{10}$`, resp.Username) +} + +func TestInfluxdb_CreateUser_CustomUsernameTemplate(t *testing.T) { + cleanup, config := prepareInfluxdbTestContainer(t) + defer cleanup() + + db := new() + + conf := config.connectionParams() + conf["username_template"] = "{{.DisplayName}}_{{random 10}}" + + req := dbplugin.InitializeRequest{ + Config: conf, + VerifyConnection: true, + } + dbtesting.AssertInitialize(t, db, req) + + password := "nuozxby98523u89bdfnkjl" + newUserReq := dbplugin.NewUserRequest{ + UsernameConfig: dbplugin.UsernameMetadata{ + DisplayName: "token", + RoleName: "mylongrolenamewithmanycharacters", + }, + Statements: dbplugin.Statements{ + Commands: []string{createUserStatements}, + }, + Password: password, + Expiration: time.Now().Add(1 * time.Minute), + } + resp := dbtesting.AssertNewUser(t, db, newUserReq) + + if resp.Username == "" { + t.Fatalf("Missing username") + } + + assertCredsExist(t, config.URL().String(), resp.Username, password) + + require.Regexp(t, `^token_[a-zA-Z0-9]{10}$`, resp.Username) } func TestUpdateUser_expiration(t *testing.T) { @@ -436,4 +477,4 @@ func testCredsExist(address, username, password string) error { return fmt.Errorf("error using the correct influx database: %w", response.Error()) } return nil -} +} \ No newline at end of file From 0fd61e7b76bf90846009d125cfb8a816265b1b34 Mon Sep 17 00:00:00 2001 From: Milena Zlaticanin Date: Tue, 8 Jun 2021 15:26:32 -0500 Subject: [PATCH 2/3] go fmt --- plugins/database/influxdb/influxdb.go | 2 +- plugins/database/influxdb/influxdb_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/database/influxdb/influxdb.go b/plugins/database/influxdb/influxdb.go index bd6f06301d3f..d17939cd4284 100644 --- a/plugins/database/influxdb/influxdb.go +++ b/plugins/database/influxdb/influxdb.go @@ -64,7 +64,7 @@ func (i *Influxdb) getConnection(ctx context.Context) (influx.Client, error) { func (i *Influxdb) Initialize(ctx context.Context, req dbplugin.InitializeRequest) (resp dbplugin.InitializeResponse, err error) { usernameTemplate, err := strutil.GetString(req.Config, "username_template") - if err != nil { + if err != nil { return dbplugin.InitializeResponse{}, fmt.Errorf("failed to retrieve username_template: %w", err) } if usernameTemplate == "" { diff --git a/plugins/database/influxdb/influxdb_test.go b/plugins/database/influxdb/influxdb_test.go index ea652bed8a56..93530ec94a9b 100644 --- a/plugins/database/influxdb/influxdb_test.go +++ b/plugins/database/influxdb/influxdb_test.go @@ -3,7 +3,6 @@ package influxdb import ( "context" "fmt" - "github.com/stretchr/testify/require" "net/url" "os" "reflect" @@ -16,6 +15,7 @@ import ( dbplugin "github.com/hashicorp/vault/sdk/database/dbplugin/v5" dbtesting "github.com/hashicorp/vault/sdk/database/dbplugin/v5/testing" influx "github.com/influxdata/influxdb/client/v2" + "github.com/stretchr/testify/require" ) const createUserStatements = `CREATE USER "{{username}}" WITH PASSWORD '{{password}}';GRANT ALL ON "vault" TO "{{username}}";` @@ -477,4 +477,4 @@ func testCredsExist(address, username, password string) error { return fmt.Errorf("error using the correct influx database: %w", response.Error()) } return nil -} \ No newline at end of file +} From a08e775eb63e9dd9a675ab11fe180a1e950a682d Mon Sep 17 00:00:00 2001 From: Milena Zlaticanin Date: Wed, 9 Jun 2021 15:49:40 -0500 Subject: [PATCH 3/3] goimport for influxdb.go --- plugins/database/influxdb/influxdb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/database/influxdb/influxdb.go b/plugins/database/influxdb/influxdb.go index d17939cd4284..332617aeff8d 100644 --- a/plugins/database/influxdb/influxdb.go +++ b/plugins/database/influxdb/influxdb.go @@ -3,13 +3,13 @@ package influxdb import ( "context" "fmt" - "github.com/hashicorp/vault/sdk/helper/template" "strings" multierror "github.com/hashicorp/go-multierror" dbplugin "github.com/hashicorp/vault/sdk/database/dbplugin/v5" "github.com/hashicorp/vault/sdk/database/helper/dbutil" "github.com/hashicorp/vault/sdk/helper/strutil" + "github.com/hashicorp/vault/sdk/helper/template" influx "github.com/influxdata/influxdb/client/v2" )