From 83da570609c535dc59e31e31df4ab534b98b582d Mon Sep 17 00:00:00 2001 From: JM Faircloth Date: Fri, 3 May 2024 15:48:57 -0500 Subject: [PATCH] enable hierarchical path for static-cred endpoint --- path_static_creds.go | 3 +- path_static_creds_test.go | 148 +++++++++++++++++--------------------- path_static_roles_test.go | 28 +++----- 3 files changed, 80 insertions(+), 99 deletions(-) diff --git a/path_static_creds.go b/path_static_creds.go index 7788d2a..2cfb89d 100644 --- a/path_static_creds.go +++ b/path_static_creds.go @@ -5,6 +5,7 @@ package openldap import ( "context" + "strings" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" @@ -15,7 +16,7 @@ const staticCredPath = "static-cred/" func (b *backend) pathStaticCredsCreate() []*framework.Path { return []*framework.Path{ { - Pattern: staticCredPath + framework.GenericNameRegex("name"), + Pattern: strings.TrimSuffix(staticCredPath, "/") + GenericNameWithForwardSlashRegex("name"), DisplayAttrs: &framework.DisplayAttributes{ OperationPrefix: operationPrefixLDAP, OperationVerb: "request", diff --git a/path_static_creds_test.go b/path_static_creds_test.go index e3e9c91..4022fdb 100644 --- a/path_static_creds_test.go +++ b/path_static_creds_test.go @@ -14,90 +14,39 @@ func TestCreds(t *testing.T) { t.Run("happy path with creds", func(t *testing.T) { b, storage := getBackend(false) defer b.Cleanup(context.Background()) + configureOpenLDAPMount(t, b, storage) data := map[string]interface{}{ - "binddn": "tester", - "bindpass": "pa$$w0rd", - "url": "ldap://138.91.247.105", - "certificate": validCertificate, - } - - req := &logical.Request{ - Operation: logical.CreateOperation, - Path: configPath, - Storage: storage, - Data: data, - } - - resp, err := b.HandleRequest(context.Background(), req) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("err:%s resp:%#v\n", err, resp) - } - - data = map[string]interface{}{ "username": "hashicorp", "dn": "uid=hashicorp,ou=users,dc=hashicorp,dc=com", - "rotation_period": "60s", - } - - req = &logical.Request{ - Operation: logical.CreateOperation, - Path: staticRolePath + "hashicorp", - Storage: storage, - Data: data, + "rotation_period": float64(60), } - resp, err = b.HandleRequest(context.Background(), req) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("err:%s resp:%#v\n", err, resp) - } - - req = &logical.Request{ - Operation: logical.ReadOperation, - Path: staticRolePath + "hashicorp", - Storage: storage, - Data: nil, - } - - resp, err = b.HandleRequest(context.Background(), req) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("err:%s resp:%#v\n", err, resp) - } - - req = &logical.Request{ - Operation: logical.ReadOperation, - Path: staticCredPath + "hashicorp", - Storage: storage, - Data: nil, - } - - resp, err = b.HandleRequest(context.Background(), req) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("err:%s resp:%#v\n", err, resp) - } - - if resp.Data["dn"] == "" { - t.Fatal("expected dn to be set, it wasn't") - } - - if resp.Data["password"] == "" { - t.Fatal("expected password to be set, it wasn't") - } + roleName := "hashicorp" + createStaticRoleWithData(t, b, storage, roleName, data) + assertReadStaticCred(t, b, storage, roleName, data) + }) - if resp.Data["username"] == "" { - t.Fatal("expected username to be set, it wasn't") - } + t.Run("happy path with hierarchical cred path", func(t *testing.T) { + b, storage := getBackend(false) + defer b.Cleanup(context.Background()) + configureOpenLDAPMount(t, b, storage) - if resp.Data["last_vault_rotation"] == nil { - t.Fatal("expected last_vault_rotation to be set, it wasn't") - } + roles := []string{"org/secure", "org/platform/dev", "org/platform/support"} - if resp.Data["rotation_period"] != float64(60) { - t.Fatalf("expected rotation_period to be %f, got %f", float64(60), resp.Data["rotation_period"]) + // create all the roles + for _, role := range roles { + data := getTestStaticRoleConfig(role) + resp, err := createStaticRoleWithData(t, b, storage, role, data) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } } - if resp.Data["ttl"] == nil { - t.Fatal("expected ttl to be set, it wasn't") + // read all the creds + for _, role := range roles { + data := getTestStaticRoleConfig(role) + assertReadStaticCred(t, b, storage, role, data) } }) @@ -105,14 +54,7 @@ func TestCreds(t *testing.T) { b, storage := getBackend(false) defer b.Cleanup(context.Background()) - req := &logical.Request{ - Operation: logical.ReadOperation, - Path: staticCredPath + "hashicorp", - Storage: storage, - Data: nil, - } - - resp, err := b.HandleRequest(context.Background(), req) + resp, err := readStaticCred(t, b, storage, "hashicorp") if err != nil { t.Fatalf("error reading cred: %s", err) } @@ -121,3 +63,47 @@ func TestCreds(t *testing.T) { } }) } + +func readStaticCred(t *testing.T, b *backend, storage logical.Storage, roleName string) (*logical.Response, error) { + req := &logical.Request{ + Operation: logical.ReadOperation, + Path: staticCredPath + roleName, + Storage: storage, + Data: nil, + } + + return b.HandleRequest(context.Background(), req) +} + +func assertReadStaticCred(t *testing.T, b *backend, storage logical.Storage, roleName string, data map[string]interface{}) { + t.Helper() + resp, err := readStaticCred(t, b, storage, roleName) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + if resp.Data["dn"] != data["dn"] { + t.Fatalf("expected dn to be %s but got %s", data["dn"], resp.Data["dn"]) + } + + if resp.Data["password"] == "" { + t.Fatal("expected password to be set, it wasn't") + } + + if resp.Data["username"] != data["username"] { + t.Fatalf("expected username to be %s but got %s", data["username"], resp.Data["username"]) + } + + if resp.Data["last_vault_rotation"] == nil { + t.Fatal("expected last_vault_rotation to be set, it wasn't") + } + + expected := data["rotation_period"].(float64) + if resp.Data["rotation_period"] != expected { + t.Fatalf("expected rotation_period to be %f but got %s", expected, resp.Data["rotation_period"]) + } + + if resp.Data["ttl"] == nil { + t.Fatal("expected ttl to be set, it wasn't") + } +} diff --git a/path_static_roles_test.go b/path_static_roles_test.go index 90eee96..170317e 100644 --- a/path_static_roles_test.go +++ b/path_static_roles_test.go @@ -221,17 +221,10 @@ func TestRoles(t *testing.T) { configureOpenLDAPMount(t, b, storage) roles := []string{"org/secure", "org/platform/dev", "org/platform/support"} - getData := func(name string) map[string]interface{} { - return map[string]interface{}{ - "username": name, - "dn": "uid=hashicorp,ou=users,dc=hashicorp,dc=com", - "rotation_period": float64(5), - } - } // create all the roles for _, role := range roles { - data := getData(role) + data := getTestStaticRoleConfig(role) resp, err := createStaticRoleWithData(t, b, storage, role, data) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%s resp:%#v\n", err, resp) @@ -240,7 +233,7 @@ func TestRoles(t *testing.T) { // read all the roles for _, role := range roles { - data := getData(role) + data := getTestStaticRoleConfig(role) assertReadStaticRole(t, b, storage, role, data) } }) @@ -494,17 +487,10 @@ func TestListRoles(t *testing.T) { configureOpenLDAPMount(t, b, storage) roles := []string{"org/secure", "org/platform/dev", "org/platform/support"} - getData := func(name string) map[string]interface{} { - return map[string]interface{}{ - "username": name, - "dn": "uid=hashicorp,ou=users,dc=hashicorp,dc=com", - "rotation_period": float64(5), - } - } // create all the roles for _, role := range roles { - data := getData(role) + data := getTestStaticRoleConfig(role) resp, err := createStaticRoleWithData(t, b, storage, role, data) if err != nil || (resp != nil && resp.IsError()) { t.Fatalf("err:%s resp:%#v\n", err, resp) @@ -736,3 +722,11 @@ func assertReadStaticRole(t *testing.T, b *backend, storage logical.Storage, rol t.Fatal("expected last_vault_rotation to not be empty") } } + +func getTestStaticRoleConfig(name string) map[string]interface{} { + return map[string]interface{}{ + "username": name, + "dn": "uid=hashicorp,ou=users,dc=hashicorp,dc=com", + "rotation_period": float64(5), + } +}