func TestSession_Get_List_NodeSessions_ACLFilter(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" c.ACLMasterToken = "root" c.ACLDefaultPolicy = "deny" c.ACLEnforceVersion8 = false }) defer os.RemoveAll(dir1) defer s1.Shutdown() codec := rpcClient(t, s1) defer codec.Close() testutil.WaitForLeader(t, s1.RPC, "dc1") // Create the ACL. req := structs.ACLRequest{ Datacenter: "dc1", Op: structs.ACLSet, ACL: structs.ACL{ Name: "User token", Type: structs.ACLTypeClient, Rules: ` session "foo" { policy = "read" } `, }, WriteRequest: structs.WriteRequest{Token: "root"}, } var token string if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { t.Fatalf("err: %v", err) } // Create a node and a session. s1.fsm.State().EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"}) arg := structs.SessionRequest{ Datacenter: "dc1", Op: structs.SessionCreate, Session: structs.Session{ Node: "foo", }, WriteRequest: structs.WriteRequest{Token: "root"}, } var out string if err := msgpackrpc.CallWithCodec(codec, "Session.Apply", &arg, &out); err != nil { t.Fatalf("err: %v", err) } // Perform all the read operations, which should go through since version // 8 ACL enforcement isn't enabled. getR := structs.SessionSpecificRequest{ Datacenter: "dc1", Session: out, } { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.Get", &getR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 1 { t.Fatalf("bad: %v", sessions.Sessions) } } listR := structs.DCSpecificRequest{ Datacenter: "dc1", } { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.List", &listR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 1 { t.Fatalf("bad: %v", sessions.Sessions) } } nodeR := structs.NodeSpecificRequest{ Datacenter: "dc1", Node: "foo", } { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.NodeSessions", &nodeR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 1 { t.Fatalf("bad: %v", sessions.Sessions) } } // Now turn on version 8 enforcement and make sure everything is empty. s1.config.ACLEnforceVersion8 = true { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.Get", &getR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 0 { t.Fatalf("bad: %v", sessions.Sessions) } } { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.List", &listR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 0 { t.Fatalf("bad: %v", sessions.Sessions) } } { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.NodeSessions", &nodeR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 0 { t.Fatalf("bad: %v", sessions.Sessions) } } // Finally, supply the token and make sure the reads are allowed. getR.Token = token { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.Get", &getR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 1 { t.Fatalf("bad: %v", sessions.Sessions) } } listR.Token = token { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.List", &listR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 1 { t.Fatalf("bad: %v", sessions.Sessions) } } nodeR.Token = token { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.NodeSessions", &nodeR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 1 { t.Fatalf("bad: %v", sessions.Sessions) } } // Try to get a session that doesn't exist to make sure that's handled // correctly by the filter (it will get passed a nil slice). getR.Session = "adf4238a-882b-9ddc-4a9d-5b6758e4159e" { var sessions structs.IndexedSessions if err := msgpackrpc.CallWithCodec(codec, "Session.Get", &getR, &sessions); err != nil { t.Fatalf("err: %v", err) } if len(sessions.Sessions) != 0 { t.Fatalf("bad: %v", sessions.Sessions) } } }
func TestCatalog_ListNodes_ACLFilter(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" c.ACLMasterToken = "root" c.ACLDefaultPolicy = "deny" c.ACLEnforceVersion8 = false }) defer os.RemoveAll(dir1) defer s1.Shutdown() codec := rpcClient(t, s1) defer codec.Close() testutil.WaitForLeader(t, s1.RPC, "dc1") // We scope the reply in each of these since msgpack won't clear out an // existing slice if the incoming one is nil, so it's best to start // clean each time. // Prior to version 8, the node policy should be ignored. args := structs.DCSpecificRequest{ Datacenter: "dc1", } { reply := structs.IndexedNodes{} if err := msgpackrpc.CallWithCodec(codec, "Catalog.ListNodes", &args, &reply); err != nil { t.Fatalf("err: %v", err) } if len(reply.Nodes) != 1 { t.Fatalf("bad: %v", reply.Nodes) } } // Now turn on version 8 enforcement and try again. s1.config.ACLEnforceVersion8 = true { reply := structs.IndexedNodes{} if err := msgpackrpc.CallWithCodec(codec, "Catalog.ListNodes", &args, &reply); err != nil { t.Fatalf("err: %v", err) } if len(reply.Nodes) != 0 { t.Fatalf("bad: %v", reply.Nodes) } } // Create an ACL that can read the node. arg := structs.ACLRequest{ Datacenter: "dc1", Op: structs.ACLSet, ACL: structs.ACL{ Name: "User token", Type: structs.ACLTypeClient, Rules: fmt.Sprintf(` node "%s" { policy = "read" } `, s1.config.NodeName), }, WriteRequest: structs.WriteRequest{Token: "root"}, } var id string if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &id); err != nil { t.Fatalf("err: %v", err) } // Now try with the token and it will go through. args.Token = id { reply := structs.IndexedNodes{} if err := msgpackrpc.CallWithCodec(codec, "Catalog.ListNodes", &args, &reply); err != nil { t.Fatalf("err: %v", err) } if len(reply.Nodes) != 1 { t.Fatalf("bad: %v", reply.Nodes) } } }
func TestOperator_RaftGetConfiguration_ACLDeny(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" c.ACLMasterToken = "root" c.ACLDefaultPolicy = "deny" }) defer os.RemoveAll(dir1) defer s1.Shutdown() codec := rpcClient(t, s1) defer codec.Close() testutil.WaitForLeader(t, s1.RPC, "dc1") // Make a request with no token to make sure it gets denied. arg := structs.DCSpecificRequest{ Datacenter: "dc1", } var reply structs.RaftConfigurationResponse err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply) if err == nil || !strings.Contains(err.Error(), permissionDenied) { t.Fatalf("err: %v", err) } // Create an ACL with operator read permissions. var token string { var rules = ` operator = "read" ` req := structs.ACLRequest{ Datacenter: "dc1", Op: structs.ACLSet, ACL: structs.ACL{ Name: "User token", Type: structs.ACLTypeClient, Rules: rules, }, WriteRequest: structs.WriteRequest{Token: "root"}, } if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { t.Fatalf("err: %v", err) } } // Now it should go through. arg.Token = token if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply); err != nil { t.Fatalf("err: %v", err) } future := s1.raft.GetConfiguration() if err := future.Error(); err != nil { t.Fatalf("err: %v", err) } if len(future.Configuration().Servers) != 1 { t.Fatalf("bad: %v", future.Configuration().Servers) } me := future.Configuration().Servers[0] expected := structs.RaftConfigurationResponse{ Servers: []*structs.RaftServer{ &structs.RaftServer{ ID: me.ID, Node: s1.config.NodeName, Address: me.Address, Leader: true, Voter: true, }, }, Index: future.Index(), } if !reflect.DeepEqual(reply, expected) { t.Fatalf("bad: %v", reply) } }
func TestCoordinate_ListNodes_ACLFilter(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" c.ACLMasterToken = "root" c.ACLDefaultPolicy = "deny" c.ACLEnforceVersion8 = false }) defer os.RemoveAll(dir1) defer s1.Shutdown() codec := rpcClient(t, s1) defer codec.Close() testutil.WaitForLeader(t, s1.RPC, "dc1") // Register some nodes. nodes := []string{"foo", "bar", "baz"} for _, node := range nodes { req := structs.RegisterRequest{ Datacenter: "dc1", Node: node, Address: "127.0.0.1", WriteRequest: structs.WriteRequest{ Token: "root", }, } var reply struct{} if err := msgpackrpc.CallWithCodec(codec, "Catalog.Register", &req, &reply); err != nil { t.Fatalf("err: %v", err) } } // Send coordinate updates for a few nodes. arg1 := structs.CoordinateUpdateRequest{ Datacenter: "dc1", Node: "foo", Coord: generateRandomCoordinate(), WriteRequest: structs.WriteRequest{ Token: "root", }, } var out struct{} if err := msgpackrpc.CallWithCodec(codec, "Coordinate.Update", &arg1, &out); err != nil { t.Fatalf("err: %v", err) } arg2 := structs.CoordinateUpdateRequest{ Datacenter: "dc1", Node: "bar", Coord: generateRandomCoordinate(), WriteRequest: structs.WriteRequest{ Token: "root", }, } if err := msgpackrpc.CallWithCodec(codec, "Coordinate.Update", &arg2, &out); err != nil { t.Fatalf("err: %v", err) } arg3 := structs.CoordinateUpdateRequest{ Datacenter: "dc1", Node: "baz", Coord: generateRandomCoordinate(), WriteRequest: structs.WriteRequest{ Token: "root", }, } if err := msgpackrpc.CallWithCodec(codec, "Coordinate.Update", &arg3, &out); err != nil { t.Fatalf("err: %v", err) } // Wait for all the coordinate updates to apply. Since we aren't // enforcing version 8 ACLs, this should also allow us to read // everything back without a token. testutil.WaitForResult(func() (bool, error) { arg := structs.DCSpecificRequest{ Datacenter: "dc1", } resp := structs.IndexedCoordinates{} if err := msgpackrpc.CallWithCodec(codec, "Coordinate.ListNodes", &arg, &resp); err != nil { t.Fatalf("err: %v", err) } if len(resp.Coordinates) == 3 { return true, nil } return false, fmt.Errorf("bad: %v", resp.Coordinates) }, func(err error) { t.Fatalf("err: %v", err) }) // Now that we've waited for the batch processing to ingest the // coordinates we can do the rest of the requests without the loop. We // will start by turning on version 8 ACL support which should block // everything. s1.config.ACLEnforceVersion8 = true arg := structs.DCSpecificRequest{ Datacenter: "dc1", } resp := structs.IndexedCoordinates{} if err := msgpackrpc.CallWithCodec(codec, "Coordinate.ListNodes", &arg, &resp); err != nil { t.Fatalf("err: %v", err) } if len(resp.Coordinates) != 0 { t.Fatalf("bad: %#v", resp.Coordinates) } // Create an ACL that can read one of the nodes. var id string { req := structs.ACLRequest{ Datacenter: "dc1", Op: structs.ACLSet, ACL: structs.ACL{ Name: "User token", Type: structs.ACLTypeClient, Rules: ` node "foo" { policy = "read" } `, }, WriteRequest: structs.WriteRequest{Token: "root"}, } if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &id); err != nil { t.Fatalf("err: %v", err) } } // With the token, it should now go through. arg.Token = id if err := msgpackrpc.CallWithCodec(codec, "Coordinate.ListNodes", &arg, &resp); err != nil { t.Fatalf("err: %v", err) } if len(resp.Coordinates) != 1 || resp.Coordinates[0].Node != "foo" { t.Fatalf("bad: %#v", resp.Coordinates) } }