mirror of
https://github.com/hashicorp/vault.git
synced 2025-11-30 07:01:14 +01:00
logical/framework: PathMap can get missing things
This commit is contained in:
parent
790d61c1ca
commit
10425cdb8a
105
logical/framework/path_map.go
Normal file
105
logical/framework/path_map.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PathMap can be used to generate a path that stores mappings in the
|
||||||
|
// storage. It is a structure that also exports functions for querying the
|
||||||
|
// mappings.
|
||||||
|
//
|
||||||
|
// The primary use case for this is for credential providers to do their
|
||||||
|
// mapping to policies.
|
||||||
|
type PathMap struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get reads a value out of the mapping
|
||||||
|
func (p *PathMap) Get(s logical.Storage, k string) (string, error) {
|
||||||
|
entry, err := s.Get(fmt.Sprintf("map/%s/%s", p.Name, k))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if entry == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(entry.Value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put writes a value into the mapping
|
||||||
|
func (p *PathMap) Put(s logical.Storage, k string, v string) error {
|
||||||
|
return s.Put(&logical.StorageEntry{
|
||||||
|
Key: fmt.Sprintf("map/%s/%s", p.Name, k),
|
||||||
|
Value: []byte(v),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paths are the paths to append to the Backend paths.
|
||||||
|
func (p *PathMap) Paths() []*Path {
|
||||||
|
return []*Path{
|
||||||
|
&Path{
|
||||||
|
Pattern: fmt.Sprintf("map/%s$", p.Name),
|
||||||
|
|
||||||
|
Callbacks: map[logical.Operation]OperationFunc{
|
||||||
|
logical.ListOperation: p.pathList,
|
||||||
|
logical.ReadOperation: p.pathList,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
&Path{
|
||||||
|
Pattern: fmt.Sprintf("map/%s/(?P<key>\\w+)", p.Name),
|
||||||
|
|
||||||
|
Fields: map[string]*FieldSchema{
|
||||||
|
"key": &FieldSchema{
|
||||||
|
Type: TypeString,
|
||||||
|
Description: "Key for the mapping",
|
||||||
|
},
|
||||||
|
|
||||||
|
"value": &FieldSchema{
|
||||||
|
Type: TypeString,
|
||||||
|
Description: "Value for the mapping",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Callbacks: map[logical.Operation]OperationFunc{
|
||||||
|
logical.WriteOperation: p.pathSingleWrite,
|
||||||
|
logical.ReadOperation: p.pathSingleRead,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PathMap) pathList(
|
||||||
|
req *logical.Request, d *FieldData) (*logical.Response, error) {
|
||||||
|
keys, err := req.Storage.List(req.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return logical.ListResponse(keys), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PathMap) pathSingleRead(
|
||||||
|
req *logical.Request, d *FieldData) (*logical.Response, error) {
|
||||||
|
v, err := p.Get(req.Storage, d.Get("key").(string))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &logical.Response{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"value": v,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PathMap) pathSingleWrite(
|
||||||
|
req *logical.Request, d *FieldData) (*logical.Response, error) {
|
||||||
|
err := p.Put(
|
||||||
|
req.Storage,
|
||||||
|
d.Get("key").(string), d.Get("value").(string))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
61
logical/framework/path_map_test.go
Normal file
61
logical/framework/path_map_test.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPathMap(t *testing.T) {
|
||||||
|
p := &PathMap{Name: "foo"}
|
||||||
|
storage := new(logical.InmemStorage)
|
||||||
|
var b logical.Backend = &Backend{Paths: p.Paths()}
|
||||||
|
|
||||||
|
// Write via HTTP
|
||||||
|
_, err := b.HandleRequest(&logical.Request{
|
||||||
|
Operation: logical.WriteOperation,
|
||||||
|
Path: "map/foo/a",
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"value": "bar",
|
||||||
|
},
|
||||||
|
Storage: storage,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read via HTTP
|
||||||
|
resp, err := b.HandleRequest(&logical.Request{
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
Path: "map/foo/a",
|
||||||
|
Storage: storage,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %#v", err)
|
||||||
|
}
|
||||||
|
if resp.Data["value"] != "bar" {
|
||||||
|
t.Fatalf("bad: %#v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read via API
|
||||||
|
v, err := p.Get(storage, "a")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %#v", err)
|
||||||
|
}
|
||||||
|
if v != "bar" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathMap_getInvalid(t *testing.T) {
|
||||||
|
p := &PathMap{Name: "foo"}
|
||||||
|
storage := new(logical.InmemStorage)
|
||||||
|
|
||||||
|
v, err := p.Get(storage, "nope")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %#v", err)
|
||||||
|
}
|
||||||
|
if v != "" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user