forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
vault: Passthrough backend uses logical.Backend
- Loading branch information
Showing
7 changed files
with
398 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package logical | ||
|
||
import ( | ||
"strings" | ||
"sync" | ||
) | ||
|
||
// InmemStorage implements Storage and stores all data in memory. | ||
type InmemStorage struct { | ||
Data map[string]*StorageEntry | ||
|
||
once sync.Once | ||
} | ||
|
||
func (s *InmemStorage) List(prefix string) ([]string, error) { | ||
s.once.Do(s.init) | ||
|
||
var result []string | ||
for k, _ := range s.Data { | ||
if strings.HasPrefix(k, prefix) { | ||
result = append(result, k) | ||
} | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
func (s *InmemStorage) Get(key string) (*StorageEntry, error) { | ||
s.once.Do(s.init) | ||
return s.Data[key], nil | ||
} | ||
|
||
func (s *InmemStorage) Put(entry *StorageEntry) error { | ||
s.once.Do(s.init) | ||
s.Data[entry.Key] = entry | ||
return nil | ||
} | ||
|
||
func (s *InmemStorage) Delete(k string) error { | ||
s.once.Do(s.init) | ||
delete(s.Data, k) | ||
return nil | ||
} | ||
|
||
func (s *InmemStorage) init() { | ||
s.Data = make(map[string]*StorageEntry) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package logical | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestInmemStorage(t *testing.T) { | ||
TestStorage(t, new(InmemStorage)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package logical | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
// TestRequest is a helper to create a purely in-memory Request struct. | ||
func TestRequest(t *testing.T, op Operation, path string) *Request { | ||
return &Request{ | ||
Operation: op, | ||
Path: path, | ||
Data: make(map[string]interface{}), | ||
Storage: new(InmemStorage), | ||
} | ||
} | ||
|
||
// TestStorage is a helper that can be used from unit tests to verify | ||
// the behavior of a Storage impl. | ||
func TestStorage(t *testing.T, s Storage) { | ||
keys, err := s.List("") | ||
if err != nil { | ||
t.Fatalf("list error: %s", err) | ||
} | ||
if len(keys) > 0 { | ||
t.Fatalf("should have no keys to start: %#v", keys) | ||
} | ||
|
||
entry := &StorageEntry{Key: "foo", Value: []byte("bar")} | ||
if err := s.Put(entry); err != nil { | ||
t.Fatalf("put error: %s", err) | ||
} | ||
|
||
actual, err := s.Get("foo") | ||
if err != nil { | ||
t.Fatalf("get error: %s", err) | ||
} | ||
if !reflect.DeepEqual(actual, entry) { | ||
t.Fatalf("wrong value. Expected: %#v\nGot: %#v", entry, actual) | ||
} | ||
|
||
keys, err = s.List("") | ||
if err != nil { | ||
t.Fatalf("list error: %s", err) | ||
} | ||
if !reflect.DeepEqual(keys, []string{"foo"}) { | ||
t.Fatalf("bad keys: %#v", keys) | ||
} | ||
|
||
if err := s.Delete("foo"); err != nil { | ||
t.Fatalf("put error: %s", err) | ||
} | ||
|
||
keys, err = s.List("") | ||
if err != nil { | ||
t.Fatalf("list error: %s", err) | ||
} | ||
if len(keys) > 0 { | ||
t.Fatalf("should have no keys to start: %#v", keys) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package vault | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/hashicorp/vault/logical" | ||
) | ||
|
||
// PassthroughBackend is used storing secrets directly into the physical | ||
// backend. The secrest are encrypted in the durable storage and custom lease | ||
// information can be specified, but otherwise this backend doesn't do anything | ||
// fancy. | ||
type PassthroughBackend struct{} | ||
|
||
func (b *PassthroughBackend) HandleRequest(req *logical.Request) (*logical.Response, error) { | ||
// TODO(mitchellh): help, let's just do it when we migrate to helper/backend | ||
|
||
switch req.Operation { | ||
case logical.ReadOperation: | ||
return b.handleRead(req) | ||
case logical.WriteOperation: | ||
return b.handleWrite(req) | ||
case logical.DeleteOperation: | ||
return b.handleDelete(req) | ||
case logical.ListOperation: | ||
return b.handleList(req) | ||
default: | ||
return nil, ErrUnsupportedOperation | ||
} | ||
} | ||
|
||
func (b *PassthroughBackend) RootPaths() []string { | ||
return nil | ||
} | ||
|
||
func (b *PassthroughBackend) handleRead(req *logical.Request) (*logical.Response, error) { | ||
// Read the path | ||
out, err := req.Storage.Get(req.Path) | ||
if err != nil { | ||
return nil, fmt.Errorf("read failed: %v", err) | ||
} | ||
|
||
// Fast-path the no data case | ||
if out == nil { | ||
return nil, nil | ||
} | ||
|
||
// Decode the data | ||
var raw map[string]interface{} | ||
if err := json.Unmarshal(out.Value, &raw); err != nil { | ||
return nil, fmt.Errorf("json decoding failed: %v", err) | ||
} | ||
|
||
// Check if there is a lease key | ||
leaseVal, ok := raw["lease"].(string) | ||
var lease *logical.Lease | ||
if ok { | ||
leaseDuration, err := time.ParseDuration(leaseVal) | ||
if err == nil { | ||
lease = &logical.Lease{ | ||
Renewable: false, | ||
Revokable: false, | ||
Duration: leaseDuration, | ||
MaxDuration: leaseDuration, | ||
MaxIncrement: 0, | ||
} | ||
} | ||
} | ||
|
||
// Generate the response | ||
resp := &logical.Response{ | ||
IsSecret: true, | ||
Lease: lease, | ||
Data: raw, | ||
} | ||
return resp, nil | ||
} | ||
|
||
func (b *PassthroughBackend) handleWrite(req *logical.Request) (*logical.Response, error) { | ||
// Check that some fields are given | ||
if len(req.Data) == 0 { | ||
return nil, fmt.Errorf("missing data fields") | ||
} | ||
|
||
// JSON encode the data | ||
buf, err := json.Marshal(req.Data) | ||
if err != nil { | ||
return nil, fmt.Errorf("json encoding failed: %v", err) | ||
} | ||
|
||
// Write out a new key | ||
entry := &logical.StorageEntry{ | ||
Key: req.Path, | ||
Value: buf, | ||
} | ||
if err := req.Storage.Put(entry); err != nil { | ||
return nil, fmt.Errorf("failed to write: %v", err) | ||
} | ||
|
||
return nil, nil | ||
} | ||
|
||
func (b *PassthroughBackend) handleDelete(req *logical.Request) (*logical.Response, error) { | ||
// Delete the key at the request path | ||
if err := req.Storage.Delete(req.Path); err != nil { | ||
return nil, err | ||
} | ||
|
||
return nil, nil | ||
} | ||
|
||
func (b *PassthroughBackend) handleList(req *logical.Request) (*logical.Response, error) { | ||
// List the keys at the prefix given by the request | ||
keys, err := req.Storage.List(req.Path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Generate the response | ||
return logical.ListResponse(keys), nil | ||
} |
Oops, something went wrong.