open-vault/http/handler_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

110 lines
2.5 KiB
Go

package http
import (
"errors"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/vault"
)
// We use this test to verify header auth
func TestSysMounts_headerAuth(t *testing.T) {
core, _, token := vault.TestCoreUnsealed(t)
ln, addr := TestServer(t, core)
defer ln.Close()
req, err := http.NewRequest("GET", addr+"/v1/sys/mounts", nil)
if err != nil {
t.Fatalf("err: %s", err)
}
req.Header.Set(AuthHeaderName, token)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
t.Fatalf("err: %s", err)
}
var actual map[string]interface{}
expected := map[string]interface{}{
"secret/": map[string]interface{}{
"description": "generic secret storage",
"type": "generic",
"config": map[string]interface{}{
"default_lease_ttl": float64(0),
"max_lease_ttl": float64(0),
},
},
"sys/": map[string]interface{}{
"description": "system endpoints used for control, policy and debugging",
"type": "system",
"config": map[string]interface{}{
"default_lease_ttl": float64(0),
"max_lease_ttl": float64(0),
},
},
"cubbyhole/": map[string]interface{}{
"description": "per-token private secret storage",
"type": "cubbyhole",
"config": map[string]interface{}{
"default_lease_ttl": float64(0),
"max_lease_ttl": float64(0),
},
},
}
testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual)
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad:\nExpected: %#v\nActual: %#v\n", expected, actual)
}
}
func TestHandler_sealed(t *testing.T) {
core, _, token := vault.TestCoreUnsealed(t)
ln, addr := TestServer(t, core)
defer ln.Close()
core.Seal(token)
resp, err := http.Get(addr + "/v1/secret/foo")
if err != nil {
t.Fatalf("err: %s", err)
}
testResponseStatus(t, resp, 503)
}
func TestHandler_error(t *testing.T) {
w := httptest.NewRecorder()
respondError(w, 500, errors.New("Test Error"))
if w.Code != 500 {
t.Fatalf("expected 500, got %d", w.Code)
}
// The code inside of the error should override
// the argument to respondError
w2 := httptest.NewRecorder()
e := logical.CodedError(403, "error text")
respondError(w2, 500, e)
if w2.Code != 403 {
t.Fatalf("expected 403, got %d", w2.Code)
}
// vault.ErrSealed is a special case
w3 := httptest.NewRecorder()
respondError(w3, 400, vault.ErrSealed)
if w3.Code != 503 {
t.Fatalf("expected 503, got %d", w3.Code)
}
}