MSSQL - Add username customization (#10767)

This commit is contained in:
Michael Golowka
2021-02-05 11:14:24 -07:00
committed by GitHub
parent 5299c2d09b
commit 5436e75b54
3 changed files with 53 additions and 26 deletions

View File

@@ -12,19 +12,25 @@ import (
multierror "github.com/hashicorp/go-multierror"
dbplugin "github.com/hashicorp/vault/sdk/database/dbplugin/v5"
"github.com/hashicorp/vault/sdk/database/helper/connutil"
"github.com/hashicorp/vault/sdk/database/helper/credsutil"
"github.com/hashicorp/vault/sdk/database/helper/dbutil"
"github.com/hashicorp/vault/sdk/helper/dbtxn"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/helper/template"
)
const msSQLTypeName = "mssql"
const (
msSQLTypeName = "mssql"
defaultUserNameTemplate = `{{ printf "v-%s-%s-%s-%s" (.DisplayName | truncate 20) (.RoleName | truncate 20) (random 20) (unix_time) | truncate 128 }}`
)
var _ dbplugin.Database = &MSSQL{}
// MSSQL is an implementation of Database interface
type MSSQL struct {
*connutil.SQLConnectionProducer
usernameProducer template.StringTemplate
}
func New() (interface{}, error) {
@@ -69,6 +75,26 @@ func (m *MSSQL) Initialize(ctx context.Context, req dbplugin.InitializeRequest)
if err != nil {
return dbplugin.InitializeResponse{}, err
}
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)
}
m.usernameProducer = up
_, err = m.usernameProducer.Generate(dbplugin.UsernameMetadata{})
if err != nil {
return dbplugin.InitializeResponse{}, fmt.Errorf("invalid username template - did you reference a field that isn't available? : %w", err)
}
resp := dbplugin.InitializeResponse{
Config: newConf,
}
@@ -90,12 +116,7 @@ func (m *MSSQL) NewUser(ctx context.Context, req dbplugin.NewUserRequest) (dbplu
return dbplugin.NewUserResponse{}, dbutil.ErrEmptyCreationStatement
}
username, err := credsutil.GenerateUsername(
credsutil.DisplayName(req.UsernameConfig.DisplayName, 20),
credsutil.RoleName(req.UsernameConfig.RoleName, 20),
credsutil.MaxLength(128),
credsutil.Separator("-"),
)
username, err := m.usernameProducer.Generate(req.UsernameConfig)
if err != nil {
return dbplugin.NewUserResponse{}, err
}

View File

@@ -62,10 +62,11 @@ func TestNewUser(t *testing.T) {
defer cleanup()
type testCase struct {
req dbplugin.NewUserRequest
usernameRegex string
expectErr bool
assertUser func(t testing.TB, connURL, username, password string)
usernameTemplate string
req dbplugin.NewUserRequest
usernameRegex string
expectErr bool
assertUser func(t testing.TB, connURL, username, password string)
}
tests := map[string]testCase{
@@ -99,6 +100,23 @@ func TestNewUser(t *testing.T) {
expectErr: false,
assertUser: assertCredsExist,
},
"custom username template": {
usernameTemplate: "{{random 10}}_{{.RoleName}}.{{.DisplayName | sha256}}",
req: dbplugin.NewUserRequest{
UsernameConfig: dbplugin.UsernameMetadata{
DisplayName: "tokenwithlotsofextracharactershere",
RoleName: "myrolenamewithlotsofextracharacters",
},
Statements: dbplugin.Statements{
Commands: []string{testMSSQLRole},
},
Password: "AG4qagho-dsvZ",
Expiration: time.Now().Add(1 * time.Second),
},
usernameRegex: "^[a-zA-Z0-9]{10}_myrolenamewithlotsofextracharacters.80d15d22dba29ddbd4994f8009b5ff7b17922c267eb49fb805a9488bd55d11f9$",
expectErr: false,
assertUser: assertCredsExist,
},
}
for name, test := range tests {
@@ -110,7 +128,8 @@ func TestNewUser(t *testing.T) {
initReq := dbplugin.InitializeRequest{
Config: map[string]interface{}{
"connection_url": connURL,
"connection_url": connURL,
"username_template": test.usernameTemplate,
},
VerifyConnection: true,
}