From 5f42e2560ad661dca69ebef1f99c9f748bacdbce Mon Sep 17 00:00:00 2001 From: MilenaHC <85197148+MilenaHC@users.noreply.github.com> Date: Wed, 9 Jun 2021 16:08:59 -0500 Subject: [PATCH] InfluxDB - Add username customization (#11796) * Add username_template to influxdb * go fmt * goimport for influxdb.go --- plugins/database/influxdb/influxdb.go | 40 +++++++++++++----- plugins/database/influxdb/influxdb_test.go | 47 ++++++++++++++++++++-- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/plugins/database/influxdb/influxdb.go b/plugins/database/influxdb/influxdb.go index c8d0cc157c437..332617aeff8dc 100644 --- a/plugins/database/influxdb/influxdb.go +++ b/plugins/database/influxdb/influxdb.go @@ -7,9 +7,9 @@ import ( 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" + "github.com/hashicorp/vault/sdk/helper/template" 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 5328996927d40..93530ec94a9b3 100644 --- a/plugins/database/influxdb/influxdb_test.go +++ b/plugins/database/influxdb/influxdb_test.go @@ -15,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}}";` @@ -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,46 @@ 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}, + }, + 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, `^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}, @@ -250,6 +289,8 @@ func TestInfluxdb_CreateUser(t *testing.T) { } 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) {