func TestACL_filterNodeServices(t *testing.T) { // Create some node services services := structs.NodeServices{ Node: structs.Node{ Node: "node1", }, Services: map[string]*structs.NodeService{ "foo": &structs.NodeService{ ID: "foo", Service: "foo", }, }, } // Try permissive filtering filt := newAclFilter(acl.AllowAll(), nil) filt.filterNodeServices(&services) if len(services.Services) != 1 { t.Fatalf("bad: %#v", services.Services) } // Try restrictive filtering filt = newAclFilter(acl.DenyAll(), nil) filt.filterNodeServices(&services) if len(services.Services) != 0 { t.Fatalf("bad: %#v", services.Services) } }
func TestKeys(t *testing.T) { policy, _ := acl.Parse(testFilterRules) aclR, _ := acl.New(acl.DenyAll(), policy) type tcase struct { in []string out []string } cases := []tcase{ tcase{ in: []string{"foo/test", "foo/priv/nope", "foo/other", "zoo"}, out: []string{"foo/test", "foo/other"}, }, tcase{ in: []string{"abe", "lincoln"}, out: []string{}, }, tcase{ in: []string{"abe", "foo/1", "foo/2", "foo/3", "nope"}, out: []string{"foo/1", "foo/2", "foo/3"}, }, } for _, tc := range cases { out := FilterKeys(aclR, tc.in) if !reflect.DeepEqual(out, tc.out) { t.Fatalf("bad: %#v %#v", out, tc.out) } } }
// lookupACL is used when we are non-authoritative, and need // to resolve an ACL func (c *aclCache) lookupACL(id, authDC string) (acl.ACL, error) { // Check the cache for the ACL var cached *aclCacheEntry raw, ok := c.acls.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 := c.rpc("ACL.GetPolicy", &args, &out) // Handle the happy path if err == nil { return c.useACLPolicy(id, authDC, cached, &out) } // Check for not-found if strings.Contains(err.Error(), aclNotFound) { return nil, errors.New(aclNotFound) } else { c.logger.Printf("[ERR] consul.acl: Failed to get policy for '%s': %v", id, err) } // Unable to refresh, apply the down policy switch c.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_filterNodeDump(t *testing.T) { // Create a node dump dump := structs.NodeDump{ &structs.NodeInfo{ Node: "node1", Services: []*structs.NodeService{ &structs.NodeService{ ID: "foo", Service: "foo", }, }, Checks: []*structs.HealthCheck{ &structs.HealthCheck{ Node: "node1", CheckID: "check1", ServiceName: "foo", }, }, }, } // Try permissive filtering filt := newAclFilter(acl.AllowAll(), nil) filt.filterNodeDump(&dump) if len(dump) != 1 { t.Fatalf("bad: %#v", dump) } if len(dump[0].Services) != 1 { t.Fatalf("bad: %#v", dump[0].Services) } if len(dump[0].Checks) != 1 { t.Fatalf("bad: %#v", dump[0].Checks) } // Try restrictive filtering filt = newAclFilter(acl.DenyAll(), nil) filt.filterNodeDump(&dump) if len(dump) != 1 { t.Fatalf("bad: %#v", dump) } if len(dump[0].Services) != 0 { t.Fatalf("bad: %#v", dump[0].Services) } if len(dump[0].Checks) != 0 { t.Fatalf("bad: %#v", dump[0].Checks) } }
func TestACL_filterServices(t *testing.T) { // Create some services services := structs.Services{ "service1": []string{}, "service2": []string{}, } // Try permissive filtering filt := newAclFilter(acl.AllowAll(), nil) filt.filterServices(services) if len(services) != 2 { t.Fatalf("bad: %#v", services) } // Try restrictive filtering filt = newAclFilter(acl.DenyAll(), nil) filt.filterServices(services) if len(services) != 0 { t.Fatalf("bad: %#v", services) } }
func TestFilterDirEnt(t *testing.T) { policy, _ := acl.Parse(testFilterRules) aclR, _ := acl.New(acl.DenyAll(), policy) type tcase struct { in []string out []string } cases := []tcase{ tcase{ in: []string{"foo/test", "foo/priv/nope", "foo/other", "zoo"}, out: []string{"foo/test", "foo/other"}, }, tcase{ in: []string{"abe", "lincoln"}, out: nil, }, tcase{ in: []string{"abe", "foo/1", "foo/2", "foo/3", "nope"}, out: []string{"foo/1", "foo/2", "foo/3"}, }, } for _, tc := range cases { ents := structs.DirEntries{} for _, in := range tc.in { ents = append(ents, &structs.DirEntry{Key: in}) } ents = FilterDirEnt(aclR, ents) var outL []string for _, e := range ents { outL = append(outL, e.Key) } if !reflect.DeepEqual(outL, tc.out) { t.Fatalf("bad: %#v %#v", outL, tc.out) } } }
func TestACL_filterCheckServiceNodes(t *testing.T) { // Create some nodes nodes := structs.CheckServiceNodes{ structs.CheckServiceNode{ Node: structs.Node{ Node: "node1", }, Service: structs.NodeService{ ID: "foo", Service: "foo", }, Checks: structs.HealthChecks{ &structs.HealthCheck{ Node: "node1", CheckID: "check1", ServiceName: "foo", }, }, }, } // Try permissive filtering filt := newAclFilter(acl.AllowAll(), nil) filt.filterCheckServiceNodes(&nodes) if len(nodes) != 1 { t.Fatalf("bad: %#v", nodes) } if len(nodes[0].Checks) != 1 { t.Fatalf("bad: %#v", nodes[0].Checks) } // Try restrictive filtering filt = newAclFilter(acl.DenyAll(), nil) filt.filterCheckServiceNodes(&nodes) if len(nodes) != 0 { t.Fatalf("bad: %#v", nodes) } }
func TestACL_filterServiceNodes(t *testing.T) { // Create some service nodes nodes := structs.ServiceNodes{ structs.ServiceNode{ Node: "node1", ServiceName: "foo", }, } // Try permissive filtering filt := newAclFilter(acl.AllowAll(), nil) filt.filterServiceNodes(&nodes) if len(nodes) != 1 { t.Fatalf("bad: %#v", nodes) } // Try restrictive filtering filt = newAclFilter(acl.DenyAll(), nil) filt.filterServiceNodes(&nodes) if len(nodes) != 0 { t.Fatalf("bad: %#v", nodes) } }
func TestACL_filterHealthChecks(t *testing.T) { // Create some health checks hc := structs.HealthChecks{ &structs.HealthCheck{ Node: "node1", CheckID: "check1", ServiceName: "foo", }, } // Try permissive filtering filt := newAclFilter(acl.AllowAll(), nil) filt.filterHealthChecks(&hc) if len(hc) != 1 { t.Fatalf("bad: %#v", hc) } // Try restrictive filtering filt = newAclFilter(acl.DenyAll(), nil) filt.filterHealthChecks(&hc) if len(hc) != 0 { t.Fatalf("bad: %#v", hc) } }
func TestACL_DownPolicy_Deny(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" c.ACLDownPolicy = "deny" 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 = "deny" 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 DenyAll aclR, err := nonAuth.resolveToken(id) if err != nil { t.Fatalf("err: %v", err) } if aclR != acl.DenyAll() { t.Fatalf("bad acl: %#v", aclR) } }