github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/integration/v3_auth_test.go (about) 1 // Copyright 2017 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package integration 16 17 import ( 18 "context" 19 "fmt" 20 "sync" 21 "testing" 22 "time" 23 24 "github.com/lfch/etcd-io/api/v3/authpb" 25 pb "github.com/lfch/etcd-io/api/v3/etcdserverpb" 26 "github.com/lfch/etcd-io/api/v3/v3rpc/rpctypes" 27 "github.com/lfch/etcd-io/client/pkg/v3/testutil" 28 "github.com/lfch/etcd-io/client/v3" 29 "github.com/lfch/etcd-io/tests/v3/framework/integration" 30 ) 31 32 // TestV3AuthEmptyUserGet ensures that a get with an empty user will return an empty user error. 33 func TestV3AuthEmptyUserGet(t *testing.T) { 34 integration.BeforeTest(t) 35 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 36 defer clus.Terminate(t) 37 38 ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second) 39 defer cancel() 40 41 api := integration.ToGRPC(clus.Client(0)) 42 authSetupRoot(t, api.Auth) 43 44 _, err := api.KV.Range(ctx, &pb.RangeRequest{Key: []byte("abc")}) 45 if !eqErrGRPC(err, rpctypes.ErrUserEmpty) { 46 t.Fatalf("got %v, expected %v", err, rpctypes.ErrUserEmpty) 47 } 48 } 49 50 // TestV3AuthEmptyUserPut ensures that a put with an empty user will return an empty user error, 51 // and the consistent_index should be moved forward even the apply-->Put fails. 52 func TestV3AuthEmptyUserPut(t *testing.T) { 53 integration.BeforeTest(t) 54 clus := integration.NewCluster(t, &integration.ClusterConfig{ 55 Size: 1, 56 SnapshotCount: 3, 57 }) 58 defer clus.Terminate(t) 59 60 ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second) 61 defer cancel() 62 63 api := integration.ToGRPC(clus.Client(0)) 64 authSetupRoot(t, api.Auth) 65 66 // The SnapshotCount is 3, so there must be at least 3 new snapshot files being created. 67 // The VERIFY logic will check whether the consistent_index >= last snapshot index on 68 // cluster terminating. 69 for i := 0; i < 10; i++ { 70 _, err := api.KV.Put(ctx, &pb.PutRequest{Key: []byte("foo"), Value: []byte("bar")}) 71 if !eqErrGRPC(err, rpctypes.ErrUserEmpty) { 72 t.Fatalf("got %v, expected %v", err, rpctypes.ErrUserEmpty) 73 } 74 } 75 } 76 77 // TestV3AuthTokenWithDisable tests that auth won't crash if 78 // given a valid token when authentication is disabled 79 func TestV3AuthTokenWithDisable(t *testing.T) { 80 integration.BeforeTest(t) 81 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 82 defer clus.Terminate(t) 83 84 authSetupRoot(t, integration.ToGRPC(clus.Client(0)).Auth) 85 86 c, cerr := integration.NewClient(t, clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "root", Password: "123"}) 87 if cerr != nil { 88 t.Fatal(cerr) 89 } 90 defer c.Close() 91 92 rctx, cancel := context.WithCancel(context.TODO()) 93 donec := make(chan struct{}) 94 go func() { 95 defer close(donec) 96 for rctx.Err() == nil { 97 c.Put(rctx, "abc", "def") 98 } 99 }() 100 101 time.Sleep(10 * time.Millisecond) 102 if _, err := c.AuthDisable(context.TODO()); err != nil { 103 t.Fatal(err) 104 } 105 time.Sleep(10 * time.Millisecond) 106 107 cancel() 108 <-donec 109 } 110 111 func TestV3AuthRevision(t *testing.T) { 112 integration.BeforeTest(t) 113 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 114 defer clus.Terminate(t) 115 116 api := integration.ToGRPC(clus.Client(0)) 117 118 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 119 presp, perr := api.KV.Put(ctx, &pb.PutRequest{Key: []byte("foo"), Value: []byte("bar")}) 120 cancel() 121 if perr != nil { 122 t.Fatal(perr) 123 } 124 rev := presp.Header.Revision 125 126 ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) 127 aresp, aerr := api.Auth.UserAdd(ctx, &pb.AuthUserAddRequest{Name: "root", Password: "123", Options: &authpb.UserAddOptions{NoPassword: false}}) 128 cancel() 129 if aerr != nil { 130 t.Fatal(aerr) 131 } 132 if aresp.Header.Revision != rev { 133 t.Fatalf("revision expected %d, got %d", rev, aresp.Header.Revision) 134 } 135 } 136 137 // TestV3AuthWithLeaseRevokeWithRoot ensures that granted leases 138 // with root user be revoked after TTL. 139 func TestV3AuthWithLeaseRevokeWithRoot(t *testing.T) { 140 testV3AuthWithLeaseRevokeWithRoot(t, integration.ClusterConfig{Size: 1}) 141 } 142 143 // TestV3AuthWithLeaseRevokeWithRootJWT creates a lease with a JWT-token enabled cluster. 144 // And tests if server is able to revoke expiry lease item. 145 func TestV3AuthWithLeaseRevokeWithRootJWT(t *testing.T) { 146 testV3AuthWithLeaseRevokeWithRoot(t, integration.ClusterConfig{Size: 1, AuthToken: integration.DefaultTokenJWT}) 147 } 148 149 func testV3AuthWithLeaseRevokeWithRoot(t *testing.T, ccfg integration.ClusterConfig) { 150 integration.BeforeTest(t) 151 152 clus := integration.NewCluster(t, &ccfg) 153 defer clus.Terminate(t) 154 155 api := integration.ToGRPC(clus.Client(0)) 156 authSetupRoot(t, api.Auth) 157 158 rootc, cerr := integration.NewClient(t, clientv3.Config{ 159 Endpoints: clus.Client(0).Endpoints(), 160 Username: "root", 161 Password: "123", 162 }) 163 if cerr != nil { 164 t.Fatal(cerr) 165 } 166 defer rootc.Close() 167 168 leaseResp, err := rootc.Grant(context.TODO(), 2) 169 if err != nil { 170 t.Fatal(err) 171 } 172 leaseID := leaseResp.ID 173 174 if _, err = rootc.Put(context.TODO(), "foo", "bar", clientv3.WithLease(leaseID)); err != nil { 175 t.Fatal(err) 176 } 177 178 // wait for lease expire 179 time.Sleep(3 * time.Second) 180 181 tresp, terr := api.Lease.LeaseTimeToLive( 182 context.TODO(), 183 &pb.LeaseTimeToLiveRequest{ 184 ID: int64(leaseID), 185 Keys: true, 186 }, 187 ) 188 if terr != nil { 189 t.Error(terr) 190 } 191 if len(tresp.Keys) > 0 || tresp.GrantedTTL != 0 { 192 t.Errorf("lease %016x should have been revoked, got %+v", leaseID, tresp) 193 } 194 if tresp.TTL != -1 { 195 t.Errorf("lease %016x should have been expired, got %+v", leaseID, tresp) 196 } 197 } 198 199 type user struct { 200 name string 201 password string 202 role string 203 key string 204 end string 205 } 206 207 func TestV3AuthWithLeaseRevoke(t *testing.T) { 208 integration.BeforeTest(t) 209 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 210 defer clus.Terminate(t) 211 212 users := []user{ 213 { 214 name: "user1", 215 password: "user1-123", 216 role: "role1", 217 key: "k1", 218 end: "k2", 219 }, 220 } 221 authSetupUsers(t, integration.ToGRPC(clus.Client(0)).Auth, users) 222 223 authSetupRoot(t, integration.ToGRPC(clus.Client(0)).Auth) 224 225 rootc, cerr := integration.NewClient(t, clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "root", Password: "123"}) 226 if cerr != nil { 227 t.Fatal(cerr) 228 } 229 defer rootc.Close() 230 231 leaseResp, err := rootc.Grant(context.TODO(), 90) 232 if err != nil { 233 t.Fatal(err) 234 } 235 leaseID := leaseResp.ID 236 // permission of k3 isn't granted to user1 237 _, err = rootc.Put(context.TODO(), "k3", "val", clientv3.WithLease(leaseID)) 238 if err != nil { 239 t.Fatal(err) 240 } 241 242 userc, cerr := integration.NewClient(t, clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "user1", Password: "user1-123"}) 243 if cerr != nil { 244 t.Fatal(cerr) 245 } 246 defer userc.Close() 247 _, err = userc.Revoke(context.TODO(), leaseID) 248 if err == nil { 249 t.Fatal("revoking from user1 should be failed with permission denied") 250 } 251 } 252 253 func TestV3AuthWithLeaseAttach(t *testing.T) { 254 integration.BeforeTest(t) 255 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 256 defer clus.Terminate(t) 257 258 users := []user{ 259 { 260 name: "user1", 261 password: "user1-123", 262 role: "role1", 263 key: "k1", 264 end: "k3", 265 }, 266 { 267 name: "user2", 268 password: "user2-123", 269 role: "role2", 270 key: "k2", 271 end: "k4", 272 }, 273 } 274 authSetupUsers(t, integration.ToGRPC(clus.Client(0)).Auth, users) 275 276 authSetupRoot(t, integration.ToGRPC(clus.Client(0)).Auth) 277 278 user1c, cerr := integration.NewClient(t, clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "user1", Password: "user1-123"}) 279 if cerr != nil { 280 t.Fatal(cerr) 281 } 282 defer user1c.Close() 283 284 user2c, cerr := integration.NewClient(t, clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "user2", Password: "user2-123"}) 285 if cerr != nil { 286 t.Fatal(cerr) 287 } 288 defer user2c.Close() 289 290 leaseResp, err := user1c.Grant(context.TODO(), 90) 291 if err != nil { 292 t.Fatal(err) 293 } 294 leaseID := leaseResp.ID 295 // permission of k2 is also granted to user2 296 _, err = user1c.Put(context.TODO(), "k2", "val", clientv3.WithLease(leaseID)) 297 if err != nil { 298 t.Fatal(err) 299 } 300 301 _, err = user2c.Revoke(context.TODO(), leaseID) 302 if err != nil { 303 t.Fatal(err) 304 } 305 306 leaseResp, err = user1c.Grant(context.TODO(), 90) 307 if err != nil { 308 t.Fatal(err) 309 } 310 leaseID = leaseResp.ID 311 // permission of k1 isn't granted to user2 312 _, err = user1c.Put(context.TODO(), "k1", "val", clientv3.WithLease(leaseID)) 313 if err != nil { 314 t.Fatal(err) 315 } 316 317 _, err = user2c.Revoke(context.TODO(), leaseID) 318 if err == nil { 319 t.Fatal("revoking from user2 should be failed with permission denied") 320 } 321 } 322 323 func authSetupUsers(t *testing.T, auth pb.AuthClient, users []user) { 324 for _, user := range users { 325 if _, err := auth.UserAdd(context.TODO(), &pb.AuthUserAddRequest{Name: user.name, Password: user.password, Options: &authpb.UserAddOptions{NoPassword: false}}); err != nil { 326 t.Fatal(err) 327 } 328 if _, err := auth.RoleAdd(context.TODO(), &pb.AuthRoleAddRequest{Name: user.role}); err != nil { 329 t.Fatal(err) 330 } 331 if _, err := auth.UserGrantRole(context.TODO(), &pb.AuthUserGrantRoleRequest{User: user.name, Role: user.role}); err != nil { 332 t.Fatal(err) 333 } 334 335 if len(user.key) == 0 { 336 continue 337 } 338 339 perm := &authpb.Permission{ 340 PermType: authpb.READWRITE, 341 Key: []byte(user.key), 342 RangeEnd: []byte(user.end), 343 } 344 if _, err := auth.RoleGrantPermission(context.TODO(), &pb.AuthRoleGrantPermissionRequest{Name: user.role, Perm: perm}); err != nil { 345 t.Fatal(err) 346 } 347 } 348 } 349 350 func authSetupRoot(t *testing.T, auth pb.AuthClient) { 351 root := []user{ 352 { 353 name: "root", 354 password: "123", 355 role: "root", 356 key: "", 357 }, 358 } 359 authSetupUsers(t, auth, root) 360 if _, err := auth.AuthEnable(context.TODO(), &pb.AuthEnableRequest{}); err != nil { 361 t.Fatal(err) 362 } 363 } 364 365 func TestV3AuthNonAuthorizedRPCs(t *testing.T) { 366 integration.BeforeTest(t) 367 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 368 defer clus.Terminate(t) 369 370 nonAuthedKV := clus.Client(0).KV 371 372 key := "foo" 373 val := "bar" 374 _, err := nonAuthedKV.Put(context.TODO(), key, val) 375 if err != nil { 376 t.Fatalf("couldn't put key (%v)", err) 377 } 378 379 authSetupRoot(t, integration.ToGRPC(clus.Client(0)).Auth) 380 381 respput, err := nonAuthedKV.Put(context.TODO(), key, val) 382 if !eqErrGRPC(err, rpctypes.ErrGRPCUserEmpty) { 383 t.Fatalf("could put key (%v), it should cause an error of permission denied", respput) 384 } 385 } 386 387 func TestV3AuthOldRevConcurrent(t *testing.T) { 388 integration.BeforeTest(t) 389 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 390 defer clus.Terminate(t) 391 392 authSetupRoot(t, integration.ToGRPC(clus.Client(0)).Auth) 393 394 c, cerr := integration.NewClient(t, clientv3.Config{ 395 Endpoints: clus.Client(0).Endpoints(), 396 DialTimeout: 5 * time.Second, 397 Username: "root", 398 Password: "123", 399 }) 400 testutil.AssertNil(t, cerr) 401 defer c.Close() 402 403 var wg sync.WaitGroup 404 f := func(i int) { 405 defer wg.Done() 406 role, user := fmt.Sprintf("test-role-%d", i), fmt.Sprintf("test-user-%d", i) 407 _, err := c.RoleAdd(context.TODO(), role) 408 testutil.AssertNil(t, err) 409 _, err = c.RoleGrantPermission(context.TODO(), role, "", clientv3.GetPrefixRangeEnd(""), clientv3.PermissionType(clientv3.PermReadWrite)) 410 testutil.AssertNil(t, err) 411 _, err = c.UserAdd(context.TODO(), user, "123") 412 testutil.AssertNil(t, err) 413 _, err = c.Put(context.TODO(), "a", "b") 414 testutil.AssertNil(t, err) 415 } 416 // needs concurrency to trigger 417 numRoles := 2 418 wg.Add(numRoles) 419 for i := 0; i < numRoles; i++ { 420 go f(i) 421 } 422 wg.Wait() 423 } 424 425 func TestV3AuthRestartMember(t *testing.T) { 426 integration.BeforeTest(t) 427 428 // create a cluster with 1 member 429 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 430 defer clus.Terminate(t) 431 432 // create a client 433 c, cerr := integration.NewClient(t, clientv3.Config{ 434 Endpoints: clus.Client(0).Endpoints(), 435 DialTimeout: 5 * time.Second, 436 }) 437 testutil.AssertNil(t, cerr) 438 defer c.Close() 439 440 authData := []struct { 441 user string 442 role string 443 pass string 444 }{ 445 { 446 user: "root", 447 role: "root", 448 pass: "123", 449 }, 450 { 451 user: "user0", 452 role: "role0", 453 pass: "123", 454 }, 455 } 456 457 for _, authObj := range authData { 458 // add a role 459 _, err := c.RoleAdd(context.TODO(), authObj.role) 460 testutil.AssertNil(t, err) 461 // add a user 462 _, err = c.UserAdd(context.TODO(), authObj.user, authObj.pass) 463 testutil.AssertNil(t, err) 464 // grant role to user 465 _, err = c.UserGrantRole(context.TODO(), authObj.user, authObj.role) 466 testutil.AssertNil(t, err) 467 } 468 469 // role grant permission to role0 470 _, err := c.RoleGrantPermission(context.TODO(), authData[1].role, "foo", "", clientv3.PermissionType(clientv3.PermReadWrite)) 471 testutil.AssertNil(t, err) 472 473 // enable auth 474 _, err = c.AuthEnable(context.TODO()) 475 testutil.AssertNil(t, err) 476 477 // create another client with ID:Password 478 c2, cerr := integration.NewClient(t, clientv3.Config{ 479 Endpoints: clus.Client(0).Endpoints(), 480 DialTimeout: 5 * time.Second, 481 Username: authData[1].user, 482 Password: authData[1].pass, 483 }) 484 testutil.AssertNil(t, cerr) 485 defer c2.Close() 486 487 // create foo since that is within the permission set 488 // expectation is to succeed 489 _, err = c2.Put(context.TODO(), "foo", "bar") 490 testutil.AssertNil(t, err) 491 492 clus.Members[0].Stop(t) 493 err = clus.Members[0].Restart(t) 494 testutil.AssertNil(t, err) 495 integration.WaitClientV3WithKey(t, c2.KV, "foo") 496 497 // nothing has changed, but it fails without refreshing cache after restart 498 _, err = c2.Put(context.TODO(), "foo", "bar2") 499 testutil.AssertNil(t, err) 500 } 501 502 func TestV3AuthWatchAndTokenExpire(t *testing.T) { 503 integration.BeforeTest(t) 504 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1, AuthTokenTTL: 3}) 505 defer clus.Terminate(t) 506 507 ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second) 508 defer cancel() 509 510 authSetupRoot(t, integration.ToGRPC(clus.Client(0)).Auth) 511 512 c, cerr := integration.NewClient(t, clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "root", Password: "123"}) 513 if cerr != nil { 514 t.Fatal(cerr) 515 } 516 defer c.Close() 517 518 _, err := c.Put(ctx, "key", "val") 519 if err != nil { 520 t.Fatalf("Unexpected error from Put: %v", err) 521 } 522 523 // The first watch gets a valid auth token through watcher.newWatcherGrpcStream() 524 // We should discard the first one by waiting TTL after the first watch. 525 wChan := c.Watch(ctx, "key", clientv3.WithRev(1)) 526 watchResponse := <-wChan 527 528 time.Sleep(5 * time.Second) 529 530 wChan = c.Watch(ctx, "key", clientv3.WithRev(1)) 531 watchResponse = <-wChan 532 testutil.AssertNil(t, watchResponse.Err()) 533 } 534 535 func TestV3AuthWatchErrorAndWatchId0(t *testing.T) { 536 integration.BeforeTest(t) 537 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) 538 defer clus.Terminate(t) 539 540 ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second) 541 defer cancel() 542 543 users := []user{ 544 { 545 name: "user1", 546 password: "user1-123", 547 role: "role1", 548 key: "k1", 549 end: "k2", 550 }, 551 } 552 authSetupUsers(t, integration.ToGRPC(clus.Client(0)).Auth, users) 553 554 authSetupRoot(t, integration.ToGRPC(clus.Client(0)).Auth) 555 556 c, cerr := integration.NewClient(t, clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "user1", Password: "user1-123"}) 557 if cerr != nil { 558 t.Fatal(cerr) 559 } 560 defer c.Close() 561 562 watchStartCh, watchEndCh := make(chan interface{}), make(chan interface{}) 563 564 go func() { 565 wChan := c.Watch(ctx, "k1", clientv3.WithRev(1)) 566 watchStartCh <- struct{}{} 567 watchResponse := <-wChan 568 t.Logf("watch response from k1: %v", watchResponse) 569 testutil.AssertTrue(t, len(watchResponse.Events) != 0) 570 watchEndCh <- struct{}{} 571 }() 572 573 // Chan for making sure that the above goroutine invokes Watch() 574 // So the above Watch() can get watch ID = 0 575 <-watchStartCh 576 577 wChan := c.Watch(ctx, "non-allowed-key", clientv3.WithRev(1)) 578 watchResponse := <-wChan 579 testutil.AssertNotNil(t, watchResponse.Err()) // permission denied 580 581 _, err := c.Put(ctx, "k1", "val") 582 if err != nil { 583 t.Fatalf("Unexpected error from Put: %v", err) 584 } 585 586 <-watchEndCh 587 }