Skip to content

Commit

Permalink
enable hierarchical path for dynamic roles and creds (#104)
Browse files Browse the repository at this point in the history
* adds poc with nested role listing

* add make configure

* update regex to honor previous contraints

* refactor static role tests

* add tests for static role read and list

* enable hierarchical path for static-cred endpoint

* enable hierarchical path for rotate-role endpoint

* address review comments

* update makefile and test checks

* enable hierarchical path for dynamic roles and creds

* use unexported regex helper name

* update test name

---------

Co-authored-by: Austin Gebauer <agebauer@hashicorp.com>
  • Loading branch information
fairclothjm and austingebauer committed May 10, 2024
1 parent 3273e17 commit 9d63d94
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 142 deletions.
9 changes: 6 additions & 3 deletions backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package openldap
import (
"context"
"errors"
"fmt"
"time"

"github.com/go-ldap/ldif"
Expand Down Expand Up @@ -85,8 +84,12 @@ func (f *fakeLdapClient) UpdateDNPassword(_ *client.Config, _ string, _ string)
return err
}

func (f *fakeLdapClient) Execute(_ *client.Config, _ []*ldif.Entry, _ bool) (err error) {
return fmt.Errorf("not implemented")
func (f *fakeLdapClient) Execute(_ *client.Config, _ []*ldif.Entry, _ bool) error {
var err error
if f.throwErrs {
err = errors.New("forced error")
}
return err
}

const validCertificate = `
Expand Down
3 changes: 2 additions & 1 deletion path_dynamic_creds.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package openldap
import (
"context"
"fmt"
"strings"
"time"

"github.com/go-ldap/ldif"
Expand All @@ -21,7 +22,7 @@ import (
func (b *backend) pathDynamicCredsCreate() []*framework.Path {
return []*framework.Path{
{
Pattern: dynamicCredPath + framework.GenericNameRegex("name"),
Pattern: strings.TrimSuffix(dynamicCredPath, "/") + genericNameWithForwardSlashRegex("name"),
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: operationPrefixLDAP,
OperationVerb: "request",
Expand Down
40 changes: 40 additions & 0 deletions path_dynamic_creds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,46 @@ func TestDynamicCredsRead_success(t *testing.T) {
}
}

func TestDynamicCredsRead_success_hierarchicalRolePath(t *testing.T) {
t.Run("read dynamic role creds with hierarchical role path", func(t *testing.T) {
b, storage := getBackend(false)
defer b.Cleanup(context.Background())
configureOpenLDAPMount(t, b, storage)

roles := []string{"org/secure", "org/platform/dev", "org/platform/support"}

// create all the roles
for _, role := range roles {
data := getTestDynamicRoleConfig(role)
resp, err := createDynamicRoleWithData(t, b, storage, role, data)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err:%s resp:%#v\n", err, resp)
}
}

// read all the creds
for _, rolePath := range roles {
req := &logical.Request{
Operation: logical.ReadOperation,
Path: dynamicCredPath + rolePath,
Storage: storage,
}
resp, err := b.HandleRequest(context.Background(), req)
require.NoError(t, err)

username := getStringT(t, resp.Data, "username")
require.NotEmpty(t, username)
require.Contains(t, username, rolePath)

password := getStringT(t, resp.Data, "password")
require.NotEmpty(t, password)

dns := getStringSlice(t, resp.Data, "distinguished_names")
require.Len(t, dns, 1)
}
})
}

func TestSecretCredsRenew(t *testing.T) {
roleName := "testrole"
now := time.Now()
Expand Down
15 changes: 11 additions & 4 deletions path_dynamic_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"context"
"encoding/base64"
"fmt"
"path"
"strings"
"time"

"github.com/go-ldap/ldif"
Expand All @@ -27,7 +27,7 @@ const (
func (b *backend) pathDynamicRoles() []*framework.Path {
return []*framework.Path{
{
Pattern: path.Join(dynamicRolePath, framework.GenericNameRegex("name")),
Pattern: strings.TrimSuffix(dynamicRolePath, "/") + genericNameWithForwardSlashRegex("name"),
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: operationPrefixLDAP,
OperationSuffix: "dynamic-role",
Expand Down Expand Up @@ -84,12 +84,18 @@ func (b *backend) pathDynamicRoles() []*framework.Path {
HelpDescription: staticRoleHelpDescription,
},
{
Pattern: dynamicRolePath + "?$",
Pattern: strings.TrimSuffix(dynamicRolePath, "/") + optionalGenericNameWithForwardSlashListRegex("path"),
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: operationPrefixLDAP,
OperationVerb: "list",
OperationSuffix: "dynamic-roles",
},
Fields: map[string]*framework.FieldSchema{
"path": {
Type: framework.TypeLowerCaseString,
Description: "Path of roles to list",
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.ListOperation: &framework.PathOperation{
Callback: b.pathDynamicRoleList,
Expand Down Expand Up @@ -286,7 +292,8 @@ func (b *backend) pathDynamicRoleRead(ctx context.Context, req *logical.Request,
}

func (b *backend) pathDynamicRoleList(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
roles, err := req.Storage.List(ctx, dynamicRolePath)
rolePath := data.Get("path").(string)
roles, err := req.Storage.List(ctx, dynamicRolePath+rolePath)
if err != nil {
return nil, fmt.Errorf("failed to list roles: %w", err)
}
Expand Down

0 comments on commit 9d63d94

Please sign in to comment.