vitess.io/vitess@v0.16.2/go/vt/tableacl/tableacl_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tableacl
    18  
    19  import (
    20  	"errors"
    21  	"io"
    22  	"os"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"google.golang.org/protobuf/proto"
    27  
    28  	"vitess.io/vitess/go/vt/tableacl/acl"
    29  	"vitess.io/vitess/go/vt/tableacl/simpleacl"
    30  
    31  	querypb "vitess.io/vitess/go/vt/proto/query"
    32  	tableaclpb "vitess.io/vitess/go/vt/proto/tableacl"
    33  )
    34  
    35  type fakeACLFactory struct{}
    36  
    37  func (factory *fakeACLFactory) New(entries []string) (acl.ACL, error) {
    38  	return nil, errors.New("unable to create a new ACL")
    39  }
    40  
    41  func TestInitWithInvalidFilePath(t *testing.T) {
    42  	tacl := tableACL{factory: &simpleacl.Factory{}}
    43  	if err := tacl.init("/invalid_file_path", func() {}); err == nil {
    44  		t.Fatalf("init should fail for an invalid config file path")
    45  	}
    46  }
    47  
    48  var aclJSON = `{
    49    "table_groups": [
    50      {
    51        "name": "group01",
    52        "table_names_or_prefixes": ["test_table"],
    53        "readers": ["vt"],
    54        "writers": ["vt"]
    55      }
    56    ]
    57  }`
    58  
    59  func TestInitWithValidConfig(t *testing.T) {
    60  	tacl := tableACL{factory: &simpleacl.Factory{}}
    61  	f, err := os.CreateTemp("", "tableacl")
    62  	if err != nil {
    63  		t.Fatal(err)
    64  	}
    65  	defer os.Remove(f.Name())
    66  	if _, err := io.WriteString(f, aclJSON); err != nil {
    67  		t.Fatal(err)
    68  	}
    69  	if err := f.Close(); err != nil {
    70  		t.Fatal(err)
    71  	}
    72  	if err := tacl.init(f.Name(), func() {}); err != nil {
    73  		t.Fatal(err)
    74  	}
    75  }
    76  
    77  func TestInitFromProto(t *testing.T) {
    78  	tacl := tableACL{factory: &simpleacl.Factory{}}
    79  	readerACL := tacl.Authorized("my_test_table", READER)
    80  	want := &ACLResult{ACL: acl.DenyAllACL{}, GroupName: ""}
    81  	if !reflect.DeepEqual(readerACL, want) {
    82  		t.Fatalf("tableacl has not been initialized, got: %v, want: %v", readerACL, want)
    83  	}
    84  	config := &tableaclpb.Config{
    85  		TableGroups: []*tableaclpb.TableGroupSpec{{
    86  			Name:                 "group01",
    87  			TableNamesOrPrefixes: []string{"test_table"},
    88  			Readers:              []string{"vt"},
    89  		}},
    90  	}
    91  	if err := tacl.Set(config); err != nil {
    92  		t.Fatalf("tableacl init should succeed, but got error: %v", err)
    93  	}
    94  	if got := tacl.Config(); !proto.Equal(got, config) {
    95  		t.Fatalf("GetCurrentConfig() = %v, want: %v", got, config)
    96  	}
    97  	readerACL = tacl.Authorized("unknown_table", READER)
    98  	if !reflect.DeepEqual(readerACL, want) {
    99  		t.Fatalf("there is no config for unknown_table, should deny by default")
   100  	}
   101  	readerACL = tacl.Authorized("test_table", READER)
   102  	if !readerACL.IsMember(&querypb.VTGateCallerID{Username: "vt"}) {
   103  		t.Fatalf("user: vt should have reader permission to table: test_table")
   104  	}
   105  }
   106  
   107  func TestTableACLValidateConfig(t *testing.T) {
   108  	tests := []struct {
   109  		names []string
   110  		valid bool
   111  	}{
   112  		{nil, true},
   113  		{[]string{}, true},
   114  		{[]string{"b"}, true},
   115  		{[]string{"b", "a"}, true},
   116  		{[]string{"b%c"}, false},                    // invalid entry
   117  		{[]string{"aaa", "aaab%", "aaabb"}, false},  // overlapping
   118  		{[]string{"aaa", "aaab", "aaab%"}, false},   // overlapping
   119  		{[]string{"a", "aa%", "aaab%"}, false},      // overlapping
   120  		{[]string{"a", "aa%", "aaab"}, false},       // overlapping
   121  		{[]string{"a", "aa", "aaa%%"}, false},       // invalid entry
   122  		{[]string{"a", "aa", "aa", "aaaaa"}, false}, // duplicate
   123  	}
   124  	for _, test := range tests {
   125  		var groups []*tableaclpb.TableGroupSpec
   126  		for _, name := range test.names {
   127  			groups = append(groups, &tableaclpb.TableGroupSpec{
   128  				TableNamesOrPrefixes: []string{name},
   129  			})
   130  		}
   131  		config := &tableaclpb.Config{TableGroups: groups}
   132  		err := ValidateProto(config)
   133  		if test.valid && err != nil {
   134  			t.Fatalf("ValidateProto(%v) = %v, want nil", config, err)
   135  		} else if !test.valid && err == nil {
   136  			t.Fatalf("ValidateProto(%v) = nil, want error", config)
   137  		}
   138  	}
   139  }
   140  
   141  func TestTableACLAuthorize(t *testing.T) {
   142  	tacl := tableACL{factory: &simpleacl.Factory{}}
   143  	config := &tableaclpb.Config{
   144  		TableGroups: []*tableaclpb.TableGroupSpec{
   145  			{
   146  				Name:                 "group01",
   147  				TableNamesOrPrefixes: []string{"test_music"},
   148  				Readers:              []string{"u1", "u2"},
   149  				Writers:              []string{"u1", "u3"},
   150  				Admins:               []string{"u1"},
   151  			},
   152  			{
   153  				Name:                 "group02",
   154  				TableNamesOrPrefixes: []string{"test_music_02", "test_video"},
   155  				Readers:              []string{"u1", "u2"},
   156  				Writers:              []string{"u3"},
   157  				Admins:               []string{"u4"},
   158  			},
   159  			{
   160  				Name:                 "group03",
   161  				TableNamesOrPrefixes: []string{"test_other%"},
   162  				Readers:              []string{"u2"},
   163  				Writers:              []string{"u2", "u3"},
   164  				Admins:               []string{"u3"},
   165  			},
   166  			{
   167  				Name:                 "group04",
   168  				TableNamesOrPrefixes: []string{"test_data%"},
   169  				Readers:              []string{"u1", "u2"},
   170  				Writers:              []string{"u1", "u3"},
   171  				Admins:               []string{"u1"},
   172  			},
   173  		},
   174  	}
   175  	if err := tacl.Set(config); err != nil {
   176  		t.Fatalf("InitFromProto(<data>) = %v, want: nil", err)
   177  	}
   178  
   179  	readerACL := tacl.Authorized("test_data_any", READER)
   180  	if !readerACL.IsMember(&querypb.VTGateCallerID{Username: "u1"}) {
   181  		t.Fatalf("user u1 should have reader permission to table test_data_any")
   182  	}
   183  	if !readerACL.IsMember(&querypb.VTGateCallerID{Username: "u2"}) {
   184  		t.Fatalf("user u2 should have reader permission to table test_data_any")
   185  	}
   186  }
   187  
   188  func TestFailedToCreateACL(t *testing.T) {
   189  	tacl := tableACL{factory: &fakeACLFactory{}}
   190  	config := &tableaclpb.Config{
   191  		TableGroups: []*tableaclpb.TableGroupSpec{{
   192  			Name:                 "group01",
   193  			TableNamesOrPrefixes: []string{"test_table"},
   194  			Readers:              []string{"vt"},
   195  			Writers:              []string{"vt"},
   196  		}},
   197  	}
   198  	if err := tacl.Set(config); err == nil {
   199  		t.Fatalf("tableacl init should fail because fake ACL returns an error")
   200  	}
   201  }
   202  
   203  func TestDoubleRegisterTheSameKey(t *testing.T) {
   204  	name := "tableacl-name-TestDoubleRegisterTheSameKey"
   205  	Register(name, &simpleacl.Factory{})
   206  	defer func() {
   207  		err := recover()
   208  		if err == nil {
   209  			t.Fatalf("the second tableacl register should fail")
   210  		}
   211  	}()
   212  	Register(name, &simpleacl.Factory{})
   213  }
   214  
   215  func TestGetCurrentAclFactory(t *testing.T) {
   216  	acls = make(map[string]acl.Factory)
   217  	defaultACL = ""
   218  	name := "tableacl-name-TestGetCurrentAclFactory"
   219  	aclFactory := &simpleacl.Factory{}
   220  	Register(name+"-1", aclFactory)
   221  	f, err := GetCurrentACLFactory()
   222  	if err != nil {
   223  		t.Errorf("Fail to get current ACL Factory: %v", err)
   224  	}
   225  	if !reflect.DeepEqual(aclFactory, f) {
   226  		t.Fatalf("should return registered acl factory even if default acl is not set.")
   227  	}
   228  	Register(name+"-2", aclFactory)
   229  	_, err = GetCurrentACLFactory()
   230  	if err == nil {
   231  		t.Fatalf("there are more than one acl factories, but the default is not set")
   232  	}
   233  }
   234  
   235  func TestGetCurrentACLFactoryWithWrongDefault(t *testing.T) {
   236  	acls = make(map[string]acl.Factory)
   237  	defaultACL = ""
   238  	name := "tableacl-name-TestGetCurrentAclFactoryWithWrongDefault"
   239  	aclFactory := &simpleacl.Factory{}
   240  	Register(name+"-1", aclFactory)
   241  	Register(name+"-2", aclFactory)
   242  	SetDefaultACL("wrong_name")
   243  	_, err := GetCurrentACLFactory()
   244  	if err == nil {
   245  		t.Fatalf("there are more than one acl factories, but the default given does not match any of these.")
   246  	}
   247  }