open-vault/vault/logical_cubbyhole_test.go
Jeff Mitchell 77e7379ab5 Implement the cubbyhole backend
In order to implement this efficiently, I have introduced the concept of
"singleton" backends -- currently, 'sys' and 'cubbyhole'. There isn't
much reason to allow sys to be mounted at multiple places, and there
isn't much reason you'd need multiple per-token storage areas. By
restricting it to just one, I can store that particular mount instead of
iterating through them in order to call the appropriate revoke function.

Additionally, because revocation on the backend needs to be triggered by
the token store, the token store's salt is kept in the router and
client tokens going to the cubbyhole backend are double-salted by the
router. This allows the token store to drive when revocation happens
using its salted tokens.
2015-09-15 13:50:37 -04:00

257 lines
5.9 KiB
Go

package vault
import (
"reflect"
"sort"
"testing"
"time"
"github.com/hashicorp/vault/helper/uuid"
"github.com/hashicorp/vault/logical"
)
func TestCubbyholeBackend_RootPaths(t *testing.T) {
b := testCubbyholeBackend()
root := b.SpecialPaths()
if root != nil {
t.Fatalf("unexpected: %v", root)
}
}
func TestCubbyholeBackend_Write(t *testing.T) {
b := testCubbyholeBackend()
req := logical.TestRequest(t, logical.WriteOperation, "foo")
clientToken := uuid.GenerateUUID()
req.ClientToken = clientToken
storage := req.Storage
req.Data["raw"] = "test"
resp, err := b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %v", resp)
}
req = logical.TestRequest(t, logical.ReadOperation, "foo")
req.Storage = storage
req.ClientToken = clientToken
_, err = b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
}
func TestCubbyholeBackend_Read(t *testing.T) {
b := testCubbyholeBackend()
req := logical.TestRequest(t, logical.WriteOperation, "foo")
req.Data["raw"] = "test"
storage := req.Storage
clientToken := uuid.GenerateUUID()
req.ClientToken = clientToken
if _, err := b.HandleRequest(req); err != nil {
t.Fatalf("err: %v", err)
}
req = logical.TestRequest(t, logical.ReadOperation, "foo")
req.Storage = storage
req.ClientToken = clientToken
resp, err := b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
expected := &logical.Response{
Data: map[string]interface{}{
"raw": "test",
},
}
if !reflect.DeepEqual(resp, expected) {
t.Fatalf("bad response.\n\nexpected: %#v\n\nGot: %#v", expected, resp)
}
}
func TestCubbyholeBackend_Delete(t *testing.T) {
b := testCubbyholeBackend()
req := logical.TestRequest(t, logical.WriteOperation, "foo")
req.Data["raw"] = "test"
storage := req.Storage
clientToken := uuid.GenerateUUID()
req.ClientToken = clientToken
if _, err := b.HandleRequest(req); err != nil {
t.Fatalf("err: %v", err)
}
req = logical.TestRequest(t, logical.DeleteOperation, "foo")
req.Storage = storage
req.ClientToken = clientToken
resp, err := b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %v", resp)
}
req = logical.TestRequest(t, logical.ReadOperation, "foo")
req.Storage = storage
req.ClientToken = clientToken
resp, err = b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %v", resp)
}
}
func TestCubbyholeBackend_List(t *testing.T) {
b := testCubbyholeBackend()
req := logical.TestRequest(t, logical.WriteOperation, "foo")
clientToken := uuid.GenerateUUID()
req.Data["raw"] = "test"
req.ClientToken = clientToken
storage := req.Storage
if _, err := b.HandleRequest(req); err != nil {
t.Fatalf("err: %v", err)
}
req = logical.TestRequest(t, logical.WriteOperation, "bar")
req.Data["raw"] = "baz"
req.ClientToken = clientToken
req.Storage = storage
if _, err := b.HandleRequest(req); err != nil {
t.Fatalf("err: %v", err)
}
req = logical.TestRequest(t, logical.ListOperation, "")
req.Storage = storage
req.ClientToken = clientToken
resp, err := b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
expKeys := []string{"foo", "bar"}
respKeys := resp.Data["keys"].([]string)
sort.Strings(expKeys)
sort.Strings(respKeys)
if !reflect.DeepEqual(respKeys, expKeys) {
t.Fatalf("bad response.\n\nexpected: %#v\n\nGot: %#v", expKeys, respKeys)
}
}
func TestCubbyholeIsolation(t *testing.T) {
b := testCubbyholeBackend()
clientTokenA := uuid.GenerateUUID()
clientTokenB := uuid.GenerateUUID()
var storageA logical.Storage
var storageB logical.Storage
// Populate and test A entries
req := logical.TestRequest(t, logical.WriteOperation, "foo")
req.ClientToken = clientTokenA
storageA = req.Storage
req.Data["raw"] = "test"
resp, err := b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %v", resp)
}
req = logical.TestRequest(t, logical.ReadOperation, "foo")
req.Storage = storageA
req.ClientToken = clientTokenA
resp, err = b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
expected := &logical.Response{
Data: map[string]interface{}{
"raw": "test",
},
}
if !reflect.DeepEqual(resp, expected) {
t.Fatalf("bad response.\n\nexpected: %#v\n\nGot: %#v", expected, resp)
}
// Populate and test B entries
req = logical.TestRequest(t, logical.WriteOperation, "bar")
req.ClientToken = clientTokenB
storageB = req.Storage
req.Data["raw"] = "baz"
resp, err = b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %v", resp)
}
req = logical.TestRequest(t, logical.ReadOperation, "bar")
req.Storage = storageB
req.ClientToken = clientTokenB
resp, err = b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
expected = &logical.Response{
Data: map[string]interface{}{
"raw": "baz",
},
}
if !reflect.DeepEqual(resp, expected) {
t.Fatalf("bad response.\n\nexpected: %#v\n\nGot: %#v", expected, resp)
}
// We shouldn't be able to read A from B and vice versa
req = logical.TestRequest(t, logical.ReadOperation, "foo")
req.Storage = storageB
req.ClientToken = clientTokenB
resp, err = b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("err: was able to read from other user's cubbyhole")
}
req = logical.TestRequest(t, logical.ReadOperation, "bar")
req.Storage = storageA
req.ClientToken = clientTokenA
resp, err = b.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("err: was able to read from other user's cubbyhole")
}
}
func testCubbyholeBackend() logical.Backend {
b, _ := CubbyholeBackendFactory(&logical.BackendConfig{
Logger: nil,
System: logical.StaticSystemView{
DefaultLeaseTTLVal: time.Hour * 24,
MaxLeaseTTLVal: time.Hour * 24 * 30,
},
})
return b
}