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 }