nomad: allow getting policies which are subset of token, fixes client resolution

This commit is contained in:
Armon Dadgar
2017-08-21 17:53:17 -07:00
parent 5f04c0c2f1
commit 5415926763
2 changed files with 50 additions and 3 deletions

View File

@@ -216,10 +216,17 @@ func (a *ACL) GetPolicies(args *structs.ACLPolicySetRequest, reply *structs.ACLP
}
defer metrics.MeasureSince([]string{"nomad", "acl", "get_policies"}, time.Now())
// Check management level permissions
if acl, err := a.srv.resolveToken(args.SecretID); err != nil {
// For client typed tokens, allow them to query any policies associated with that token.
// This is used by clients which are resolving the policies to enforce. Any associated
// policies need to be fetched so that the client can determine what to allow.
token, err := a.srv.State().ACLTokenBySecretID(nil, args.SecretID)
if err != nil {
return err
} else if acl == nil || !acl.IsManagement() {
}
if token == nil {
return structs.ErrTokenNotFound
}
if token.Type != structs.ACLManagementToken && !token.PolicySubset(args.Names) {
return structs.ErrPermissionDenied
}

View File

@@ -165,6 +165,46 @@ func TestACLEndpoint_GetPolicies(t *testing.T) {
assert.Equal(t, 0, len(resp.Policies))
}
func TestACLEndpoint_GetPolicies_TokenSubset(t *testing.T) {
t.Parallel()
s1, _ := testACLServer(t, nil)
defer s1.Shutdown()
codec := rpcClient(t, s1)
testutil.WaitForLeader(t, s1.RPC)
// Create the register request
policy := mock.ACLPolicy()
policy2 := mock.ACLPolicy()
s1.fsm.State().UpsertACLPolicies(1000, []*structs.ACLPolicy{policy, policy2})
token := mock.ACLToken()
token.Policies = []string{policy.Name}
s1.fsm.State().UpsertACLTokens(1000, []*structs.ACLToken{token})
// Lookup the policy which is a subset of our tokens
get := &structs.ACLPolicySetRequest{
Names: []string{policy.Name},
QueryOptions: structs.QueryOptions{
Region: "global",
SecretID: token.SecretID,
},
}
var resp structs.ACLPolicySetResponse
if err := msgpackrpc.CallWithCodec(codec, "ACL.GetPolicies", get, &resp); err != nil {
t.Fatalf("err: %v", err)
}
assert.Equal(t, uint64(1000), resp.Index)
assert.Equal(t, 1, len(resp.Policies))
assert.Equal(t, policy, resp.Policies[policy.Name])
// Lookup non-associated policy
get.Names = []string{policy2.Name}
resp = structs.ACLPolicySetResponse{}
if err := msgpackrpc.CallWithCodec(codec, "ACL.GetPolicies", get, &resp); err == nil {
t.Fatalf("expected error")
}
}
func TestACLEndpoint_GetPolicies_Blocking(t *testing.T) {
t.Parallel()
s1, root := testACLServer(t, nil)