func makeTestGossip(t *testing.T) (*gossip.Gossip, func()) { n := simulation.NewNetwork(1, "tcp", gossip.TestInterval) g := n.Nodes[0].Gossip permConfig := &proto.PermConfig{ Read: []string{""}, Write: []string{""}, } configMap, err := storage.NewPrefixConfigMap([]*storage.PrefixConfig{ {proto.KeyMin, nil, permConfig}, }) if err != nil { t.Fatalf("failed to make prefix config map, err: %s", err.Error()) } if err := g.AddInfo(gossip.KeySentinel, "cluster1", time.Hour); err != nil { t.Fatal(err) } if err := g.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour); err != nil { t.Fatal(err) } if err := g.AddInfo(gossip.KeyFirstRangeDescriptor, testRangeDescriptor, time.Hour); err != nil { t.Fatal(err) } nodeIDKey := gossip.MakeNodeIDKey(1) if err := g.AddInfo(nodeIDKey, &proto.NodeDescriptor{ NodeID: 1, Address: proto.Addr{ Network: testAddress.Network(), Address: testAddress.String(), }, Attrs: proto.Attributes{Attrs: []string{"attr1", "attr2"}}, }, time.Hour); err != nil { t.Fatal(err) } return g, n.Stop }
// TestVerifyPermissions verifies permissions are checked for single // zones and across multiple zones. It also verifies that permissions // are checked hierarchically. func TestVerifyPermissions(t *testing.T) { defer leaktest.AfterTest(t) n := simulation.NewNetwork(1, "tcp", gossip.TestInterval) ds := NewDistSender(nil, n.Nodes[0].Gossip) config1 := &proto.PermConfig{ Read: []string{"read1", "readAll", "rw1", "rwAll"}, Write: []string{"write1", "writeAll", "rw1", "rwAll"}} config2 := &proto.PermConfig{ Read: []string{"read2", "readAll", "rw2", "rwAll"}, Write: []string{"write2", "writeAll", "rw2", "rwAll"}} configs := []*storage.PrefixConfig{ {proto.KeyMin, nil, config1}, {proto.Key("a"), nil, config2}, } configMap, err := storage.NewPrefixConfigMap(configs) if err != nil { t.Fatalf("failed to make prefix config map, err: %s", err.Error()) } if err := ds.gossip.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour); err != nil { t.Fatal(err) } allRequestTypes := []proto.Request{ &proto.GetRequest{}, &proto.PutRequest{}, &proto.ConditionalPutRequest{}, &proto.IncrementRequest{}, &proto.DeleteRequest{}, &proto.DeleteRangeRequest{}, &proto.ScanRequest{}, &proto.EndTransactionRequest{}, &proto.BatchRequest{}, &proto.AdminSplitRequest{}, &proto.AdminMergeRequest{}, &proto.InternalHeartbeatTxnRequest{}, &proto.InternalGCRequest{}, &proto.InternalPushTxnRequest{}, &proto.InternalRangeLookupRequest{}, &proto.InternalResolveIntentRequest{}, &proto.InternalResolveIntentRangeRequest{}, &proto.InternalMergeRequest{}, &proto.InternalTruncateLogRequest{}, &proto.InternalLeaderLeaseRequest{}, &proto.InternalBatchRequest{}, } var readOnlyRequests []proto.Request var writeOnlyRequests []proto.Request var readWriteRequests []proto.Request for _, r := range allRequestTypes { if proto.IsRead(r) && !proto.IsWrite(r) { readOnlyRequests = append(readOnlyRequests, r) } if proto.IsWrite(r) && !proto.IsRead(r) { writeOnlyRequests = append(writeOnlyRequests, r) } if proto.IsRead(r) && proto.IsWrite(r) { readWriteRequests = append(readWriteRequests, r) } } testData := []struct { // Permission-based db methods from the storage package. requests []proto.Request user string startKey, endKey proto.Key hasPermission bool }{ // Test permissions within a single range {readOnlyRequests, "read1", proto.KeyMin, proto.KeyMin, true}, {readOnlyRequests, "rw1", proto.KeyMin, proto.KeyMin, true}, {readOnlyRequests, "write1", proto.KeyMin, proto.KeyMin, false}, {readOnlyRequests, "random", proto.KeyMin, proto.KeyMin, false}, {readWriteRequests, "rw1", proto.KeyMin, proto.KeyMin, true}, {readWriteRequests, "read1", proto.KeyMin, proto.KeyMin, false}, {readWriteRequests, "write1", proto.KeyMin, proto.KeyMin, false}, {writeOnlyRequests, "write1", proto.KeyMin, proto.KeyMin, true}, {writeOnlyRequests, "rw1", proto.KeyMin, proto.KeyMin, true}, {writeOnlyRequests, "read1", proto.KeyMin, proto.KeyMin, false}, {writeOnlyRequests, "random", proto.KeyMin, proto.KeyMin, false}, // Test permissions hierarchically. {readOnlyRequests, "read1", proto.Key("a"), proto.Key("a1"), true}, {readWriteRequests, "rw1", proto.Key("a"), proto.Key("a1"), true}, {writeOnlyRequests, "write1", proto.Key("a"), proto.Key("a1"), true}, // Test permissions across both ranges. {readOnlyRequests, "readAll", proto.KeyMin, proto.Key("b"), true}, {readOnlyRequests, "read1", proto.KeyMin, proto.Key("b"), true}, {readOnlyRequests, "read2", proto.KeyMin, proto.Key("b"), false}, {readOnlyRequests, "random", proto.KeyMin, proto.Key("b"), false}, {readWriteRequests, "rwAll", proto.KeyMin, proto.Key("b"), true}, {readWriteRequests, "rw1", proto.KeyMin, proto.Key("b"), true}, {readWriteRequests, "random", proto.KeyMin, proto.Key("b"), false}, {writeOnlyRequests, "writeAll", proto.KeyMin, proto.Key("b"), true}, {writeOnlyRequests, "write1", proto.KeyMin, proto.Key("b"), true}, {writeOnlyRequests, "write2", proto.KeyMin, proto.Key("b"), false}, {writeOnlyRequests, "random", proto.KeyMin, proto.Key("b"), false}, // Test permissions within and around the boundaries of a range, // representatively using rw methods. {readWriteRequests, "rw2", proto.Key("a"), proto.Key("b"), true}, {readWriteRequests, "rwAll", proto.Key("a"), proto.Key("b"), true}, {readWriteRequests, "rw2", proto.Key("a"), proto.Key("a"), true}, {readWriteRequests, "rw2", proto.Key("a"), proto.Key("a1"), true}, {readWriteRequests, "rw2", proto.Key("a"), proto.Key("b1"), false}, {readWriteRequests, "rw2", proto.Key("a3"), proto.Key("a4"), true}, {readWriteRequests, "rw2", proto.Key("a3"), proto.Key("b1"), false}, } for i, test := range testData { for _, r := range test.requests { *r.Header() = proto.RequestHeader{ User: test.user, Key: test.startKey, EndKey: test.endKey, } err := ds.verifyPermissions(r) if err != nil && test.hasPermission { t.Errorf("test %d: user %s should have had permission to %s, err: %s", i, test.user, r.Method(), err.Error()) break } else if err == nil && !test.hasPermission { t.Errorf("test %d: user %s should not have had permission to %s", i, test.user, r.Method()) break } } } n.Stop() }
// TestVerifyPermissions verifies permissions are checked for single // zones and across multiple zones. It also verifies that permissions // are checked hierarchically. func TestVerifyPermissions(t *testing.T) { n := simulation.NewNetwork(1, "unix", gossip.TestInterval, gossip.TestBootstrap) ds := NewDistSender(n.Nodes[0].Gossip) config1 := &proto.PermConfig{ Read: []string{"read1", "readAll", "rw1", "rwAll"}, Write: []string{"write1", "writeAll", "rw1", "rwAll"}} config2 := &proto.PermConfig{ Read: []string{"read2", "readAll", "rw2", "rwAll"}, Write: []string{"write2", "writeAll", "rw2", "rwAll"}} configs := []*storage.PrefixConfig{ {engine.KeyMin, nil, config1}, {proto.Key("a"), nil, config2}, } configMap, err := storage.NewPrefixConfigMap(configs) if err != nil { t.Fatalf("failed to make prefix config map, err: %s", err.Error()) } ds.gossip.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour) readOnlyMethods := make([]string, 0, len(proto.ReadMethods)) writeOnlyMethods := make([]string, 0, len(proto.WriteMethods)) readWriteMethods := make([]string, 0, len(proto.ReadMethods)+len(proto.WriteMethods)) for readM := range proto.ReadMethods { if proto.IsReadOnly(readM) { readOnlyMethods = append(readOnlyMethods, readM) } else { readWriteMethods = append(readWriteMethods, readM) } } for writeM := range proto.WriteMethods { if !proto.NeedReadPerm(writeM) { writeOnlyMethods = append(writeOnlyMethods, writeM) } } testData := []struct { // Permission-based db methods from the storage package. methods []string user string startKey, endKey proto.Key hasPermission bool }{ // Test permissions within a single range {readOnlyMethods, "read1", engine.KeyMin, engine.KeyMin, true}, {readOnlyMethods, "rw1", engine.KeyMin, engine.KeyMin, true}, {readOnlyMethods, "write1", engine.KeyMin, engine.KeyMin, false}, {readOnlyMethods, "random", engine.KeyMin, engine.KeyMin, false}, {readWriteMethods, "rw1", engine.KeyMin, engine.KeyMin, true}, {readWriteMethods, "read1", engine.KeyMin, engine.KeyMin, false}, {readWriteMethods, "write1", engine.KeyMin, engine.KeyMin, false}, {writeOnlyMethods, "write1", engine.KeyMin, engine.KeyMin, true}, {writeOnlyMethods, "rw1", engine.KeyMin, engine.KeyMin, true}, {writeOnlyMethods, "read1", engine.KeyMin, engine.KeyMin, false}, {writeOnlyMethods, "random", engine.KeyMin, engine.KeyMin, false}, // Test permissions hierarchically. {readOnlyMethods, "read1", proto.Key("a"), proto.Key("a1"), true}, {readWriteMethods, "rw1", proto.Key("a"), proto.Key("a1"), true}, {writeOnlyMethods, "write1", proto.Key("a"), proto.Key("a1"), true}, // Test permissions across both ranges. {readOnlyMethods, "readAll", engine.KeyMin, proto.Key("b"), true}, {readOnlyMethods, "read1", engine.KeyMin, proto.Key("b"), true}, {readOnlyMethods, "read2", engine.KeyMin, proto.Key("b"), false}, {readOnlyMethods, "random", engine.KeyMin, proto.Key("b"), false}, {readWriteMethods, "rwAll", engine.KeyMin, proto.Key("b"), true}, {readWriteMethods, "rw1", engine.KeyMin, proto.Key("b"), true}, {readWriteMethods, "random", engine.KeyMin, proto.Key("b"), false}, {writeOnlyMethods, "writeAll", engine.KeyMin, proto.Key("b"), true}, {writeOnlyMethods, "write1", engine.KeyMin, proto.Key("b"), true}, {writeOnlyMethods, "write2", engine.KeyMin, proto.Key("b"), false}, {writeOnlyMethods, "random", engine.KeyMin, proto.Key("b"), false}, // Test permissions within and around the boundaries of a range, // representatively using rw methods. {readWriteMethods, "rw2", proto.Key("a"), proto.Key("b"), true}, {readWriteMethods, "rwAll", proto.Key("a"), proto.Key("b"), true}, {readWriteMethods, "rw2", proto.Key("a"), proto.Key("a"), true}, {readWriteMethods, "rw2", proto.Key("a"), proto.Key("a1"), true}, {readWriteMethods, "rw2", proto.Key("a"), proto.Key("b1"), false}, {readWriteMethods, "rw2", proto.Key("a3"), proto.Key("a4"), true}, {readWriteMethods, "rw2", proto.Key("a3"), proto.Key("b1"), false}, } for i, test := range testData { for _, method := range test.methods { err := ds.verifyPermissions( method, &proto.RequestHeader{ User: test.user, Key: test.startKey, EndKey: test.endKey}) if err != nil && test.hasPermission { t.Errorf("test %d: user %s should have had permission to %s, err: %s", i, test.user, method, err.Error()) break } else if err == nil && !test.hasPermission { t.Errorf("test %d: user %s should not have had permission to %s", i, test.user, method) break } } } n.Stop() }