Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit test for static-creds read endpoint #22505

Merged
merged 1 commit into from
Aug 22, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions builtin/logical/database/path_roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,186 @@ func TestBackend_StaticRole_Config(t *testing.T) {
}
}

func TestBackend_StaticRole_ReadCreds(t *testing.T) {
cluster, sys := getCluster(t)
defer cluster.Cleanup()

config := logical.TestBackendConfig()
config.StorageView = &logical.InmemStorage{}
config.System = sys

lb, err := Factory(context.Background(), config)
if err != nil {
t.Fatal(err)
}
b, ok := lb.(*databaseBackend)
if !ok {
t.Fatal("could not convert to db backend")
}
defer b.Cleanup(context.Background())

cleanup, connURL := postgreshelper.PrepareTestContainer(t, "")
defer cleanup()

// create the database user
createTestPGUser(t, connURL, dbUser, dbUserDefaultPassword, testRoleStaticCreate)

verifyPgConn(t, dbUser, dbUserDefaultPassword, connURL)

// Configure a connection
data := map[string]interface{}{
"connection_url": connURL,
"plugin_name": "postgresql-database-plugin",
"verify_connection": false,
"allowed_roles": []string{"*"},
"name": "plugin-test",
}

req := &logical.Request{
Operation: logical.UpdateOperation,
Path: "config/plugin-test",
Storage: config.StorageView,
Data: data,
}
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err:%s resp:%#v\n", err, resp)
}

testCases := map[string]struct {
account map[string]interface{}
path string
expected map[string]interface{}
}{
"happy path for rotation_period": {
account: map[string]interface{}{
"username": dbUser,
"rotation_period": "5400s",
},
path: "plugin-role-test",
expected: map[string]interface{}{
"username": dbUser,
"rotation_period": float64(5400),
},
},
"happy path for rotation_schedule": {
account: map[string]interface{}{
"username": dbUser,
"rotation_schedule": "* * * * *",
},
path: "plugin-role-test",
expected: map[string]interface{}{
"username": dbUser,
"rotation_schedule": "* * * * *",
},
},
"happy path for rotation_schedule and rotation_window": {
account: map[string]interface{}{
"username": dbUser,
"rotation_schedule": "* * * * *",
"rotation_window": "3600s",
},
path: "plugin-role-test",
expected: map[string]interface{}{
"username": dbUser,
"rotation_schedule": "* * * * *",
"rotation_window": float64(3600),
},
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
data = map[string]interface{}{
"name": "plugin-role-test",
"db_name": "plugin-test",
"rotation_statements": testRoleStaticUpdate,
"username": dbUser,
}

for k, v := range tc.account {
data[k] = v
}

req = &logical.Request{
Operation: logical.CreateOperation,
Path: "static-roles/plugin-role-test",
Storage: config.StorageView,
Data: data,
}

resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err:%s resp:%#v\n", err, resp)
}

// Read the creds
data = map[string]interface{}{}
req = &logical.Request{
Operation: logical.ReadOperation,
Path: "static-creds/plugin-role-test",
Storage: config.StorageView,
Data: data,
}

resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err:%s resp:%#v\n", err, resp)
}

expected := tc.expected
actual := make(map[string]interface{})
dataKeys := []string{
"username",
"password",
"last_vault_rotation",
"rotation_period",
"rotation_schedule",
"rotation_window",
"ttl",
}
for _, key := range dataKeys {
if v, ok := resp.Data[key]; ok {
actual[key] = v
}
}

if len(tc.expected) > 0 {
// verify a password is returned, but we don't care what it's value is
if actual["password"] == "" {
t.Fatalf("expected result to contain password, but none found")
}
if actual["ttl"] == "" {
t.Fatalf("expected result to contain ttl, but none found")
}
if v, ok := actual["last_vault_rotation"].(time.Time); !ok {
t.Fatalf("expected last_vault_rotation to be set to time.Time type, got: %#v", v)
}

// delete these values before the comparison, since we can't know them in
// advance
delete(actual, "password")
delete(actual, "ttl")
delete(actual, "last_vault_rotation")
if diff := deep.Equal(expected, actual); diff != nil {
t.Fatal(diff)
}
}

// Delete role for next run
req = &logical.Request{
Operation: logical.DeleteOperation,
Path: "static-roles/plugin-role-test",
Storage: config.StorageView,
}
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err:%s resp:%#v\n", err, resp)
}
})
}
}

func TestBackend_StaticRole_Updates(t *testing.T) {
cluster, sys := getCluster(t)
defer cluster.Cleanup()
Expand Down