logical/framework: PathMap can get missing things

This commit is contained in:
Mitchell Hashimoto 2015-04-01 14:51:13 -07:00
parent 4138e43f00
commit 83de0fd03d
2 changed files with 166 additions and 0 deletions

View 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
}

View 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)
}
}