Пример #1
0
// verifyPermissions verifies that the requesting user (header.User)
// has permission to read/write (capabilities depend on method
// name). In the event that multiple permission configs apply to the
// key range implicated by the command, the lowest common denominator
// for permission. For example, if a scan crosses two permission
// configs, both configs must allow read permissions or the entire
// scan will fail.
func (db *DistDB) verifyPermissions(method string, header *storage.RequestHeader) error {
	// Get permissions map from gossip.
	permMap, err := db.gossip.GetInfo(gossip.KeyConfigPermission)
	if err != nil {
		return err
	}
	if permMap == nil {
		return util.Errorf("perm configs not available; cannot execute %s", method)
	}
	// Visit PermConfig(s) which apply to the method's key range.
	//   - For each, verify each PermConfig allows reads or writes as method requires.
	end := header.EndKey
	if end == nil {
		end = header.Key
	}
	return permMap.(storage.PrefixConfigMap).VisitPrefixes(
		header.Key, end, func(start, end storage.Key, config interface{}) error {
			perm := config.(*storage.PermConfig)
			if storage.NeedReadPerm(method) && !perm.CanRead(header.User) {
				return util.Errorf("user %q cannot read range %q-%q; permissions: %+v",
					header.User, string(start), string(end), perm)
			}
			if storage.NeedWritePerm(method) && !perm.CanWrite(header.User) {
				return util.Errorf("user %q cannot read range %q-%q; permissions: %+v",
					header.User, string(start), string(end), perm)
			}
			return nil
		})
}
Пример #2
0
func TestVerifyPermissions(t *testing.T) {
	n := gossip.NewSimulationNetwork(1, "unix", gossip.DefaultTestGossipInterval)
	kv := NewDistKV(n.Nodes[0].Gossip)
	config1 := &proto.PermConfig{
		Read:  []string{"read1", "readAll", "rw", "rwAll"},
		Write: []string{"write1", "writeAll", "rw", "rwAll"}}
	config2 := &proto.PermConfig{
		Read:  []string{"read2", "readAll", "rw2", "rwAll"},
		Write: []string{"write2", "writeAll", "rw2", "rwAll"}}
	configs := []*storage.PrefixConfig{
		{engine.KeyMin, nil, config1},
		{engine.Key("a"), nil, config2},
	}
	configMap, err := storage.NewPrefixConfigMap(configs)
	if err != nil {
		t.Fatalf("failed to make prefix config map, err: %s", err.Error())
	}
	kv.gossip.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour)

	readMethods := storage.ReadMethods
	writeMethods := storage.WriteMethods
	readOnlyMethods := make([]string, 0, len(readMethods))
	writeOnlyMethods := make([]string, 0, len(writeMethods))
	readWriteMethods := make([]string, 0, len(readMethods)+len(writeMethods))
	for _, readM := range readMethods {
		if storage.IsReadOnly(readM) {
			readOnlyMethods = append(readOnlyMethods, readM)
		} else {
			readWriteMethods = append(readWriteMethods, readM)
		}
	}
	for _, writeM := range writeMethods {
		if !storage.NeedReadPerm(writeM) {
			writeOnlyMethods = append(writeOnlyMethods, writeM)
		}
	}

	testData := []struct {
		// Permission-based db methods from the storage package.
		methods          []string
		user             string
		startKey, endKey engine.Key
		hasPermission    bool
	}{
		// Test permissions within a single range
		{readOnlyMethods, "read1", engine.KeyMin, engine.KeyMin, true},
		{readOnlyMethods, "rw", engine.KeyMin, engine.KeyMin, true},
		{readOnlyMethods, "write1", engine.KeyMin, engine.KeyMin, false},
		{readOnlyMethods, "random", engine.KeyMin, engine.KeyMin, false},
		{readWriteMethods, "rw", 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, "rw", engine.KeyMin, engine.KeyMin, true},
		{writeOnlyMethods, "read1", engine.KeyMin, engine.KeyMin, false},
		{writeOnlyMethods, "random", engine.KeyMin, engine.KeyMin, false},
		// Test permissions across both ranges
		{readOnlyMethods, "readAll", engine.KeyMin, engine.Key("b"), true},
		{readOnlyMethods, "read1", engine.KeyMin, engine.Key("b"), false},
		{readOnlyMethods, "read2", engine.KeyMin, engine.Key("b"), false},
		{readOnlyMethods, "random", engine.KeyMin, engine.Key("b"), false},
		{readWriteMethods, "rwAll", engine.KeyMin, engine.Key("b"), true},
		{readWriteMethods, "rw", engine.KeyMin, engine.Key("b"), false},
		{readWriteMethods, "random", engine.KeyMin, engine.Key("b"), false},
		{writeOnlyMethods, "writeAll", engine.KeyMin, engine.Key("b"), true},
		{writeOnlyMethods, "write1", engine.KeyMin, engine.Key("b"), false},
		{writeOnlyMethods, "write2", engine.KeyMin, engine.Key("b"), false},
		{writeOnlyMethods, "random", engine.KeyMin, engine.Key("b"), false},
		// Test permissions within and around the boundaries of a range,
		// representatively using rw methods.
		{readWriteMethods, "rw2", engine.Key("a"), engine.Key("b"), true},
		{readWriteMethods, "rwAll", engine.Key("a"), engine.Key("b"), true},
		{readWriteMethods, "rw2", engine.Key("a"), engine.Key("a"), true},
		{readWriteMethods, "rw2", engine.Key("a"), engine.Key("a1"), true},
		{readWriteMethods, "rw2", engine.Key("a"), engine.Key("b1"), false},
		{readWriteMethods, "rw2", engine.Key("a3"), engine.Key("a4"), true},
		{readWriteMethods, "rw2", engine.Key("a3"), engine.Key("b1"), false},
	}

	for _, test := range testData {
		for _, method := range test.methods {
			err := kv.verifyPermissions(
				method,
				&proto.RequestHeader{
					User: test.user, Key: test.startKey, EndKey: test.endKey})
			if err != nil && test.hasPermission {
				t.Errorf("user: %s should have had permission to %s, err: %s",
					test.user, method, err.Error())
			} else if err == nil && !test.hasPermission {
				t.Errorf("user: %s should not have had permission to %s",
					test.user, method)
			}
		}
	}
	n.Stop()
}