diff --git a/nomad/acl.go b/nomad/acl.go index 259180d96..46b17ee20 100644 --- a/nomad/acl.go +++ b/nomad/acl.go @@ -1,9 +1,6 @@ package nomad import ( - "crypto/sha1" - "encoding/binary" - "fmt" "time" metrics "github.com/armon/go-metrics" @@ -37,12 +34,20 @@ func (s *Server) resolveToken(secretID string) (*acl.ACL, error) { // to simplify testing. func resolveTokenFromSnapshotCache(snap *state.StateSnapshot, cache *lru.TwoQueueCache, secretID string) (*acl.ACL, error) { // Lookup the ACL Token - token, err := snap.ACLTokenBySecretID(nil, secretID) - if err != nil { - return nil, err - } - if token == nil { - return nil, structs.TokenNotFound + var token *structs.ACLToken + var err error + + // Handle anonymous requests + if secretID == "" { + token = structs.AnonymousACLToken + } else { + token, err = snap.ACLTokenBySecretID(nil, secretID) + if err != nil { + return nil, err + } + if token == nil { + return nil, structs.TokenNotFound + } } // Check if this is a management token @@ -52,7 +57,6 @@ func resolveTokenFromSnapshotCache(snap *state.StateSnapshot, cache *lru.TwoQueu // Get all associated policies policies := make([]*structs.ACLPolicy, 0, len(token.Policies)) - cacheKeyHash := sha1.New() for _, policyName := range token.Policies { policy, err := snap.ACLPolicyByName(nil, policyName) if err != nil { @@ -65,39 +69,12 @@ func resolveTokenFromSnapshotCache(snap *state.StateSnapshot, cache *lru.TwoQueu // Save the policy and update the cache key policies = append(policies, policy) - - // Update the cache key using (policy name, modify index). - // This ensures any updates to the policy cause the cache to be busted. - cacheKeyHash.Write([]byte(policyName)) - binary.Write(cacheKeyHash, binary.BigEndian, policy.ModifyIndex) } - // Finalize the cache key and check for a match - cacheKey := string(cacheKeyHash.Sum(nil)) - aclRaw, ok := cache.Get(cacheKey) - if ok { - return aclRaw.(*acl.ACL), nil - } - - // Parse the policies - parsed := make([]*acl.Policy, 0, len(policies)) - for _, policy := range policies { - p, err := acl.Parse(policy.Rules) - if err != nil { - return nil, fmt.Errorf("failed to parse %q: %v", policy.Name, err) - } - parsed = append(parsed, p) - } - - // Create the ACL object - aclObj, err := acl.NewACL(false, parsed) + // Compile and cache the ACL object + aclObj, err := structs.CompileACLObject(cache, policies) if err != nil { - return nil, fmt.Errorf("failed to construct ACL: %v", err) + return nil, err } - - // Update the cache - cache.Add(cacheKey, aclObj) - - // Return the ACL object return aclObj, nil } diff --git a/nomad/acl_test.go b/nomad/acl_test.go index 50a739106..259f5b7dc 100644 --- a/nomad/acl_test.go +++ b/nomad/acl_test.go @@ -35,9 +35,14 @@ func TestResolveACLToken(t *testing.T) { snap, err := state.Snapshot() assert.Nil(t, err) + // Attempt resolution of blank token. Should return anonymous policy + aclObj, err := resolveTokenFromSnapshotCache(snap, cache, "") + assert.Nil(t, err) + assert.NotNil(t, aclObj) + // Attempt resolution of unknown token. Should fail. randID := structs.GenerateUUID() - aclObj, err := resolveTokenFromSnapshotCache(snap, cache, randID) + aclObj, err = resolveTokenFromSnapshotCache(snap, cache, randID) assert.Equal(t, structs.TokenNotFound, err) assert.Nil(t, aclObj)