From 1e76ad42ef4221cb8a58e050d2edbfc552a878a0 Mon Sep 17 00:00:00 2001 From: John-Michael Faircloth Date: Tue, 19 Sep 2023 10:12:09 -0500 Subject: [PATCH] secrets/db: add tests for static role config updates (#23153) --- builtin/logical/database/path_roles.go | 12 +-- builtin/logical/database/path_roles_test.go | 106 ++++++++++++++++++++ 2 files changed, 111 insertions(+), 7 deletions(-) diff --git a/builtin/logical/database/path_roles.go b/builtin/logical/database/path_roles.go index b135eaf3d6..fd09414798 100644 --- a/builtin/logical/database/path_roles.go +++ b/builtin/logical/database/path_roles.go @@ -560,8 +560,7 @@ func (b *databaseBackend) pathStaticRoleCreateUpdate(ctx context.Context, req *l role.StaticAccount.Username = username rotationPeriodSecondsRaw, rotationPeriodOk := data.GetOk("rotation_period") - rotationSchedule := data.Get("rotation_schedule").(string) - rotationScheduleOk := rotationSchedule != "" + rotationScheduleRaw, rotationScheduleOk := data.GetOk("rotation_schedule") rotationWindowSecondsRaw, rotationWindowOk := data.GetOk("rotation_window") if rotationScheduleOk && rotationPeriodOk { @@ -591,6 +590,7 @@ func (b *databaseBackend) pathStaticRoleCreateUpdate(ctx context.Context, req *l } if rotationScheduleOk { + rotationSchedule := rotationScheduleRaw.(string) parsedSchedule, err := b.schedule.Parse(rotationSchedule) if err != nil { return logical.ErrorResponse("could not parse rotation_schedule", "error", err), nil @@ -683,15 +683,13 @@ func (b *databaseBackend) pathStaticRoleCreateUpdate(ctx context.Context, req *l } } - _, rotationPeriodChanged := data.Raw["rotation_period"] - _, rotationScheduleChanged := data.Raw["rotation_schedule"] - if rotationPeriodChanged { + if rotationPeriodOk { b.logger.Debug("init priority for RotationPeriod", "lvr", lvr, "next", lvr.Add(role.StaticAccount.RotationPeriod)) item.Priority = lvr.Add(role.StaticAccount.RotationPeriod).Unix() - } else if rotationScheduleChanged { + } else if rotationScheduleOk { next := role.StaticAccount.Schedule.Next(lvr) b.logger.Debug("init priority for Schedule", "lvr", lvr, "next", next) - item.Priority = role.StaticAccount.Schedule.Next(lvr).Unix() + item.Priority = next.Unix() } // Add their rotation to the queue diff --git a/builtin/logical/database/path_roles_test.go b/builtin/logical/database/path_roles_test.go index 87dcc0cdb3..865304a1b9 100644 --- a/builtin/logical/database/path_roles_test.go +++ b/builtin/logical/database/path_roles_test.go @@ -842,6 +842,112 @@ func TestBackend_StaticRole_Updates(t *testing.T) { } } +func TestBackend_StaticRole_Updates_RotationSchedule(t *testing.T) { + ctx := context.Background() + b, storage, mockDB := getBackend(t) + defer b.Cleanup(ctx) + configureDBMount(t, storage) + + data := map[string]interface{}{ + "name": "plugin-role-test-updates", + "db_name": "mockv5", + "rotation_statements": testRoleStaticUpdate, + "username": dbUser, + "rotation_schedule": "0 0 */2 * * *", + "rotation_window": "1h", + } + + mockDB.On("UpdateUser", mock.Anything, mock.Anything). + Return(v5.UpdateUserResponse{}, nil). + Once() + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "static-roles/plugin-role-test-updates", + Storage: storage, + 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 role + data = map[string]interface{}{} + req = &logical.Request{ + Operation: logical.ReadOperation, + Path: "static-roles/plugin-role-test-updates", + Storage: storage, + 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) + } + + rotation := resp.Data["rotation_schedule"].(string) + window := resp.Data["rotation_window"].(float64) + + // update rotation_schedule and window + updateData := map[string]interface{}{ + "name": "plugin-role-test-updates", + "db_name": "mockv5", + "username": dbUser, + "rotation_schedule": "0 0 */1 * * *", + "rotation_window": "2h", + } + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "static-roles/plugin-role-test-updates", + Storage: storage, + Data: updateData, + } + resp, err = b.HandleRequest(namespace.RootContext(nil), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + // re-read the role + data = map[string]interface{}{} + req = &logical.Request{ + Operation: logical.ReadOperation, + Path: "static-roles/plugin-role-test-updates", + Storage: storage, + 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) + } + + newRotation := resp.Data["rotation_schedule"].(string) + if newRotation == rotation { + t.Fatalf("expected change in rotation, but got old value: %#v", newRotation) + } + newWindow := resp.Data["rotation_window"].(float64) + if newWindow == window { + t.Fatalf("expected change in rotation_window, but got old value: %#v", newWindow) + } + + // verify that rotation_schedule is only required when creating + updateData = map[string]interface{}{ + "name": "plugin-role-test-updates", + "db_name": "mockv5", + "username": dbUser, + "rotation_statements": testRoleStaticUpdateRotation, + } + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "static-roles/plugin-role-test-updates", + Storage: storage, + Data: updateData, + } + + 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_Role_name_check(t *testing.T) { cluster, sys := getCluster(t) defer cluster.Cleanup()