github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/admin-handlers-users_test.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "bytes" 22 "context" 23 "crypto/sha256" 24 "encoding/hex" 25 "encoding/json" 26 "fmt" 27 "io" 28 "net/http" 29 "net/url" 30 "runtime" 31 "strings" 32 "testing" 33 "time" 34 35 "github.com/minio/madmin-go/v3" 36 "github.com/minio/minio-go/v7" 37 "github.com/minio/minio-go/v7/pkg/credentials" 38 "github.com/minio/minio-go/v7/pkg/s3utils" 39 "github.com/minio/minio-go/v7/pkg/set" 40 "github.com/minio/minio-go/v7/pkg/signer" 41 "github.com/minio/minio/internal/auth" 42 "github.com/minio/pkg/v2/env" 43 ) 44 45 const ( 46 testDefaultTimeout = 30 * time.Second 47 ) 48 49 // API suite container for IAM 50 type TestSuiteIAM struct { 51 TestSuiteCommon 52 53 ServerTypeDescription string 54 55 // Flag to turn on tests for etcd backend IAM 56 withEtcdBackend bool 57 58 endpoint string 59 adm *madmin.AdminClient 60 client *minio.Client 61 } 62 63 func newTestSuiteIAM(c TestSuiteCommon, withEtcdBackend bool) *TestSuiteIAM { 64 etcdStr := "" 65 if withEtcdBackend { 66 etcdStr = " (with etcd backend)" 67 } 68 return &TestSuiteIAM{ 69 TestSuiteCommon: c, 70 ServerTypeDescription: fmt.Sprintf("%s%s", c.serverType, etcdStr), 71 withEtcdBackend: withEtcdBackend, 72 } 73 } 74 75 func (s *TestSuiteIAM) iamSetup(c *check) { 76 var err error 77 // strip url scheme from endpoint 78 s.endpoint = strings.TrimPrefix(s.endPoint, "http://") 79 if s.secure { 80 s.endpoint = strings.TrimPrefix(s.endPoint, "https://") 81 } 82 83 s.adm, err = madmin.New(s.endpoint, s.accessKey, s.secretKey, s.secure) 84 if err != nil { 85 c.Fatalf("error creating admin client: %v", err) 86 } 87 // Set transport, so that TLS is handled correctly. 88 s.adm.SetCustomTransport(s.TestSuiteCommon.client.Transport) 89 90 s.client, err = minio.New(s.endpoint, &minio.Options{ 91 Creds: credentials.NewStaticV4(s.accessKey, s.secretKey, ""), 92 Secure: s.secure, 93 Transport: s.TestSuiteCommon.client.Transport, 94 }) 95 if err != nil { 96 c.Fatalf("error creating minio client: %v", err) 97 } 98 } 99 100 // List of all IAM test suites (i.e. test server configuration combinations) 101 // common to tests. 102 var iamTestSuites = func() []*TestSuiteIAM { 103 baseTestCases := []TestSuiteCommon{ 104 // Init and run test on ErasureSD backend with signature v4. 105 {serverType: "ErasureSD", signer: signerV4}, 106 // Init and run test on ErasureSD backend, with tls enabled. 107 {serverType: "ErasureSD", signer: signerV4, secure: true}, 108 // Init and run test on Erasure backend. 109 {serverType: "Erasure", signer: signerV4}, 110 // Init and run test on ErasureSet backend. 111 {serverType: "ErasureSet", signer: signerV4}, 112 } 113 testCases := []*TestSuiteIAM{} 114 for _, bt := range baseTestCases { 115 testCases = append(testCases, 116 newTestSuiteIAM(bt, false), 117 newTestSuiteIAM(bt, true), 118 ) 119 } 120 return testCases 121 }() 122 123 const ( 124 EnvTestEtcdBackend = "_MINIO_ETCD_TEST_SERVER" 125 ) 126 127 func (s *TestSuiteIAM) setUpEtcd(c *check, etcdServer string) { 128 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 129 defer cancel() 130 131 configCmds := []string{ 132 "etcd", 133 "endpoints=" + etcdServer, 134 "path_prefix=" + mustGetUUID(), 135 } 136 _, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " ")) 137 if err != nil { 138 c.Fatalf("unable to setup Etcd for tests: %v", err) 139 } 140 141 s.RestartIAMSuite(c) 142 } 143 144 func (s *TestSuiteIAM) SetUpSuite(c *check) { 145 // If etcd backend is specified and etcd server is not present, the test 146 // is skipped. 147 etcdServer := env.Get(EnvTestEtcdBackend, "") 148 if s.withEtcdBackend && etcdServer == "" { 149 c.Skip("Skipping etcd backend IAM test as no etcd server is configured.") 150 } 151 152 s.TestSuiteCommon.SetUpSuite(c) 153 154 s.iamSetup(c) 155 156 if s.withEtcdBackend { 157 s.setUpEtcd(c, etcdServer) 158 } 159 } 160 161 func (s *TestSuiteIAM) RestartIAMSuite(c *check) { 162 s.TestSuiteCommon.RestartTestServer(c) 163 164 s.iamSetup(c) 165 } 166 167 func (s *TestSuiteIAM) getAdminClient(c *check, accessKey, secretKey, sessionToken string) *madmin.AdminClient { 168 madmClnt, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ 169 Creds: credentials.NewStaticV4(accessKey, secretKey, sessionToken), 170 Secure: s.secure, 171 }) 172 if err != nil { 173 c.Fatalf("error creating user admin client: %s", err) 174 } 175 madmClnt.SetCustomTransport(s.TestSuiteCommon.client.Transport) 176 return madmClnt 177 } 178 179 func (s *TestSuiteIAM) getUserClient(c *check, accessKey, secretKey, sessionToken string) *minio.Client { 180 client, err := minio.New(s.endpoint, &minio.Options{ 181 Creds: credentials.NewStaticV4(accessKey, secretKey, sessionToken), 182 Secure: s.secure, 183 Transport: s.TestSuiteCommon.client.Transport, 184 }) 185 if err != nil { 186 c.Fatalf("error creating user minio client: %s", err) 187 } 188 return client 189 } 190 191 func TestIAMInternalIDPServerSuite(t *testing.T) { 192 if runtime.GOOS == globalWindowsOSName { 193 t.Skip("windows is clunky disable these tests") 194 } 195 for i, testCase := range iamTestSuites { 196 t.Run( 197 fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription), 198 func(t *testing.T) { 199 suite := testCase 200 c := &check{t, testCase.serverType} 201 202 suite.SetUpSuite(c) 203 suite.TestUserCreate(c) 204 suite.TestUserPolicyEscalationBug(c) 205 suite.TestPolicyCreate(c) 206 suite.TestCannedPolicies(c) 207 suite.TestGroupAddRemove(c) 208 suite.TestServiceAccountOpsByAdmin(c) 209 suite.TestServiceAccountPrivilegeEscalationBug(c) 210 suite.TestServiceAccountOpsByUser(c) 211 suite.TestServiceAccountDurationSecondsCondition(c) 212 suite.TestAddServiceAccountPerms(c) 213 suite.TearDownSuite(c) 214 }, 215 ) 216 } 217 } 218 219 func (s *TestSuiteIAM) TestUserCreate(c *check) { 220 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 221 defer cancel() 222 223 // 1. Create a user. 224 accessKey, secretKey := mustGenerateCredentials(c) 225 err := s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 226 if err != nil { 227 c.Fatalf("Unable to set user: %v", err) 228 } 229 230 // 2. Check new user appears in listing 231 usersMap, err := s.adm.ListUsers(ctx) 232 if err != nil { 233 c.Fatalf("error listing: %v", err) 234 } 235 v, ok := usersMap[accessKey] 236 if !ok { 237 c.Fatalf("user not listed: %s", accessKey) 238 } 239 c.Assert(v.Status, madmin.AccountEnabled) 240 241 // 3. Associate policy and check that user can access 242 err = s.adm.SetPolicy(ctx, "readwrite", accessKey, false) 243 if err != nil { 244 c.Fatalf("unable to set policy: %v", err) 245 } 246 247 client := s.getUserClient(c, accessKey, secretKey, "") 248 err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) 249 if err != nil { 250 c.Fatalf("user could not create bucket: %v", err) 251 } 252 253 // 3.10. Check that user's password can be updated. 254 _, newSecretKey := mustGenerateCredentials(c) 255 err = s.adm.SetUser(ctx, accessKey, newSecretKey, madmin.AccountEnabled) 256 if err != nil { 257 c.Fatalf("Unable to update user's secret key: %v", err) 258 } 259 // 3.10.1 Check that old password no longer works. 260 err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) 261 if err == nil { 262 c.Fatalf("user was unexpectedly able to create bucket with bad password!") 263 } 264 // 3.10.2 Check that new password works. 265 client = s.getUserClient(c, accessKey, newSecretKey, "") 266 err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) 267 if err != nil { 268 c.Fatalf("user could not create bucket: %v", err) 269 } 270 271 // 4. Check that user can be disabled and verify it. 272 err = s.adm.SetUserStatus(ctx, accessKey, madmin.AccountDisabled) 273 if err != nil { 274 c.Fatalf("could not set user account to disabled") 275 } 276 usersMap, err = s.adm.ListUsers(ctx) 277 if err != nil { 278 c.Fatalf("error listing: %v", err) 279 } 280 v, ok = usersMap[accessKey] 281 if !ok { 282 c.Fatalf("user was not listed after disabling: %s", accessKey) 283 } 284 c.Assert(v.Status, madmin.AccountDisabled) 285 err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) 286 if err == nil { 287 c.Fatalf("user account was not disabled!") 288 } 289 290 // 5. Check that user can be deleted and verify it. 291 err = s.adm.RemoveUser(ctx, accessKey) 292 if err != nil { 293 c.Fatalf("user could not be deleted: %v", err) 294 } 295 usersMap, err = s.adm.ListUsers(ctx) 296 if err != nil { 297 c.Fatalf("error listing: %v", err) 298 } 299 _, ok = usersMap[accessKey] 300 if ok { 301 c.Fatalf("user not deleted: %s", accessKey) 302 } 303 err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) 304 if err == nil { 305 c.Fatalf("user account was not deleted!") 306 } 307 } 308 309 func (s *TestSuiteIAM) TestUserPolicyEscalationBug(c *check) { 310 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 311 defer cancel() 312 313 bucket := getRandomBucketName() 314 err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 315 if err != nil { 316 c.Fatalf("bucket creat error: %v", err) 317 } 318 319 // 2. Create a user, associate policy and verify access 320 accessKey, secretKey := mustGenerateCredentials(c) 321 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 322 if err != nil { 323 c.Fatalf("Unable to set user: %v", err) 324 } 325 // 2.1 check that user does not have any access to the bucket 326 uClient := s.getUserClient(c, accessKey, secretKey, "") 327 c.mustNotListObjects(ctx, uClient, bucket) 328 329 // 2.2 create and associate policy to user 330 policy := "mypolicy-test-user-update" 331 policyBytes := []byte(fmt.Sprintf(`{ 332 "Version": "2012-10-17", 333 "Statement": [ 334 { 335 "Effect": "Allow", 336 "Action": [ 337 "s3:PutObject", 338 "s3:GetObject", 339 "s3:ListBucket" 340 ], 341 "Resource": [ 342 "arn:aws:s3:::%s/*" 343 ] 344 } 345 ] 346 }`, bucket)) 347 err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) 348 if err != nil { 349 c.Fatalf("policy add error: %v", err) 350 } 351 err = s.adm.SetPolicy(ctx, policy, accessKey, false) 352 if err != nil { 353 c.Fatalf("Unable to set policy: %v", err) 354 } 355 // 2.3 check user has access to bucket 356 c.mustListObjects(ctx, uClient, bucket) 357 // 2.3 check that user cannot delete the bucket 358 err = uClient.RemoveBucket(ctx, bucket) 359 if err == nil || err.Error() != "Access Denied." { 360 c.Fatalf("bucket was deleted unexpectedly or got unexpected err: %v", err) 361 } 362 363 // 3. Craft a request to update the user's permissions 364 ep := s.adm.GetEndpointURL() 365 urlValue := url.Values{} 366 urlValue.Add("accessKey", accessKey) 367 u, err := url.Parse(fmt.Sprintf("%s://%s/minio/admin/v3/add-user?%s", ep.Scheme, ep.Host, s3utils.QueryEncode(urlValue))) 368 if err != nil { 369 c.Fatalf("unexpected url parse err: %v", err) 370 } 371 req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) 372 if err != nil { 373 c.Fatalf("unexpected new request err: %v", err) 374 } 375 reqBodyArg := madmin.UserInfo{ 376 SecretKey: secretKey, 377 PolicyName: "consoleAdmin", 378 Status: madmin.AccountEnabled, 379 } 380 buf, err := json.Marshal(reqBodyArg) 381 if err != nil { 382 c.Fatalf("unexpected json encode err: %v", err) 383 } 384 buf, err = madmin.EncryptData(secretKey, buf) 385 if err != nil { 386 c.Fatalf("unexpected encryption err: %v", err) 387 } 388 389 req.ContentLength = int64(len(buf)) 390 sum := sha256.Sum256(buf) 391 req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(sum[:])) 392 req.Body = io.NopCloser(bytes.NewReader(buf)) 393 req = signer.SignV4(*req, accessKey, secretKey, "", "") 394 395 // 3.1 Execute the request. 396 resp, err := s.TestSuiteCommon.client.Do(req) 397 if err != nil { 398 c.Fatalf("unexpected request err: %v", err) 399 } 400 if resp.StatusCode != 200 { 401 c.Fatalf("got unexpected response: %#v\n", resp) 402 } 403 404 // 3.2 check that user cannot delete the bucket 405 err = uClient.RemoveBucket(ctx, bucket) 406 if err == nil || err.Error() != "Access Denied." { 407 c.Fatalf("User was able to escalate privileges (Err=%v)!", err) 408 } 409 } 410 411 func (s *TestSuiteIAM) TestAddServiceAccountPerms(c *check) { 412 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 413 defer cancel() 414 415 // 1. Create a policy 416 policy1 := "deny-svc" 417 policy2 := "allow-svc" 418 policyBytes := []byte(`{ 419 "Version": "2012-10-17", 420 "Statement": [ 421 { 422 "Effect": "Deny", 423 "Action": [ 424 "admin:CreateServiceAccount" 425 ] 426 } 427 ] 428 }`) 429 430 newPolicyBytes := []byte(`{ 431 "Version": "2012-10-17", 432 "Statement": [ 433 { 434 "Effect": "Allow", 435 "Action": [ 436 "s3:ListBucket" 437 ], 438 "Resource": [ 439 "arn:aws:s3:::testbucket/*" 440 ] 441 } 442 ] 443 }`) 444 445 err := s.adm.AddCannedPolicy(ctx, policy1, policyBytes) 446 if err != nil { 447 c.Fatalf("policy add error: %v", err) 448 } 449 450 err = s.adm.AddCannedPolicy(ctx, policy2, newPolicyBytes) 451 if err != nil { 452 c.Fatalf("policy add error: %v", err) 453 } 454 455 // 2. Verify that policy json is validated by server 456 invalidPolicyBytes := policyBytes[:len(policyBytes)-1] 457 err = s.adm.AddCannedPolicy(ctx, policy1+"invalid", invalidPolicyBytes) 458 if err == nil { 459 c.Fatalf("invalid policy creation success") 460 } 461 462 // 3. Create a user, associate policy and verify access 463 accessKey, secretKey := mustGenerateCredentials(c) 464 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 465 if err != nil { 466 c.Fatalf("Unable to set user: %v", err) 467 } 468 // 3.1 check that user does not have any access to the bucket 469 uClient := s.getUserClient(c, accessKey, secretKey, "") 470 c.mustNotListObjects(ctx, uClient, "testbucket") 471 472 // 3.2 associate policy to user 473 err = s.adm.SetPolicy(ctx, policy1, accessKey, false) 474 if err != nil { 475 c.Fatalf("Unable to set policy: %v", err) 476 } 477 478 admClnt := s.getAdminClient(c, accessKey, secretKey, "") 479 480 // 3.3 check user does not have explicit permissions to create service account. 481 c.mustNotCreateSvcAccount(ctx, accessKey, admClnt) 482 483 // 4. Verify the policy appears in listing 484 ps, err := s.adm.ListCannedPolicies(ctx) 485 if err != nil { 486 c.Fatalf("policy list err: %v", err) 487 } 488 _, ok := ps[policy1] 489 if !ok { 490 c.Fatalf("policy was missing!") 491 } 492 493 // 3.2 associate policy to user 494 err = s.adm.SetPolicy(ctx, policy2, accessKey, false) 495 if err != nil { 496 c.Fatalf("Unable to set policy: %v", err) 497 } 498 499 // 3.3 check user can create service account implicitly. 500 c.mustCreateSvcAccount(ctx, accessKey, admClnt) 501 502 _, ok = ps[policy2] 503 if !ok { 504 c.Fatalf("policy was missing!") 505 } 506 507 err = s.adm.RemoveUser(ctx, accessKey) 508 if err != nil { 509 c.Fatalf("user could not be deleted: %v", err) 510 } 511 512 err = s.adm.RemoveCannedPolicy(ctx, policy1) 513 if err != nil { 514 c.Fatalf("policy del err: %v", err) 515 } 516 517 err = s.adm.RemoveCannedPolicy(ctx, policy2) 518 if err != nil { 519 c.Fatalf("policy del err: %v", err) 520 } 521 } 522 523 func (s *TestSuiteIAM) TestPolicyCreate(c *check) { 524 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 525 defer cancel() 526 527 bucket := getRandomBucketName() 528 err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 529 if err != nil { 530 c.Fatalf("bucket creat error: %v", err) 531 } 532 533 // 1. Create a policy 534 policy := "mypolicy" 535 policyBytes := []byte(fmt.Sprintf(`{ 536 "Version": "2012-10-17", 537 "Statement": [ 538 { 539 "Effect": "Allow", 540 "Action": [ 541 "s3:PutObject", 542 "s3:GetObject", 543 "s3:ListBucket" 544 ], 545 "Resource": [ 546 "arn:aws:s3:::%s/*" 547 ] 548 } 549 ] 550 }`, bucket)) 551 err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) 552 if err != nil { 553 c.Fatalf("policy add error: %v", err) 554 } 555 556 // 2. Verify that policy json is validated by server 557 invalidPolicyBytes := policyBytes[:len(policyBytes)-1] 558 err = s.adm.AddCannedPolicy(ctx, policy+"invalid", invalidPolicyBytes) 559 if err == nil { 560 c.Fatalf("invalid policy creation success") 561 } 562 563 // 3. Create a user, associate policy and verify access 564 accessKey, secretKey := mustGenerateCredentials(c) 565 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 566 if err != nil { 567 c.Fatalf("Unable to set user: %v", err) 568 } 569 // 3.1 check that user does not have any access to the bucket 570 uClient := s.getUserClient(c, accessKey, secretKey, "") 571 c.mustNotListObjects(ctx, uClient, bucket) 572 573 // 3.2 associate policy to user 574 err = s.adm.SetPolicy(ctx, policy, accessKey, false) 575 if err != nil { 576 c.Fatalf("Unable to set policy: %v", err) 577 } 578 // 3.3 check user has access to bucket 579 c.mustListObjects(ctx, uClient, bucket) 580 // 3.4 Check that user cannot exceed their permissions 581 err = uClient.RemoveBucket(ctx, bucket) 582 if err == nil { 583 c.Fatalf("bucket was deleted!") 584 } 585 586 // 4. Verify the policy appears in listing 587 ps, err := s.adm.ListCannedPolicies(ctx) 588 if err != nil { 589 c.Fatalf("policy list err: %v", err) 590 } 591 _, ok := ps[policy] 592 if !ok { 593 c.Fatalf("policy was missing!") 594 } 595 596 // 5. Check that policy cannot be deleted when attached to a user. 597 err = s.adm.RemoveCannedPolicy(ctx, policy) 598 if err == nil { 599 c.Fatalf("policy could be unexpectedly deleted!") 600 } 601 602 // 6. Delete the user and then delete the policy. 603 err = s.adm.RemoveUser(ctx, accessKey) 604 if err != nil { 605 c.Fatalf("user could not be deleted: %v", err) 606 } 607 err = s.adm.RemoveCannedPolicy(ctx, policy) 608 if err != nil { 609 c.Fatalf("policy del err: %v", err) 610 } 611 } 612 613 func (s *TestSuiteIAM) TestCannedPolicies(c *check) { 614 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 615 defer cancel() 616 617 policies, err := s.adm.ListCannedPolicies(ctx) 618 if err != nil { 619 c.Fatalf("unable to list policies: %v", err) 620 } 621 622 defaultPolicies := []string{ 623 "readwrite", 624 "readonly", 625 "writeonly", 626 "diagnostics", 627 "consoleAdmin", 628 } 629 630 for _, v := range defaultPolicies { 631 if _, ok := policies[v]; !ok { 632 c.Fatalf("Failed to find %s in policies list", v) 633 } 634 } 635 636 bucket := getRandomBucketName() 637 err = s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 638 if err != nil { 639 c.Fatalf("bucket creat error: %v", err) 640 } 641 642 policyBytes := []byte(fmt.Sprintf(`{ 643 "Version": "2012-10-17", 644 "Statement": [ 645 { 646 "Effect": "Allow", 647 "Action": [ 648 "s3:PutObject", 649 "s3:GetObject", 650 "s3:ListBucket" 651 ], 652 "Resource": [ 653 "arn:aws:s3:::%s/*" 654 ] 655 } 656 ] 657 }`, bucket)) 658 659 // Check that default policies can be overwritten. 660 err = s.adm.AddCannedPolicy(ctx, "readwrite", policyBytes) 661 if err != nil { 662 c.Fatalf("policy add error: %v", err) 663 } 664 665 info, err := s.adm.InfoCannedPolicy(ctx, "readwrite") 666 if err != nil { 667 c.Fatalf("policy info err: %v", err) 668 } 669 670 infoStr := string(info) 671 if !strings.Contains(infoStr, `"s3:PutObject"`) || !strings.Contains(infoStr, ":"+bucket+"/") { 672 c.Fatalf("policy contains unexpected content!") 673 } 674 } 675 676 func (s *TestSuiteIAM) TestGroupAddRemove(c *check) { 677 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 678 defer cancel() 679 680 bucket := getRandomBucketName() 681 err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 682 if err != nil { 683 c.Fatalf("bucket creat error: %v", err) 684 } 685 686 policy := "mypolicy" 687 policyBytes := []byte(fmt.Sprintf(`{ 688 "Version": "2012-10-17", 689 "Statement": [ 690 { 691 "Effect": "Allow", 692 "Action": [ 693 "s3:PutObject", 694 "s3:GetObject", 695 "s3:ListBucket" 696 ], 697 "Resource": [ 698 "arn:aws:s3:::%s/*" 699 ] 700 } 701 ] 702 }`, bucket)) 703 err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) 704 if err != nil { 705 c.Fatalf("policy add error: %v", err) 706 } 707 708 accessKey, secretKey := mustGenerateCredentials(c) 709 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 710 if err != nil { 711 c.Fatalf("Unable to set user: %v", err) 712 } 713 714 // 1. Add user to a new group 715 group := "mygroup" 716 err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ 717 Group: group, 718 Members: []string{accessKey}, 719 }) 720 if err != nil { 721 c.Fatalf("Unable to add user to group: %v", err) 722 } 723 724 // 2. Check that user has no access 725 uClient := s.getUserClient(c, accessKey, secretKey, "") 726 c.mustNotListObjects(ctx, uClient, bucket) 727 728 // 3. Associate policy to group and check user got access. 729 err = s.adm.SetPolicy(ctx, policy, group, true) 730 if err != nil { 731 c.Fatalf("Unable to set policy: %v", err) 732 } 733 // 3.1 check user has access to bucket 734 c.mustListObjects(ctx, uClient, bucket) 735 // 3.2 Check that user cannot exceed their permissions 736 err = uClient.RemoveBucket(ctx, bucket) 737 if err == nil { 738 c.Fatalf("bucket was deleted!") 739 } 740 741 // 4. List groups and members and verify 742 groups, err := s.adm.ListGroups(ctx) 743 if err != nil { 744 c.Fatalf("group list err: %v", err) 745 } 746 if !set.CreateStringSet(groups...).Contains(group) { 747 c.Fatalf("created group not present!") 748 } 749 groupInfo, err := s.adm.GetGroupDescription(ctx, group) 750 if err != nil { 751 c.Fatalf("group desc err: %v", err) 752 } 753 c.Assert(groupInfo.Name, group) 754 c.Assert(set.CreateStringSet(groupInfo.Members...), set.CreateStringSet(accessKey)) 755 c.Assert(groupInfo.Policy, policy) 756 c.Assert(groupInfo.Status, string(madmin.GroupEnabled)) 757 758 // 5. Disable/enable the group and verify that user access is revoked/restored. 759 err = s.adm.SetGroupStatus(ctx, group, madmin.GroupDisabled) 760 if err != nil { 761 c.Fatalf("group set status err: %v", err) 762 } 763 groupInfo, err = s.adm.GetGroupDescription(ctx, group) 764 if err != nil { 765 c.Fatalf("group desc err: %v", err) 766 } 767 c.Assert(groupInfo.Status, string(madmin.GroupDisabled)) 768 c.mustNotListObjects(ctx, uClient, bucket) 769 770 err = s.adm.SetGroupStatus(ctx, group, madmin.GroupEnabled) 771 if err != nil { 772 c.Fatalf("group set status err: %v", err) 773 } 774 groupInfo, err = s.adm.GetGroupDescription(ctx, group) 775 if err != nil { 776 c.Fatalf("group desc err: %v", err) 777 } 778 c.Assert(groupInfo.Status, string(madmin.GroupEnabled)) 779 c.mustListObjects(ctx, uClient, bucket) 780 781 // 6. Verify that group cannot be deleted with users. 782 err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ 783 Group: group, 784 IsRemove: true, 785 }) 786 if err == nil { 787 c.Fatalf("group was removed!") 788 } 789 groupInfo, err = s.adm.GetGroupDescription(ctx, group) 790 if err != nil { 791 c.Fatalf("group desc err: %v", err) 792 } 793 c.Assert(groupInfo.Name, group) 794 795 // 7. Remove user from group and verify access is revoked. 796 err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ 797 Group: group, 798 Members: []string{accessKey}, 799 IsRemove: true, 800 }) 801 if err != nil { 802 c.Fatalf("group update err: %v", err) 803 } 804 c.mustNotListObjects(ctx, uClient, bucket) 805 806 // 7.1 verify group still exists 807 groupInfo, err = s.adm.GetGroupDescription(ctx, group) 808 if err != nil { 809 c.Fatalf("group desc err: %v", err) 810 } 811 c.Assert(groupInfo.Name, group) 812 c.Assert(len(groupInfo.Members), 0) 813 814 // 8. Delete group and verify 815 err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ 816 Group: group, 817 IsRemove: true, 818 }) 819 if err != nil { 820 c.Fatalf("group update err: %v", err) 821 } 822 groups, err = s.adm.ListGroups(ctx) 823 if err != nil { 824 c.Fatalf("group list err: %v", err) 825 } 826 if set.CreateStringSet(groups...).Contains(group) { 827 c.Fatalf("created group still present!") 828 } 829 _, err = s.adm.GetGroupDescription(ctx, group) 830 if err == nil { 831 c.Fatalf("group appears to exist") 832 } 833 } 834 835 func (s *TestSuiteIAM) TestServiceAccountOpsByUser(c *check) { 836 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 837 defer cancel() 838 839 bucket := getRandomBucketName() 840 err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 841 if err != nil { 842 c.Fatalf("bucket creat error: %v", err) 843 } 844 845 // Create policy, user and associate policy 846 policy := "mypolicy" 847 policyBytes := []byte(fmt.Sprintf(`{ 848 "Version": "2012-10-17", 849 "Statement": [ 850 { 851 "Effect": "Allow", 852 "Action": [ 853 "s3:PutObject", 854 "s3:GetObject", 855 "s3:ListBucket" 856 ], 857 "Resource": [ 858 "arn:aws:s3:::%s/*" 859 ] 860 } 861 ] 862 }`, bucket)) 863 err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) 864 if err != nil { 865 c.Fatalf("policy add error: %v", err) 866 } 867 868 accessKey, secretKey := mustGenerateCredentials(c) 869 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 870 if err != nil { 871 c.Fatalf("Unable to set user: %v", err) 872 } 873 874 err = s.adm.SetPolicy(ctx, policy, accessKey, false) 875 if err != nil { 876 c.Fatalf("Unable to set policy: %v", err) 877 } 878 879 // Create an madmin client with user creds 880 userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ 881 Creds: credentials.NewStaticV4(accessKey, secretKey, ""), 882 Secure: s.secure, 883 }) 884 if err != nil { 885 c.Fatalf("Err creating user admin client: %v", err) 886 } 887 userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport) 888 889 // Create svc acc 890 cr := c.mustCreateSvcAccount(ctx, accessKey, userAdmClient) 891 892 // 1. Check that svc account appears in listing 893 c.assertSvcAccAppearsInListing(ctx, userAdmClient, accessKey, cr.AccessKey) 894 895 // 2. Check that svc account info can be queried 896 c.assertSvcAccInfoQueryable(ctx, userAdmClient, accessKey, cr.AccessKey, false) 897 898 // 3. Check S3 access 899 c.assertSvcAccS3Access(ctx, s, cr, bucket) 900 901 // 5. Check that service account can be deleted. 902 c.assertSvcAccDeletion(ctx, s, userAdmClient, accessKey, bucket) 903 904 // 6. Check that service account cannot be created for some other user. 905 c.mustNotCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient) 906 } 907 908 func (s *TestSuiteIAM) TestServiceAccountDurationSecondsCondition(c *check) { 909 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 910 defer cancel() 911 912 bucket := getRandomBucketName() 913 err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 914 if err != nil { 915 c.Fatalf("bucket creat error: %v", err) 916 } 917 918 // Create policy, user and associate policy 919 policy := "mypolicy" 920 policyBytes := []byte(fmt.Sprintf(`{ 921 "Version": "2012-10-17", 922 "Statement": [ 923 { 924 "Effect": "Deny", 925 "Action": [ 926 "admin:CreateServiceAccount", 927 "admin:UpdateServiceAccount" 928 ], 929 "Condition": {"NumericGreaterThan": {"svc:DurationSeconds": "3600"}} 930 }, 931 { 932 "Effect": "Allow", 933 "Action": [ 934 "s3:PutObject", 935 "s3:GetObject", 936 "s3:ListBucket" 937 ], 938 "Resource": [ 939 "arn:aws:s3:::%s/*" 940 ] 941 } 942 ] 943 }`, bucket)) 944 err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) 945 if err != nil { 946 c.Fatalf("policy add error: %v", err) 947 } 948 949 accessKey, secretKey := mustGenerateCredentials(c) 950 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 951 if err != nil { 952 c.Fatalf("Unable to set user: %v", err) 953 } 954 955 err = s.adm.SetPolicy(ctx, policy, accessKey, false) 956 if err != nil { 957 c.Fatalf("Unable to set policy: %v", err) 958 } 959 960 // Create an madmin client with user creds 961 userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ 962 Creds: credentials.NewStaticV4(accessKey, secretKey, ""), 963 Secure: s.secure, 964 }) 965 if err != nil { 966 c.Fatalf("Err creating user admin client: %v", err) 967 } 968 userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport) 969 970 distantExpiration := time.Now().Add(30 * time.Minute) 971 cr, err := userAdmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 972 TargetUser: accessKey, 973 AccessKey: "svc-accesskey", 974 SecretKey: "svc-secretkey", 975 Expiration: &distantExpiration, 976 }) 977 if err != nil { 978 c.Fatalf("Unable to create svc acc: %v", err) 979 } 980 981 c.assertSvcAccS3Access(ctx, s, cr, bucket) 982 983 closeExpiration := time.Now().Add(2 * time.Hour) 984 _, err = userAdmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 985 TargetUser: accessKey, 986 AccessKey: "svc-accesskey", 987 SecretKey: "svc-secretkey", 988 Expiration: &closeExpiration, 989 }) 990 if err == nil { 991 c.Fatalf("Creating a svc acc with distant expiration should fail") 992 } 993 } 994 995 func (s *TestSuiteIAM) TestServiceAccountOpsByAdmin(c *check) { 996 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 997 defer cancel() 998 999 bucket := getRandomBucketName() 1000 err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 1001 if err != nil { 1002 c.Fatalf("bucket creat error: %v", err) 1003 } 1004 1005 // Create policy, user and associate policy 1006 policy := "mypolicy" 1007 policyBytes := []byte(fmt.Sprintf(`{ 1008 "Version": "2012-10-17", 1009 "Statement": [ 1010 { 1011 "Effect": "Allow", 1012 "Action": [ 1013 "s3:PutObject", 1014 "s3:GetObject", 1015 "s3:ListBucket" 1016 ], 1017 "Resource": [ 1018 "arn:aws:s3:::%s/*" 1019 ] 1020 } 1021 ] 1022 }`, bucket)) 1023 err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) 1024 if err != nil { 1025 c.Fatalf("policy add error: %v", err) 1026 } 1027 1028 accessKey, secretKey := mustGenerateCredentials(c) 1029 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 1030 if err != nil { 1031 c.Fatalf("Unable to set user: %v", err) 1032 } 1033 1034 err = s.adm.SetPolicy(ctx, policy, accessKey, false) 1035 if err != nil { 1036 c.Fatalf("Unable to set policy: %v", err) 1037 } 1038 1039 // 1. Create a service account for the user 1040 cr := c.mustCreateSvcAccount(ctx, accessKey, s.adm) 1041 1042 // 1.2 Check that svc account appears in listing 1043 c.assertSvcAccAppearsInListing(ctx, s.adm, accessKey, cr.AccessKey) 1044 1045 // 1.3 Check that svc account info can be queried 1046 c.assertSvcAccInfoQueryable(ctx, s.adm, accessKey, cr.AccessKey, false) 1047 1048 // 2. Check that svc account can access the bucket 1049 c.assertSvcAccS3Access(ctx, s, cr, bucket) 1050 1051 // 3. Check that svc account can restrict the policy, and that the 1052 // session policy can be updated. 1053 c.assertSvcAccSessionPolicyUpdate(ctx, s, s.adm, accessKey, bucket) 1054 1055 // 4. Check that service account's secret key and account status can be 1056 // updated. 1057 c.assertSvcAccSecretKeyAndStatusUpdate(ctx, s, s.adm, accessKey, bucket) 1058 1059 // 5. Check that service account can be deleted. 1060 c.assertSvcAccDeletion(ctx, s, s.adm, accessKey, bucket) 1061 } 1062 1063 func (s *TestSuiteIAM) TestServiceAccountPrivilegeEscalationBug(c *check) { 1064 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 1065 defer cancel() 1066 1067 err := s.client.MakeBucket(ctx, "public", minio.MakeBucketOptions{}) 1068 if err != nil { 1069 c.Fatalf("bucket creat error: %v", err) 1070 } 1071 1072 err = s.client.MakeBucket(ctx, "private", minio.MakeBucketOptions{}) 1073 if err != nil { 1074 c.Fatalf("bucket creat error: %v", err) 1075 } 1076 1077 pubPolicyBytes := []byte(`{ 1078 "Version": "2012-10-17", 1079 "Statement": [ 1080 { 1081 "Effect": "Allow", 1082 "Action": [ 1083 "s3:*" 1084 ], 1085 "Resource": [ 1086 "arn:aws:s3:::public", 1087 "arn:aws:s3:::public/*" 1088 ] 1089 } 1090 ] 1091 }`) 1092 1093 fullS3PolicyBytes := []byte(`{ 1094 "Version": "2012-10-17", 1095 "Statement": [ 1096 { 1097 "Effect": "Allow", 1098 "Action": [ 1099 "s3:*" 1100 ], 1101 "Resource": [ 1102 "arn:aws:s3:::*" 1103 ] 1104 } 1105 ] 1106 } 1107 `) 1108 1109 // Create a service account for the root user. 1110 cr, err := s.adm.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 1111 TargetUser: globalActiveCred.AccessKey, 1112 Policy: pubPolicyBytes, 1113 }) 1114 if err != nil { 1115 c.Fatalf("admin should be able to create service account for themselves %s", err) 1116 } 1117 1118 svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") 1119 1120 // Check that the service account can access the public bucket. 1121 buckets, err := svcClient.ListBuckets(ctx) 1122 if err != nil { 1123 c.Fatalf("err fetching buckets %s", err) 1124 } 1125 if len(buckets) != 1 || buckets[0].Name != "public" { 1126 c.Fatalf("service account should only have access to public bucket") 1127 } 1128 1129 // Create an madmin client with the service account creds. 1130 svcAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ 1131 Creds: credentials.NewStaticV4(cr.AccessKey, cr.SecretKey, ""), 1132 Secure: s.secure, 1133 }) 1134 if err != nil { 1135 c.Fatalf("Err creating svcacct admin client: %v", err) 1136 } 1137 svcAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport) 1138 1139 // Attempt to update the policy on the service account. 1140 err = svcAdmClient.UpdateServiceAccount(ctx, cr.AccessKey, 1141 madmin.UpdateServiceAccountReq{ 1142 NewPolicy: fullS3PolicyBytes, 1143 }) 1144 1145 if err == nil { 1146 c.Fatalf("service account should not be able to update policy on itself") 1147 } else if !strings.Contains(err.Error(), "Access Denied") { 1148 c.Fatalf("unexpected error: %v", err) 1149 } 1150 } 1151 1152 func (s *TestSuiteIAM) SetUpAccMgmtPlugin(c *check) { 1153 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 1154 defer cancel() 1155 1156 pluginEndpoint := env.Get("_MINIO_POLICY_PLUGIN_ENDPOINT", "") 1157 if pluginEndpoint == "" { 1158 c.Skip("_MINIO_POLICY_PLUGIN_ENDPOINT not given - skipping.") 1159 } 1160 1161 configCmds := []string{ 1162 "policy_plugin", 1163 "url=" + pluginEndpoint, 1164 } 1165 1166 _, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " ")) 1167 if err != nil { 1168 c.Fatalf("unable to setup access management plugin for tests: %v", err) 1169 } 1170 1171 s.RestartIAMSuite(c) 1172 } 1173 1174 // TestIAM_AMPInternalIDPServerSuite - tests for access management plugin 1175 func TestIAM_AMPInternalIDPServerSuite(t *testing.T) { 1176 for i, testCase := range iamTestSuites { 1177 t.Run( 1178 fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription), 1179 func(t *testing.T) { 1180 suite := testCase 1181 c := &check{t, testCase.serverType} 1182 1183 suite.SetUpSuite(c) 1184 defer suite.TearDownSuite(c) 1185 1186 suite.SetUpAccMgmtPlugin(c) 1187 1188 suite.TestAccMgmtPlugin(c) 1189 }, 1190 ) 1191 } 1192 } 1193 1194 // TestAccMgmtPlugin - this test assumes that the access-management-plugin is 1195 // the same as the example in `docs/iam/access-manager-plugin.go` - 1196 // specifically, it denies only `s3:Put*` operations on non-root accounts. 1197 func (s *TestSuiteIAM) TestAccMgmtPlugin(c *check) { 1198 ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) 1199 defer cancel() 1200 1201 // 0. Check that owner is able to make-bucket. 1202 bucket := getRandomBucketName() 1203 err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) 1204 if err != nil { 1205 c.Fatalf("bucket creat error: %v", err) 1206 } 1207 1208 // 1. Create a user. 1209 accessKey, secretKey := mustGenerateCredentials(c) 1210 err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) 1211 if err != nil { 1212 c.Fatalf("Unable to set user: %v", err) 1213 } 1214 1215 // 2. Check new user appears in listing 1216 usersMap, err := s.adm.ListUsers(ctx) 1217 if err != nil { 1218 c.Fatalf("error listing: %v", err) 1219 } 1220 v, ok := usersMap[accessKey] 1221 if !ok { 1222 c.Fatalf("user not listed: %s", accessKey) 1223 } 1224 c.Assert(v.Status, madmin.AccountEnabled) 1225 1226 // 3. Check that user is able to make a bucket. 1227 client := s.getUserClient(c, accessKey, secretKey, "") 1228 err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) 1229 if err != nil { 1230 c.Fatalf("user not create bucket: %v", err) 1231 } 1232 1233 // 3.1 check user has access to bucket 1234 c.mustListObjects(ctx, client, bucket) 1235 1236 // 3.2 check that user cannot upload an object. 1237 _, err = client.PutObject(ctx, bucket, "objectName", bytes.NewBuffer([]byte("some content")), 12, minio.PutObjectOptions{}) 1238 if err == nil { 1239 c.Fatalf("user was able to upload unexpectedly") 1240 } 1241 1242 // Create an madmin client with user creds 1243 userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ 1244 Creds: credentials.NewStaticV4(accessKey, secretKey, ""), 1245 Secure: s.secure, 1246 }) 1247 if err != nil { 1248 c.Fatalf("Err creating user admin client: %v", err) 1249 } 1250 userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport) 1251 1252 // Create svc acc 1253 cr := c.mustCreateSvcAccount(ctx, accessKey, userAdmClient) 1254 1255 // 1. Check that svc account appears in listing 1256 c.assertSvcAccAppearsInListing(ctx, userAdmClient, accessKey, cr.AccessKey) 1257 1258 // 2. Check that svc account info can be queried 1259 c.assertSvcAccInfoQueryable(ctx, userAdmClient, accessKey, cr.AccessKey, false) 1260 1261 // 3. Check S3 access 1262 c.assertSvcAccS3Access(ctx, s, cr, bucket) 1263 1264 // Check that session policies do not apply - as policy enforcement is 1265 // delegated to plugin. 1266 { 1267 svcAK, svcSK := mustGenerateCredentials(c) 1268 1269 // This policy does not allow listing objects. 1270 policyBytes := []byte(fmt.Sprintf(`{ 1271 "Version": "2012-10-17", 1272 "Statement": [ 1273 { 1274 "Effect": "Allow", 1275 "Action": [ 1276 "s3:PutObject", 1277 "s3:GetObject" 1278 ], 1279 "Resource": [ 1280 "arn:aws:s3:::%s/*" 1281 ] 1282 } 1283 ] 1284 }`, bucket)) 1285 cr, err := userAdmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 1286 Policy: policyBytes, 1287 TargetUser: accessKey, 1288 AccessKey: svcAK, 1289 SecretKey: svcSK, 1290 }) 1291 if err != nil { 1292 c.Fatalf("Unable to create svc acc: %v", err) 1293 } 1294 svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") 1295 // Though the attached policy does not allow listing, it will be 1296 // ignored because the plugin allows it. 1297 c.mustListObjects(ctx, svcClient, bucket) 1298 } 1299 1300 // 4. Check that service account's secret key and account status can be 1301 // updated. 1302 c.assertSvcAccSecretKeyAndStatusUpdate(ctx, s, userAdmClient, accessKey, bucket) 1303 1304 // 5. Check that service account can be deleted. 1305 c.assertSvcAccDeletion(ctx, s, userAdmClient, accessKey, bucket) 1306 1307 // 6. Check that service account **can** be created for some other user. 1308 // This is possible because the policy enforced in the plugin. 1309 c.mustCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient) 1310 } 1311 1312 func (c *check) mustCreateIAMUser(ctx context.Context, admClnt *madmin.AdminClient) madmin.Credentials { 1313 c.Helper() 1314 randUser := mustGetUUID() 1315 randPass := mustGetUUID() 1316 err := admClnt.AddUser(ctx, randUser, randPass) 1317 if err != nil { 1318 c.Fatalf("should be able to create a user: %v", err) 1319 } 1320 return madmin.Credentials{ 1321 AccessKey: randUser, 1322 SecretKey: randPass, 1323 } 1324 } 1325 1326 func (c *check) mustGetIAMUserInfo(ctx context.Context, admClnt *madmin.AdminClient, accessKey string) madmin.UserInfo { 1327 c.Helper() 1328 ui, err := admClnt.GetUserInfo(ctx, accessKey) 1329 if err != nil { 1330 c.Fatalf("should be able to get user info: %v", err) 1331 } 1332 return ui 1333 } 1334 1335 func (c *check) mustNotCreateIAMUser(ctx context.Context, admClnt *madmin.AdminClient) { 1336 c.Helper() 1337 randUser := mustGetUUID() 1338 randPass := mustGetUUID() 1339 err := admClnt.AddUser(ctx, randUser, randPass) 1340 if err == nil { 1341 c.Fatalf("should not be able to create a user") 1342 } 1343 } 1344 1345 func (c *check) mustCreateSvcAccount(ctx context.Context, tgtUser string, admClnt *madmin.AdminClient) madmin.Credentials { 1346 c.Helper() 1347 cr, err := admClnt.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 1348 TargetUser: tgtUser, 1349 }) 1350 if err != nil { 1351 c.Fatalf("user should be able to create service accounts %s", err) 1352 } 1353 return cr 1354 } 1355 1356 func (c *check) mustNotCreateSvcAccount(ctx context.Context, tgtUser string, admClnt *madmin.AdminClient) { 1357 c.Helper() 1358 _, err := admClnt.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 1359 TargetUser: tgtUser, 1360 }) 1361 if err == nil { 1362 c.Fatalf("user was able to add service accounts unexpectedly!") 1363 } 1364 } 1365 1366 func (c *check) mustNotListObjects(ctx context.Context, client *minio.Client, bucket string) { 1367 c.Helper() 1368 res := client.ListObjects(ctx, bucket, minio.ListObjectsOptions{}) 1369 v, ok := <-res 1370 if !ok || v.Err == nil { 1371 c.Fatalf("user was able to list unexpectedly! on %s", bucket) 1372 } 1373 } 1374 1375 func (c *check) mustPutObjectWithTags(ctx context.Context, client *minio.Client, bucket, object string) { 1376 c.Helper() 1377 _, err := client.PutObject(ctx, bucket, object, bytes.NewBuffer([]byte("stuff")), 5, minio.PutObjectOptions{ 1378 UserTags: map[string]string{ 1379 "security": "public", 1380 "virus": "true", 1381 }, 1382 }) 1383 if err != nil { 1384 c.Fatalf("user was unable to upload the object: %v", err) 1385 } 1386 } 1387 1388 func (c *check) mustGetObject(ctx context.Context, client *minio.Client, bucket, object string) { 1389 c.Helper() 1390 1391 r, err := client.GetObject(ctx, bucket, object, minio.GetObjectOptions{}) 1392 if err != nil { 1393 c.Fatalf("user was unable to download the object: %v", err) 1394 } 1395 defer r.Close() 1396 1397 _, err = io.Copy(io.Discard, r) 1398 if err != nil { 1399 c.Fatalf("user was unable to download the object: %v", err) 1400 } 1401 } 1402 1403 func (c *check) mustHeadObject(ctx context.Context, client *minio.Client, bucket, object string, tagCount int) { 1404 c.Helper() 1405 1406 oinfo, err := client.StatObject(ctx, bucket, object, minio.StatObjectOptions{}) 1407 if err != nil { 1408 c.Fatalf("user was unable to download the object: %v", err) 1409 } 1410 1411 if oinfo.UserTagCount != tagCount { 1412 c.Fatalf("expected tagCount: %d, got %d", tagCount, oinfo.UserTagCount) 1413 } 1414 } 1415 1416 func (c *check) mustListObjects(ctx context.Context, client *minio.Client, bucket string) { 1417 c.Helper() 1418 res := client.ListObjects(ctx, bucket, minio.ListObjectsOptions{}) 1419 v, ok := <-res 1420 if ok && v.Err != nil { 1421 c.Fatalf("user was unable to list: %v", v.Err) 1422 } 1423 } 1424 1425 func (c *check) mustListBuckets(ctx context.Context, client *minio.Client) { 1426 c.Helper() 1427 _, err := client.ListBuckets(ctx) 1428 if err != nil { 1429 c.Fatalf("user was unable to list buckets: %v", err) 1430 } 1431 } 1432 1433 func (c *check) mustNotDelete(ctx context.Context, client *minio.Client, bucket string, vid string) { 1434 c.Helper() 1435 1436 err := client.RemoveObject(ctx, bucket, "some-object", minio.RemoveObjectOptions{VersionID: vid}) 1437 if err == nil { 1438 c.Fatalf("user must not be allowed to delete") 1439 } 1440 1441 err = client.RemoveObject(ctx, bucket, "some-object", minio.RemoveObjectOptions{}) 1442 if err != nil { 1443 c.Fatal("user must be able to create delete marker") 1444 } 1445 } 1446 1447 func (c *check) mustDownload(ctx context.Context, client *minio.Client, bucket string) { 1448 c.Helper() 1449 rd, err := client.GetObject(ctx, bucket, "some-object", minio.GetObjectOptions{}) 1450 if err != nil { 1451 c.Fatalf("download did not succeed got %#v", err) 1452 } 1453 if _, err = io.Copy(io.Discard, rd); err != nil { 1454 c.Fatalf("download did not succeed got %#v", err) 1455 } 1456 } 1457 1458 func (c *check) mustUploadReturnVersions(ctx context.Context, client *minio.Client, bucket string) []string { 1459 c.Helper() 1460 versions := []string{} 1461 for i := 0; i < 5; i++ { 1462 ui, err := client.PutObject(ctx, bucket, "some-object", bytes.NewBuffer([]byte("stuff")), 5, minio.PutObjectOptions{}) 1463 if err != nil { 1464 c.Fatalf("upload did not succeed got %#v", err) 1465 } 1466 versions = append(versions, ui.VersionID) 1467 } 1468 return versions 1469 } 1470 1471 func (c *check) mustUpload(ctx context.Context, client *minio.Client, bucket string) { 1472 c.Helper() 1473 _, err := client.PutObject(ctx, bucket, "some-object", bytes.NewBuffer([]byte("stuff")), 5, minio.PutObjectOptions{}) 1474 if err != nil { 1475 c.Fatalf("upload did not succeed got %#v", err) 1476 } 1477 } 1478 1479 func (c *check) mustNotUpload(ctx context.Context, client *minio.Client, bucket string) { 1480 c.Helper() 1481 _, err := client.PutObject(ctx, bucket, "some-object", bytes.NewBuffer([]byte("stuff")), 5, minio.PutObjectOptions{}) 1482 if e, ok := err.(minio.ErrorResponse); ok { 1483 if e.Code == "AccessDenied" { 1484 return 1485 } 1486 } 1487 c.Fatalf("upload did not get an AccessDenied error - got %#v instead", err) 1488 } 1489 1490 func (c *check) assertSvcAccS3Access(ctx context.Context, s *TestSuiteIAM, cr madmin.Credentials, bucket string) { 1491 svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") 1492 c.mustListObjects(ctx, svcClient, bucket) 1493 } 1494 1495 func (c *check) assertSvcAccAppearsInListing(ctx context.Context, madmClient *madmin.AdminClient, parentAK, svcAK string) { 1496 c.Helper() 1497 listResp, err := madmClient.ListServiceAccounts(ctx, parentAK) 1498 if err != nil { 1499 c.Fatalf("unable to list svc accounts: %v", err) 1500 } 1501 var accessKeys []string 1502 for _, item := range listResp.Accounts { 1503 accessKeys = append(accessKeys, item.AccessKey) 1504 } 1505 if !set.CreateStringSet(accessKeys...).Contains(svcAK) { 1506 c.Fatalf("service account did not appear in listing!") 1507 } 1508 } 1509 1510 func (c *check) assertSvcAccInfoQueryable(ctx context.Context, madmClient *madmin.AdminClient, parentAK, svcAK string, skipParentUserCheck bool) { 1511 infoResp, err := madmClient.InfoServiceAccount(ctx, svcAK) 1512 if err != nil { 1513 c.Fatalf("unable to get svc acc info: %v", err) 1514 } 1515 if !skipParentUserCheck { 1516 c.Assert(infoResp.ParentUser, parentAK) 1517 } 1518 c.Assert(infoResp.AccountStatus, "on") 1519 c.Assert(infoResp.ImpliedPolicy, true) 1520 } 1521 1522 // This test assumes that the policy for `accessKey` allows listing on the given 1523 // bucket. It creates a session policy that restricts listing on the bucket and 1524 // then enables it again in a session policy update call. 1525 func (c *check) assertSvcAccSessionPolicyUpdate(ctx context.Context, s *TestSuiteIAM, madmClient *madmin.AdminClient, accessKey, bucket string) { 1526 c.Helper() 1527 svcAK, svcSK := mustGenerateCredentials(c) 1528 1529 // This policy does not allow listing objects. 1530 policyBytes := []byte(fmt.Sprintf(`{ 1531 "Version": "2012-10-17", 1532 "Statement": [ 1533 { 1534 "Effect": "Allow", 1535 "Action": [ 1536 "s3:PutObject", 1537 "s3:GetObject" 1538 ], 1539 "Resource": [ 1540 "arn:aws:s3:::%s/*" 1541 ] 1542 } 1543 ] 1544 }`, bucket)) 1545 cr, err := madmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 1546 Policy: policyBytes, 1547 TargetUser: accessKey, 1548 AccessKey: svcAK, 1549 SecretKey: svcSK, 1550 }) 1551 if err != nil { 1552 c.Fatalf("Unable to create svc acc: %v", err) 1553 } 1554 svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") 1555 c.mustNotListObjects(ctx, svcClient, bucket) 1556 1557 // This policy allows listing objects. 1558 newPolicyBytes := []byte(fmt.Sprintf(`{ 1559 "Version": "2012-10-17", 1560 "Statement": [ 1561 { 1562 "Effect": "Allow", 1563 "Action": [ 1564 "s3:ListBucket" 1565 ], 1566 "Resource": [ 1567 "arn:aws:s3:::%s/*" 1568 ] 1569 } 1570 ] 1571 }`, bucket)) 1572 err = madmClient.UpdateServiceAccount(ctx, svcAK, madmin.UpdateServiceAccountReq{ 1573 NewPolicy: newPolicyBytes, 1574 }) 1575 if err != nil { 1576 c.Fatalf("unable to update session policy for svc acc: %v", err) 1577 } 1578 c.mustListObjects(ctx, svcClient, bucket) 1579 } 1580 1581 func (c *check) assertSvcAccSecretKeyAndStatusUpdate(ctx context.Context, s *TestSuiteIAM, madmClient *madmin.AdminClient, accessKey, bucket string) { 1582 c.Helper() 1583 svcAK, svcSK := mustGenerateCredentials(c) 1584 cr, err := madmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 1585 TargetUser: accessKey, 1586 AccessKey: svcAK, 1587 SecretKey: svcSK, 1588 }) 1589 if err != nil { 1590 c.Fatalf("Unable to create svc acc: %v", err) 1591 } 1592 svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") 1593 c.mustListObjects(ctx, svcClient, bucket) 1594 1595 _, svcSK2 := mustGenerateCredentials(c) 1596 err = madmClient.UpdateServiceAccount(ctx, svcAK, madmin.UpdateServiceAccountReq{ 1597 NewSecretKey: svcSK2, 1598 }) 1599 if err != nil { 1600 c.Fatalf("unable to update secret key for svc acc: %v", err) 1601 } 1602 // old creds should not work: 1603 c.mustNotListObjects(ctx, svcClient, bucket) 1604 // new creds work: 1605 svcClient2 := s.getUserClient(c, cr.AccessKey, svcSK2, "") 1606 c.mustListObjects(ctx, svcClient2, bucket) 1607 1608 // update status to disabled 1609 err = madmClient.UpdateServiceAccount(ctx, svcAK, madmin.UpdateServiceAccountReq{ 1610 NewStatus: "off", 1611 }) 1612 if err != nil { 1613 c.Fatalf("unable to update secret key for svc acc: %v", err) 1614 } 1615 c.mustNotListObjects(ctx, svcClient2, bucket) 1616 } 1617 1618 func (c *check) assertSvcAccDeletion(ctx context.Context, s *TestSuiteIAM, madmClient *madmin.AdminClient, accessKey, bucket string) { 1619 c.Helper() 1620 svcAK, svcSK := mustGenerateCredentials(c) 1621 cr, err := madmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ 1622 TargetUser: accessKey, 1623 AccessKey: svcAK, 1624 SecretKey: svcSK, 1625 }) 1626 if err != nil { 1627 c.Fatalf("Unable to create svc acc: %v", err) 1628 } 1629 svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") 1630 c.mustListObjects(ctx, svcClient, bucket) 1631 1632 err = madmClient.DeleteServiceAccount(ctx, svcAK) 1633 if err != nil { 1634 c.Fatalf("unable to delete svc acc: %v", err) 1635 } 1636 c.mustNotListObjects(ctx, svcClient, bucket) 1637 } 1638 1639 func mustGenerateCredentials(c *check) (string, string) { 1640 c.Helper() 1641 ak, sk, err := auth.GenerateCredentials() 1642 if err != nil { 1643 c.Fatalf("unable to generate credentials: %v", err) 1644 } 1645 return ak, sk 1646 }