diff --git a/http/sys_capabilities_test.go b/http/sys_capabilities_test.go index f192e2b0a..726621ec7 100644 --- a/http/sys_capabilities_test.go +++ b/http/sys_capabilities_test.go @@ -7,6 +7,78 @@ import ( "github.com/hashicorp/vault/vault" ) +func TestSysCapabilitiesAccessor(t *testing.T) { + core, _, token := vault.TestCoreUnsealed(t) + ln, addr := TestServer(t, core) + defer ln.Close() + TestServerAuth(t, addr, token) + + // Lookup the token properties + resp := testHttpGet(t, token, addr+"/v1/auth/token/lookup/"+token) + var lookupResp map[string]interface{} + testResponseStatus(t, resp, 200) + testResponseBody(t, resp, &lookupResp) + + // Retrieve the accessor from the token properties + lookupData := lookupResp["data"].(map[string]interface{}) + accessor := lookupData["accessor"].(string) + + resp = testHttpPost(t, token, addr+"/v1/sys/capabilities-accessor", map[string]interface{}{ + "accessor": accessor, + "path": "testpath", + }) + + var actual map[string][]string + testResponseStatus(t, resp, 200) + testResponseBody(t, resp, &actual) + + expected := map[string][]string{ + "capabilities": []string{"root"}, + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) + } + + // Testing for non-root token's accessor + // Create a policy first + resp = testHttpPost(t, token, addr+"/v1/sys/policy/foo", map[string]interface{}{ + "rules": `path "testpath" {capabilities = ["read","sudo"]}`, + }) + testResponseStatus(t, resp, 204) + + // Create a token against the test policy + resp = testHttpPost(t, token, addr+"/v1/auth/token/create", map[string]interface{}{ + "policies": []string{"foo"}, + }) + + var tokenResp map[string]interface{} + testResponseStatus(t, resp, 200) + testResponseBody(t, resp, &tokenResp) + + // Check if desired policies are present in the token + auth := tokenResp["auth"].(map[string]interface{}) + actualPolicies := auth["policies"] + expectedPolicies := []interface{}{"default", "foo"} + if !reflect.DeepEqual(actualPolicies, expectedPolicies) { + t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actualPolicies, expectedPolicies) + } + + // Check the capabilities of non-root token using the accessor + resp = testHttpPost(t, token, addr+"/v1/sys/capabilities-accessor", map[string]interface{}{ + "accessor": auth["accessor"], + "path": "testpath", + }) + testResponseStatus(t, resp, 200) + testResponseBody(t, resp, &actual) + + expected = map[string][]string{ + "capabilities": []string{"sudo", "read"}, + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) + } +} + func TestSysCapabilities(t *testing.T) { core, _, token := vault.TestCoreUnsealed(t) ln, addr := TestServer(t, core) diff --git a/vault/capabilities_test.go b/vault/capabilities_test.go index 8367dc90b..e3b0b46fc 100644 --- a/vault/capabilities_test.go +++ b/vault/capabilities_test.go @@ -5,6 +5,61 @@ import ( "testing" ) +func TestCapabilitiesAccessor_Basic(t *testing.T) { + c, _, token := TestCoreUnsealed(t) + + // Lookup the token in the store to get root token's accessor + tokenEntry, err := c.tokenStore.Lookup(token) + if err != nil { + t.Fatalf("err: %s", err) + } + accessor := tokenEntry.Accessor + + // Use the accessor to fetch the capabilities + actual, err := c.CapabilitiesAccessor(accessor, "path") + if err != nil { + t.Fatalf("err: %s", err) + } + expected := []string{"root"} + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) + } + + // Create a policy + policy, _ := Parse(aclPolicy) + err = c.policyStore.SetPolicy(policy) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Create a token for the policy + ent := &TokenEntry{ + ID: "capabilitiestoken", + Path: "testpath", + Policies: []string{"dev"}, + } + if err := c.tokenStore.create(ent); err != nil { + t.Fatalf("err: %v", err) + } + + // Lookup the token in the store to get token's accessor + tokenEntry, err = c.tokenStore.Lookup("capabilitiestoken") + if err != nil { + t.Fatalf("err: %s", err) + } + accessor = tokenEntry.Accessor + + // Use the accessor to fetch the capabilities + actual, err = c.CapabilitiesAccessor(accessor, "foo/bar") + if err != nil { + t.Fatalf("err: %s", err) + } + expected = []string{"sudo", "read", "create"} + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) + } +} + func TestCapabilities_Basic(t *testing.T) { c, _, token := TestCoreUnsealed(t) diff --git a/vault/token_store.go b/vault/token_store.go index 890e6ee4d..fc2aa515b 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -984,6 +984,7 @@ func (ts *TokenStore) handleLookup( resp := &logical.Response{ Data: map[string]interface{}{ "id": out.ID, + "accessor": out.Accessor, "policies": out.Policies, "path": out.Path, "meta": out.Meta,