// lookupACL is used when we are non-authoritative, and need // to resolve an ACL func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) { // Check the cache for the ACL var cached *aclCacheEntry raw, ok := s.aclCache.Get(id) if ok { cached = raw.(*aclCacheEntry) } // Check for live cache if cached != nil && time.Now().Before(cached.Expires) { metrics.IncrCounter([]string{"consul", "acl", "cache_hit"}, 1) return cached.ACL, nil } else { metrics.IncrCounter([]string{"consul", "acl", "cache_miss"}, 1) } // Attempt to refresh the policy args := structs.ACLPolicyRequest{ Datacenter: authDC, ACL: id, } if cached != nil { args.ETag = cached.ETag } var out structs.ACLPolicy err := s.RPC("ACL.GetPolicy", &args, &out) // Handle the happy path if err == nil { return s.useACLPolicy(id, authDC, cached, &out) } // Check for not-found if strings.Contains(err.Error(), aclNotFound) { return nil, errors.New(aclNotFound) } else { s.logger.Printf("[ERR] consul.acl: Failed to get policy for '%s': %v", id, err) } // Unable to refresh, apply the down policy switch s.config.ACLDownPolicy { case "allow": return acl.AllowAll(), nil case "extend-cache": if cached != nil { return cached.ACL, nil } fallthrough default: return acl.DenyAll(), nil } }
func TestACL_DownPolicy_Allow(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" c.ACLDownPolicy = "allow" c.ACLMasterToken = "root" }) defer os.RemoveAll(dir1) defer s1.Shutdown() client := rpcClient(t, s1) defer client.Close() dir2, s2 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" // Enable ACLs! c.ACLDownPolicy = "allow" c.Bootstrap = false // Disable bootstrap }) defer os.RemoveAll(dir2) defer s2.Shutdown() // Try to join addr := fmt.Sprintf("127.0.0.1:%d", s1.config.SerfLANConfig.MemberlistConfig.BindPort) if _, err := s2.JoinLAN([]string{addr}); err != nil { t.Fatalf("err: %v", err) } testutil.WaitForResult(func() (bool, error) { p1, _ := s1.raftPeers.Peers() return len(p1) == 2, errors.New(fmt.Sprintf("%v", p1)) }, func(err error) { t.Fatalf("should have 2 peers: %v", err) }) testutil.WaitForLeader(t, client.Call, "dc1") // Create a new token arg := structs.ACLRequest{ Datacenter: "dc1", Op: structs.ACLSet, ACL: structs.ACL{ Name: "User token", Type: structs.ACLTypeClient, Rules: testACLPolicy, }, WriteRequest: structs.WriteRequest{Token: "root"}, } var id string if err := client.Call("ACL.Apply", &arg, &id); err != nil { t.Fatalf("err: %v", err) } // find the non-authoritative server var nonAuth *Server var auth *Server if !s1.IsLeader() { nonAuth = s1 auth = s2 } else { nonAuth = s2 auth = s1 } // Kill the authoritative server auth.Shutdown() // Token should resolve into a AllowAll aclR, err := nonAuth.resolveToken(id) if err != nil { t.Fatalf("err: %v", err) } if aclR != acl.AllowAll() { t.Fatalf("bad acl: %#v", aclR) } }