1package vault 2 3import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/vault/helper/namespace" 11 "github.com/hashicorp/vault/sdk/logical" 12) 13 14func TestCapabilities_DerivedPolicies(t *testing.T) { 15 var resp *logical.Response 16 var err error 17 18 ctx := namespace.RootContext(nil) 19 i, _, c := testIdentityStoreWithGithubAuth(ctx, t) 20 21 policy1 := ` 22name = "policy1" 23path "secret/sample" { 24 capabilities = ["update", "create", "sudo"] 25} 26` 27 policy2 := ` 28name = "policy2" 29path "secret/sample" { 30 capabilities = ["read", "delete"] 31} 32` 33 34 policy3 := ` 35name = "policy3" 36path "secret/sample" { 37 capabilities = ["list", "list"] 38} 39` 40 // Create the above policies 41 policy, _ := ParseACLPolicy(namespace.RootNamespace, policy1) 42 err = c.policyStore.SetPolicy(ctx, policy) 43 if err != nil { 44 t.Fatalf("err: %v", err) 45 } 46 47 policy, _ = ParseACLPolicy(namespace.RootNamespace, policy2) 48 err = c.policyStore.SetPolicy(ctx, policy) 49 if err != nil { 50 t.Fatalf("err: %v", err) 51 } 52 53 policy, _ = ParseACLPolicy(namespace.RootNamespace, policy3) 54 err = c.policyStore.SetPolicy(ctx, policy) 55 if err != nil { 56 t.Fatalf("err: %v", err) 57 } 58 59 // Create an entity and assign policy1 to it 60 entityReq := &logical.Request{ 61 Path: "entity", 62 Operation: logical.UpdateOperation, 63 Data: map[string]interface{}{ 64 "policies": "policy1", 65 }, 66 } 67 resp, err = i.HandleRequest(ctx, entityReq) 68 if err != nil || (resp != nil && resp.IsError()) { 69 t.Fatalf("bad: resp: %#v\nerr: %#v\n", resp, err) 70 } 71 entityID := resp.Data["id"].(string) 72 73 // Create a token for the entity and assign policy2 on the token 74 ent := &logical.TokenEntry{ 75 ID: "capabilitiestoken", 76 Path: "secret/sample", 77 Policies: []string{"policy2"}, 78 EntityID: entityID, 79 TTL: time.Hour, 80 } 81 testMakeTokenDirectly(t, c.tokenStore, ent) 82 83 actual, err := c.Capabilities(ctx, "capabilitiestoken", "secret/sample") 84 if err != nil { 85 t.Fatalf("err: %v", err) 86 } 87 expected := []string{"create", "read", "sudo", "delete", "update"} 88 sort.Strings(actual) 89 sort.Strings(expected) 90 if !reflect.DeepEqual(actual, expected) { 91 t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) 92 } 93 94 // Create a group and add the above created entity to it 95 groupReq := &logical.Request{ 96 Path: "group", 97 Operation: logical.UpdateOperation, 98 Data: map[string]interface{}{ 99 "member_entity_ids": []string{entityID}, 100 "policies": "policy3", 101 }, 102 } 103 resp, err = i.HandleRequest(ctx, groupReq) 104 if err != nil || (resp != nil && resp.IsError()) { 105 t.Fatalf("bad: resp: %#v\nerr: %#v\n", resp, err) 106 } 107 108 actual, err = c.Capabilities(namespace.RootContext(nil), "capabilitiestoken", "secret/sample") 109 if err != nil { 110 t.Fatalf("err: %v", err) 111 } 112 expected = []string{"create", "read", "sudo", "delete", "update", "list"} 113 sort.Strings(actual) 114 sort.Strings(expected) 115 if !reflect.DeepEqual(actual, expected) { 116 t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) 117 } 118} 119 120func TestCapabilities_TemplatedPolicies(t *testing.T) { 121 var resp *logical.Response 122 var err error 123 i, _, c := testIdentityStoreWithGithubAuth(namespace.RootContext(nil), t) 124 // Create an entity and assign policy1 to it 125 entityReq := &logical.Request{ 126 Path: "entity", 127 Operation: logical.UpdateOperation, 128 } 129 resp, err = i.HandleRequest(namespace.RootContext(nil), entityReq) 130 if err != nil || (resp != nil && resp.IsError()) { 131 t.Fatalf("bad: resp: %#v\nerr: %#v\n", resp, err) 132 } 133 entityID := resp.Data["id"].(string) 134 135 // Create a token for the entity and assign policy2 on the token 136 ent := &logical.TokenEntry{ 137 ID: "capabilitiestoken", 138 Path: "auth/token/create", 139 Policies: []string{"testpolicy"}, 140 EntityID: entityID, 141 TTL: time.Hour, 142 } 143 testMakeTokenDirectly(t, c.tokenStore, ent) 144 145 tCases := []struct { 146 policy string 147 path string 148 expected []string 149 }{ 150 { 151 `name = "testpolicy" 152 path "secret/{{identity.entity.id}}/sample" { 153 capabilities = ["update", "create"] 154 } 155 `, 156 fmt.Sprintf("secret/%s/sample", entityID), 157 []string{"update", "create"}, 158 }, 159 { 160 `{"name": "testpolicy", "path": {"secret/{{identity.entity.id}}/sample": {"capabilities": ["read", "create"]}}}`, 161 fmt.Sprintf("secret/%s/sample", entityID), 162 []string{"read", "create"}, 163 }, 164 { 165 `{"name": "testpolicy", "path": {"secret/sample": {"capabilities": ["read"]}}}`, 166 "secret/sample", 167 []string{"read"}, 168 }, 169 } 170 for _, tCase := range tCases { 171 // Create the above policies 172 policy, err := ParseACLPolicy(namespace.RootNamespace, tCase.policy) 173 if err != nil { 174 t.Fatalf("err: %v", err) 175 } 176 err = c.policyStore.SetPolicy(namespace.RootContext(nil), policy) 177 if err != nil { 178 t.Fatalf("err: %v", err) 179 } 180 actual, err := c.Capabilities(namespace.RootContext(nil), "capabilitiestoken", tCase.path) 181 if err != nil { 182 t.Fatalf("err: %v", err) 183 } 184 sort.Strings(actual) 185 sort.Strings(tCase.expected) 186 if !reflect.DeepEqual(actual, tCase.expected) { 187 t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, tCase.expected) 188 } 189 } 190} 191 192func TestCapabilities(t *testing.T) { 193 c, _, token := TestCoreUnsealed(t) 194 195 actual, err := c.Capabilities(namespace.RootContext(nil), token, "path") 196 if err != nil { 197 t.Fatalf("err: %s", err) 198 } 199 expected := []string{"root"} 200 if !reflect.DeepEqual(actual, expected) { 201 t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) 202 } 203 204 // Create a policy 205 policy, _ := ParseACLPolicy(namespace.RootNamespace, aclPolicy) 206 err = c.policyStore.SetPolicy(namespace.RootContext(nil), policy) 207 if err != nil { 208 t.Fatalf("err: %v", err) 209 } 210 211 // Create a token for the policy 212 ent := &logical.TokenEntry{ 213 ID: "capabilitiestoken", 214 Path: "testpath", 215 Policies: []string{"dev"}, 216 TTL: time.Hour, 217 } 218 testMakeTokenDirectly(t, c.tokenStore, ent) 219 220 actual, err = c.Capabilities(namespace.RootContext(nil), "capabilitiestoken", "foo/bar") 221 if err != nil { 222 t.Fatalf("err: %s", err) 223 } 224 expected = []string{"create", "read", "sudo"} 225 if !reflect.DeepEqual(actual, expected) { 226 t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected) 227 } 228} 229