| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 	"crypto/sha256" | 
					
						
							|  |  |  | 	"encoding/hex" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2022-05-19 08:58:19 +08:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/madmin-go" | 
					
						
							|  |  |  | 	minio "github.com/minio/minio-go/v7" | 
					
						
							|  |  |  | 	"github.com/minio/minio-go/v7/pkg/credentials" | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 	cr "github.com/minio/minio-go/v7/pkg/credentials" | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 	"github.com/minio/minio-go/v7/pkg/s3utils" | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	"github.com/minio/minio-go/v7/pkg/set" | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 	"github.com/minio/minio-go/v7/pkg/signer" | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	"github.com/minio/minio/internal/auth" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2021-11-02 06:03:07 +08:00
										 |  |  | 	testDefaultTimeout = 30 * time.Second | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // API suite container for IAM
 | 
					
						
							|  |  |  | type TestSuiteIAM struct { | 
					
						
							|  |  |  | 	TestSuiteCommon | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-29 09:27:09 +08:00
										 |  |  | 	ServerTypeDescription string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | 	// Flag to turn on tests for etcd backend IAM
 | 
					
						
							|  |  |  | 	withEtcdBackend bool | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	endpoint string | 
					
						
							|  |  |  | 	adm      *madmin.AdminClient | 
					
						
							|  |  |  | 	client   *minio.Client | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | func newTestSuiteIAM(c TestSuiteCommon, withEtcdBackend bool) *TestSuiteIAM { | 
					
						
							| 
									
										
										
										
											2022-04-29 09:27:09 +08:00
										 |  |  | 	etcdStr := "" | 
					
						
							|  |  |  | 	if withEtcdBackend { | 
					
						
							|  |  |  | 		etcdStr = " (with etcd backend)" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &TestSuiteIAM{ | 
					
						
							|  |  |  | 		TestSuiteCommon:       c, | 
					
						
							|  |  |  | 		ServerTypeDescription: fmt.Sprintf("%s%s", c.serverType, etcdStr), | 
					
						
							|  |  |  | 		withEtcdBackend:       withEtcdBackend, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 23:16:30 +08:00
										 |  |  | func (s *TestSuiteIAM) iamSetup(c *check) { | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	var err error | 
					
						
							|  |  |  | 	// strip url scheme from endpoint
 | 
					
						
							|  |  |  | 	s.endpoint = strings.TrimPrefix(s.endPoint, "http://") | 
					
						
							|  |  |  | 	if s.secure { | 
					
						
							|  |  |  | 		s.endpoint = strings.TrimPrefix(s.endPoint, "https://") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.adm, err = madmin.New(s.endpoint, s.accessKey, s.secretKey, s.secure) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error creating admin client: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Set transport, so that TLS is handled correctly.
 | 
					
						
							|  |  |  | 	s.adm.SetCustomTransport(s.TestSuiteCommon.client.Transport) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.client, err = minio.New(s.endpoint, &minio.Options{ | 
					
						
							|  |  |  | 		Creds:     credentials.NewStaticV4(s.accessKey, s.secretKey, ""), | 
					
						
							|  |  |  | 		Secure:    s.secure, | 
					
						
							|  |  |  | 		Transport: s.TestSuiteCommon.client.Transport, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error creating minio client: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-13 06:24:19 +08:00
										 |  |  | // List of all IAM test suites (i.e. test server configuration combinations)
 | 
					
						
							|  |  |  | // common to tests.
 | 
					
						
							|  |  |  | var iamTestSuites = func() []*TestSuiteIAM { | 
					
						
							|  |  |  | 	baseTestCases := []TestSuiteCommon{ | 
					
						
							| 
									
										
										
										
											2022-05-31 01:58:37 +08:00
										 |  |  | 		// Init and run test on ErasureSD backend with signature v4.
 | 
					
						
							|  |  |  | 		{serverType: "ErasureSD", signer: signerV4}, | 
					
						
							|  |  |  | 		// Init and run test on ErasureSD backend, with tls enabled.
 | 
					
						
							|  |  |  | 		{serverType: "ErasureSD", signer: signerV4, secure: true}, | 
					
						
							| 
									
										
										
										
											2022-05-13 06:24:19 +08:00
										 |  |  | 		// Init and run test on Erasure backend.
 | 
					
						
							|  |  |  | 		{serverType: "Erasure", signer: signerV4}, | 
					
						
							|  |  |  | 		// Init and run test on ErasureSet backend.
 | 
					
						
							|  |  |  | 		{serverType: "ErasureSet", signer: signerV4}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	testCases := []*TestSuiteIAM{} | 
					
						
							|  |  |  | 	for _, bt := range baseTestCases { | 
					
						
							|  |  |  | 		testCases = append(testCases, | 
					
						
							|  |  |  | 			newTestSuiteIAM(bt, false), | 
					
						
							|  |  |  | 			newTestSuiteIAM(bt, true), | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return testCases | 
					
						
							|  |  |  | }() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	EnvTestEtcdBackend = "ETCD_SERVER" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *TestSuiteIAM) setUpEtcd(c *check, etcdServer string) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	configCmds := []string{ | 
					
						
							|  |  |  | 		"etcd", | 
					
						
							|  |  |  | 		"endpoints=" + etcdServer, | 
					
						
							|  |  |  | 		"path_prefix=" + mustGetUUID(), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " ")) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to setup Etcd for tests: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.RestartIAMSuite(c) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 23:16:30 +08:00
										 |  |  | func (s *TestSuiteIAM) SetUpSuite(c *check) { | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | 	// If etcd backend is specified and etcd server is not present, the test
 | 
					
						
							|  |  |  | 	// is skipped.
 | 
					
						
							|  |  |  | 	etcdServer := os.Getenv(EnvTestEtcdBackend) | 
					
						
							|  |  |  | 	if s.withEtcdBackend && etcdServer == "" { | 
					
						
							|  |  |  | 		c.Skip("Skipping etcd backend IAM test as no etcd server is configured.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 23:16:30 +08:00
										 |  |  | 	s.TestSuiteCommon.SetUpSuite(c) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.iamSetup(c) | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if s.withEtcdBackend { | 
					
						
							|  |  |  | 		s.setUpEtcd(c, etcdServer) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-04 23:16:30 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *TestSuiteIAM) RestartIAMSuite(c *check) { | 
					
						
							|  |  |  | 	s.TestSuiteCommon.RestartTestServer(c) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.iamSetup(c) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | func (s *TestSuiteIAM) getAdminClient(c *check, accessKey, secretKey, sessionToken string) *madmin.AdminClient { | 
					
						
							|  |  |  | 	madmClnt, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ | 
					
						
							|  |  |  | 		Creds:  credentials.NewStaticV4(accessKey, secretKey, sessionToken), | 
					
						
							|  |  |  | 		Secure: s.secure, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error creating user admin client: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	madmClnt.SetCustomTransport(s.TestSuiteCommon.client.Transport) | 
					
						
							|  |  |  | 	return madmClnt | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | func (s *TestSuiteIAM) getUserClient(c *check, accessKey, secretKey, sessionToken string) *minio.Client { | 
					
						
							|  |  |  | 	client, err := minio.New(s.endpoint, &minio.Options{ | 
					
						
							|  |  |  | 		Creds:     credentials.NewStaticV4(accessKey, secretKey, sessionToken), | 
					
						
							|  |  |  | 		Secure:    s.secure, | 
					
						
							|  |  |  | 		Transport: s.TestSuiteCommon.client.Transport, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error creating user minio client: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return client | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestIAMInternalIDPServerSuite(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-05-19 08:58:19 +08:00
										 |  |  | 	if runtime.GOOS == globalWindowsOSName { | 
					
						
							|  |  |  | 		t.Skip("windows is clunky disable these tests") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-13 06:24:19 +08:00
										 |  |  | 	for i, testCase := range iamTestSuites { | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | 		t.Run( | 
					
						
							| 
									
										
										
										
											2022-05-13 06:24:19 +08:00
										 |  |  | 			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription), | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | 			func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 				suite := testCase | 
					
						
							|  |  |  | 				c := &check{t, testCase.serverType} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				suite.SetUpSuite(c) | 
					
						
							|  |  |  | 				suite.TestUserCreate(c) | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 				suite.TestUserPolicyEscalationBug(c) | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 				suite.TestPolicyCreate(c) | 
					
						
							|  |  |  | 				suite.TestCannedPolicies(c) | 
					
						
							|  |  |  | 				suite.TestGroupAddRemove(c) | 
					
						
							|  |  |  | 				suite.TestServiceAccountOpsByAdmin(c) | 
					
						
							|  |  |  | 				suite.TestServiceAccountOpsByUser(c) | 
					
						
							|  |  |  | 				suite.TestAddServiceAccountPerms(c) | 
					
						
							|  |  |  | 				suite.TearDownSuite(c) | 
					
						
							| 
									
										
										
										
											2021-11-10 01:25:13 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *TestSuiteIAM) TestUserCreate(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Create a user.
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err := s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Check new user appears in listing
 | 
					
						
							|  |  |  | 	usersMap, err := s.adm.ListUsers(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error listing: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	v, ok := usersMap[accessKey] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		c.Fatalf("user not listed: %s", accessKey) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(v.Status, madmin.AccountEnabled) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Associate policy and check that user can access
 | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, "readwrite", accessKey, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-18 10:58:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	client := s.getUserClient(c, accessKey, secretKey, "") | 
					
						
							|  |  |  | 	err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("user could not create bucket: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | 	// 3.10. Check that user's password can be updated.
 | 
					
						
							|  |  |  | 	_, newSecretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, newSecretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to update user's secret key: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 3.10.1 Check that old password no longer works.
 | 
					
						
							|  |  |  | 	err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("user was unexpectedly able to create bucket with bad password!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 3.10.2 Check that new password works.
 | 
					
						
							|  |  |  | 	client = s.getUserClient(c, accessKey, newSecretKey, "") | 
					
						
							|  |  |  | 	err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("user could not create bucket: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	// 4. Check that user can be disabled and verify it.
 | 
					
						
							|  |  |  | 	err = s.adm.SetUserStatus(ctx, accessKey, madmin.AccountDisabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("could not set user account to disabled") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	usersMap, err = s.adm.ListUsers(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error listing: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	v, ok = usersMap[accessKey] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		c.Fatalf("user was not listed after disabling: %s", accessKey) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(v.Status, madmin.AccountDisabled) | 
					
						
							|  |  |  | 	err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("user account was not disabled!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 5. Check that user can be deleted and verify it.
 | 
					
						
							|  |  |  | 	err = s.adm.RemoveUser(ctx, accessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("user could not be deleted: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	usersMap, err = s.adm.ListUsers(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error listing: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, ok = usersMap[accessKey] | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		c.Fatalf("user not deleted: %s", accessKey) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("user account was not deleted!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-24 01:21:21 +08:00
										 |  |  | func (s *TestSuiteIAM) TestUserPolicyEscalationBug(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket creat error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Create a user, associate policy and verify access
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 2.1 check that user does not have any access to the bucket
 | 
					
						
							|  |  |  | 	uClient := s.getUserClient(c, accessKey, secretKey, "") | 
					
						
							|  |  |  | 	c.mustNotListObjects(ctx, uClient, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2.2 create and associate policy to user
 | 
					
						
							|  |  |  | 	policy := "mypolicy-test-user-update" | 
					
						
							|  |  |  | 	policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject", | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, policy, accessKey, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 2.3 check user has access to bucket
 | 
					
						
							|  |  |  | 	c.mustListObjects(ctx, uClient, bucket) | 
					
						
							|  |  |  | 	// 2.3 check that user cannot delete the bucket
 | 
					
						
							|  |  |  | 	err = uClient.RemoveBucket(ctx, bucket) | 
					
						
							|  |  |  | 	if err == nil || err.Error() != "Access Denied." { | 
					
						
							|  |  |  | 		c.Fatalf("bucket was deleted unexpectedly or got unexpected err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Craft a request to update the user's permissions
 | 
					
						
							|  |  |  | 	ep := s.adm.GetEndpointURL() | 
					
						
							|  |  |  | 	urlValue := url.Values{} | 
					
						
							|  |  |  | 	urlValue.Add("accessKey", accessKey) | 
					
						
							|  |  |  | 	u, err := url.Parse(fmt.Sprintf("%s://%s/minio/admin/v3/add-user?%s", ep.Scheme, ep.Host, s3utils.QueryEncode(urlValue))) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unexpected url parse err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodPut, u.String(), nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unexpected new request err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	reqBodyArg := madmin.UserInfo{ | 
					
						
							|  |  |  | 		SecretKey:  secretKey, | 
					
						
							|  |  |  | 		PolicyName: "consoleAdmin", | 
					
						
							|  |  |  | 		Status:     madmin.AccountEnabled, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	buf, err := json.Marshal(reqBodyArg) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unexpected json encode err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	buf, err = madmin.EncryptData(secretKey, buf) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unexpected encryption err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req.ContentLength = int64(len(buf)) | 
					
						
							|  |  |  | 	sum := sha256.Sum256(buf) | 
					
						
							|  |  |  | 	req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(sum[:])) | 
					
						
							|  |  |  | 	req.Body = ioutil.NopCloser(bytes.NewReader(buf)) | 
					
						
							|  |  |  | 	req = signer.SignV4(*req, accessKey, secretKey, "", "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.1 Execute the request.
 | 
					
						
							|  |  |  | 	resp, err := s.TestSuiteCommon.client.Do(req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unexpected request err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if resp.StatusCode != 200 { | 
					
						
							|  |  |  | 		c.Fatalf("got unexpected response: %#v\n", resp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.2 check that user cannot delete the bucket
 | 
					
						
							|  |  |  | 	err = uClient.RemoveBucket(ctx, bucket) | 
					
						
							|  |  |  | 	if err == nil || err.Error() != "Access Denied." { | 
					
						
							|  |  |  | 		c.Fatalf("User was able to escalate privileges (Err=%v)!", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | func (s *TestSuiteIAM) TestAddServiceAccountPerms(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Create a policy
 | 
					
						
							|  |  |  | 	policy1 := "deny-svc" | 
					
						
							|  |  |  | 	policy2 := "allow-svc" | 
					
						
							|  |  |  | 	policyBytes := []byte(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Deny", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "admin:CreateServiceAccount" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	newPolicyBytes := []byte(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::testbucket/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := s.adm.AddCannedPolicy(ctx, policy1, policyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy2, newPolicyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Verify that policy json is validated by server
 | 
					
						
							|  |  |  | 	invalidPolicyBytes := policyBytes[:len(policyBytes)-1] | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy1+"invalid", invalidPolicyBytes) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("invalid policy creation success") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Create a user, associate policy and verify access
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 3.1 check that user does not have any access to the bucket
 | 
					
						
							|  |  |  | 	uClient := s.getUserClient(c, accessKey, secretKey, "") | 
					
						
							|  |  |  | 	c.mustNotListObjects(ctx, uClient, "testbucket") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.2 associate policy to user
 | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, policy1, accessKey, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	admClnt := s.getAdminClient(c, accessKey, secretKey, "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.3 check user does not have explicit permissions to create service account.
 | 
					
						
							|  |  |  | 	c.mustNotCreateSvcAccount(ctx, accessKey, admClnt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4. Verify the policy appears in listing
 | 
					
						
							|  |  |  | 	ps, err := s.adm.ListCannedPolicies(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy list err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, ok := ps[policy1] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		c.Fatalf("policy was missing!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.2 associate policy to user
 | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, policy2, accessKey, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.3 check user can create service account implicitly.
 | 
					
						
							|  |  |  | 	c.mustCreateSvcAccount(ctx, accessKey, admClnt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, ok = ps[policy2] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		c.Fatalf("policy was missing!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = s.adm.RemoveUser(ctx, accessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("user could not be deleted: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = s.adm.RemoveCannedPolicy(ctx, policy1) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy del err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = s.adm.RemoveCannedPolicy(ctx, policy2) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy del err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | func (s *TestSuiteIAM) TestPolicyCreate(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket creat error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Create a policy
 | 
					
						
							|  |  |  | 	policy := "mypolicy" | 
					
						
							|  |  |  | 	policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject", | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Verify that policy json is validated by server
 | 
					
						
							|  |  |  | 	invalidPolicyBytes := policyBytes[:len(policyBytes)-1] | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy+"invalid", invalidPolicyBytes) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("invalid policy creation success") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Create a user, associate policy and verify access
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 3.1 check that user does not have any access to the bucket
 | 
					
						
							|  |  |  | 	uClient := s.getUserClient(c, accessKey, secretKey, "") | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.mustNotListObjects(ctx, uClient, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	// 3.2 associate policy to user
 | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, policy, accessKey, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 3.3 check user has access to bucket
 | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.mustListObjects(ctx, uClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	// 3.4 Check that user cannot exceed their permissions
 | 
					
						
							|  |  |  | 	err = uClient.RemoveBucket(ctx, bucket) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket was deleted!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4. Verify the policy appears in listing
 | 
					
						
							|  |  |  | 	ps, err := s.adm.ListCannedPolicies(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy list err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	_, ok := ps[policy] | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	if !ok { | 
					
						
							|  |  |  | 		c.Fatalf("policy was missing!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 10:47:49 +08:00
										 |  |  | 	// 5. Check that policy cannot be deleted when attached to a user.
 | 
					
						
							|  |  |  | 	err = s.adm.RemoveCannedPolicy(ctx, policy) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy could be unexpectedly deleted!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 6. Delete the user and then delete the policy.
 | 
					
						
							|  |  |  | 	err = s.adm.RemoveUser(ctx, accessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("user could not be deleted: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	err = s.adm.RemoveCannedPolicy(ctx, policy) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-11-04 10:47:49 +08:00
										 |  |  | 		c.Fatalf("policy del err: %v", err) | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 10:49:05 +08:00
										 |  |  | func (s *TestSuiteIAM) TestCannedPolicies(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policies, err := s.adm.ListCannedPolicies(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to list policies: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	defaultPolicies := []string{ | 
					
						
							|  |  |  | 		"readwrite", | 
					
						
							|  |  |  | 		"readonly", | 
					
						
							|  |  |  | 		"writeonly", | 
					
						
							|  |  |  | 		"diagnostics", | 
					
						
							|  |  |  | 		"consoleAdmin", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, v := range defaultPolicies { | 
					
						
							|  |  |  | 		if _, ok := policies[v]; !ok { | 
					
						
							|  |  |  | 			c.Fatalf("Failed to find %s in policies list", v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 	err = s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket creat error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject", | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check that default policies can be overwritten.
 | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, "readwrite", policyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info, err := s.adm.InfoCannedPolicy(ctx, "readwrite") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy info err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	infoStr := string(info) | 
					
						
							|  |  |  | 	if !strings.Contains(infoStr, `"s3:PutObject"`) || !strings.Contains(infoStr, ":"+bucket+"/") { | 
					
						
							|  |  |  | 		c.Fatalf("policy contains unexpected content!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | func (s *TestSuiteIAM) TestGroupAddRemove(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket creat error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policy := "mypolicy" | 
					
						
							|  |  |  | 	policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject", | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Add user to a new group
 | 
					
						
							|  |  |  | 	group := "mygroup" | 
					
						
							|  |  |  | 	err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ | 
					
						
							|  |  |  | 		Group:   group, | 
					
						
							|  |  |  | 		Members: []string{accessKey}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to add user to group: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Check that user has no access
 | 
					
						
							|  |  |  | 	uClient := s.getUserClient(c, accessKey, secretKey, "") | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.mustNotListObjects(ctx, uClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Associate policy to group and check user got access.
 | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, policy, group, true) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// 3.1 check user has access to bucket
 | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.mustListObjects(ctx, uClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	// 3.2 Check that user cannot exceed their permissions
 | 
					
						
							|  |  |  | 	err = uClient.RemoveBucket(ctx, bucket) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket was deleted!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4. List groups and members and verify
 | 
					
						
							|  |  |  | 	groups, err := s.adm.ListGroups(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group list err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !set.CreateStringSet(groups...).Contains(group) { | 
					
						
							|  |  |  | 		c.Fatalf("created group not present!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	groupInfo, err := s.adm.GetGroupDescription(ctx, group) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group desc err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(groupInfo.Name, group) | 
					
						
							|  |  |  | 	c.Assert(set.CreateStringSet(groupInfo.Members...), set.CreateStringSet(accessKey)) | 
					
						
							|  |  |  | 	c.Assert(groupInfo.Policy, policy) | 
					
						
							|  |  |  | 	c.Assert(groupInfo.Status, string(madmin.GroupEnabled)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 5. Disable/enable the group and verify that user access is revoked/restored.
 | 
					
						
							|  |  |  | 	err = s.adm.SetGroupStatus(ctx, group, madmin.GroupDisabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group set status err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	groupInfo, err = s.adm.GetGroupDescription(ctx, group) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group desc err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(groupInfo.Status, string(madmin.GroupDisabled)) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.mustNotListObjects(ctx, uClient, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	err = s.adm.SetGroupStatus(ctx, group, madmin.GroupEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group set status err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	groupInfo, err = s.adm.GetGroupDescription(ctx, group) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group desc err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(groupInfo.Status, string(madmin.GroupEnabled)) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.mustListObjects(ctx, uClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 6. Verify that group cannot be deleted with users.
 | 
					
						
							|  |  |  | 	err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ | 
					
						
							|  |  |  | 		Group:    group, | 
					
						
							|  |  |  | 		IsRemove: true, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("group was removed!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	groupInfo, err = s.adm.GetGroupDescription(ctx, group) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group desc err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(groupInfo.Name, group) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 7. Remove user from group and verify access is revoked.
 | 
					
						
							|  |  |  | 	err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ | 
					
						
							|  |  |  | 		Group:    group, | 
					
						
							|  |  |  | 		Members:  []string{accessKey}, | 
					
						
							|  |  |  | 		IsRemove: true, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group update err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.mustNotListObjects(ctx, uClient, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | 	// 7.1 verify group still exists
 | 
					
						
							|  |  |  | 	groupInfo, err = s.adm.GetGroupDescription(ctx, group) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group desc err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(groupInfo.Name, group) | 
					
						
							|  |  |  | 	c.Assert(len(groupInfo.Members), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 8. Delete group and verify
 | 
					
						
							|  |  |  | 	err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{ | 
					
						
							|  |  |  | 		Group:    group, | 
					
						
							|  |  |  | 		IsRemove: true, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group update err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	groups, err = s.adm.ListGroups(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("group list err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if set.CreateStringSet(groups...).Contains(group) { | 
					
						
							|  |  |  | 		c.Fatalf("created group still present!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	groupInfo, err = s.adm.GetGroupDescription(ctx, group) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("group appears to exist") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | func (s *TestSuiteIAM) TestServiceAccountOpsByUser(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket creat error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create policy, user and associate policy
 | 
					
						
							|  |  |  | 	policy := "mypolicy" | 
					
						
							|  |  |  | 	policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject", | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, policy, accessKey, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create an madmin client with user creds
 | 
					
						
							|  |  |  | 	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ | 
					
						
							|  |  |  | 		Creds:  cr.NewStaticV4(accessKey, secretKey, ""), | 
					
						
							|  |  |  | 		Secure: s.secure, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Err creating user admin client: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create svc acc
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	cr := c.mustCreateSvcAccount(ctx, accessKey, userAdmClient) | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Check that svc account appears in listing
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.assertSvcAccAppearsInListing(ctx, userAdmClient, accessKey, cr.AccessKey) | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Check that svc account info can be queried
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.assertSvcAccInfoQueryable(ctx, userAdmClient, accessKey, cr.AccessKey, false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Check S3 access
 | 
					
						
							|  |  |  | 	c.assertSvcAccS3Access(ctx, s, cr, bucket) | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 4. Check that svc account can restrict the policy, and that the
 | 
					
						
							|  |  |  | 	// session policy can be updated.
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.assertSvcAccSessionPolicyUpdate(ctx, s, userAdmClient, accessKey, bucket) | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 4. Check that service account's secret key and account status can be
 | 
					
						
							|  |  |  | 	// updated.
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.assertSvcAccSecretKeyAndStatusUpdate(ctx, s, userAdmClient, accessKey, bucket) | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 5. Check that service account can be deleted.
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.assertSvcAccDeletion(ctx, s, userAdmClient, accessKey, bucket) | 
					
						
							| 
									
										
										
										
											2022-04-12 06:30:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 6. Check that service account cannot be created for some other user.
 | 
					
						
							|  |  |  | 	c.mustNotCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient) | 
					
						
							| 
									
										
										
										
											2021-11-20 04:35:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *TestSuiteIAM) TestServiceAccountOpsByAdmin(c *check) { | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket creat error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create policy, user and associate policy
 | 
					
						
							|  |  |  | 	policy := "mypolicy" | 
					
						
							|  |  |  | 	policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject", | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							|  |  |  | 	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("policy add error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = s.adm.SetPolicy(ctx, policy, accessKey, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set policy: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Create a service account for the user
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	cr := c.mustCreateSvcAccount(ctx, accessKey, s.adm) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1.2 Check that svc account appears in listing
 | 
					
						
							|  |  |  | 	c.assertSvcAccAppearsInListing(ctx, s.adm, accessKey, cr.AccessKey) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1.3 Check that svc account info can be queried
 | 
					
						
							|  |  |  | 	c.assertSvcAccInfoQueryable(ctx, s.adm, accessKey, cr.AccessKey, false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Check that svc account can access the bucket
 | 
					
						
							|  |  |  | 	c.assertSvcAccS3Access(ctx, s, cr, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Check that svc account can restrict the policy, and that the
 | 
					
						
							|  |  |  | 	// session policy can be updated.
 | 
					
						
							|  |  |  | 	c.assertSvcAccSessionPolicyUpdate(ctx, s, s.adm, accessKey, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4. Check that service account's secret key and account status can be
 | 
					
						
							|  |  |  | 	// updated.
 | 
					
						
							|  |  |  | 	c.assertSvcAccSecretKeyAndStatusUpdate(ctx, s, s.adm, accessKey, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 5. Check that service account can be deleted.
 | 
					
						
							|  |  |  | 	c.assertSvcAccDeletion(ctx, s, s.adm, accessKey, bucket) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-13 06:24:19 +08:00
										 |  |  | func (s *TestSuiteIAM) SetUpAccMgmtPlugin(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pluginEndpoint := os.Getenv("POLICY_PLUGIN_ENDPOINT") | 
					
						
							|  |  |  | 	if pluginEndpoint == "" { | 
					
						
							|  |  |  | 		c.Skip("POLICY_PLUGIN_ENDPOINT not given - skipping.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	configCmds := []string{ | 
					
						
							|  |  |  | 		"policy_plugin", | 
					
						
							|  |  |  | 		"url=" + pluginEndpoint, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " ")) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to setup access management plugin for tests: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.RestartIAMSuite(c) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestIAM_AMPInternalIDPServerSuite - tests for access management plugin
 | 
					
						
							|  |  |  | func TestIAM_AMPInternalIDPServerSuite(t *testing.T) { | 
					
						
							|  |  |  | 	for i, testCase := range iamTestSuites { | 
					
						
							|  |  |  | 		t.Run( | 
					
						
							|  |  |  | 			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription), | 
					
						
							|  |  |  | 			func(t *testing.T) { | 
					
						
							|  |  |  | 				suite := testCase | 
					
						
							|  |  |  | 				c := &check{t, testCase.serverType} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				suite.SetUpSuite(c) | 
					
						
							|  |  |  | 				defer suite.TearDownSuite(c) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				suite.SetUpAccMgmtPlugin(c) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				suite.TestAccMgmtPlugin(c) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestAccMgmtPlugin - this test assumes that the access-management-plugin is
 | 
					
						
							|  |  |  | // the same as the example in `docs/iam/access-manager-plugin.go` -
 | 
					
						
							|  |  |  | // specifically, it denies only `s3:Put*` operations on non-root accounts.
 | 
					
						
							|  |  |  | func (s *TestSuiteIAM) TestAccMgmtPlugin(c *check) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 0. Check that owner is able to make-bucket.
 | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("bucket creat error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Create a user.
 | 
					
						
							|  |  |  | 	accessKey, secretKey := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to set user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Check new user appears in listing
 | 
					
						
							|  |  |  | 	usersMap, err := s.adm.ListUsers(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("error listing: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	v, ok := usersMap[accessKey] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		c.Fatalf("user not listed: %s", accessKey) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Assert(v.Status, madmin.AccountEnabled) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Check that user is able to make a bucket.
 | 
					
						
							|  |  |  | 	client := s.getUserClient(c, accessKey, secretKey, "") | 
					
						
							|  |  |  | 	err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("user not create bucket: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.1 check user has access to bucket
 | 
					
						
							|  |  |  | 	c.mustListObjects(ctx, client, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3.2 check that user cannot upload an object.
 | 
					
						
							|  |  |  | 	_, err = client.PutObject(ctx, bucket, "objectName", bytes.NewBuffer([]byte("some content")), 12, minio.PutObjectOptions{}) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("user was able to upload unexpectedly") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create an madmin client with user creds
 | 
					
						
							|  |  |  | 	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{ | 
					
						
							|  |  |  | 		Creds:  cr.NewStaticV4(accessKey, secretKey, ""), | 
					
						
							|  |  |  | 		Secure: s.secure, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Err creating user admin client: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create svc acc
 | 
					
						
							|  |  |  | 	cr := c.mustCreateSvcAccount(ctx, accessKey, userAdmClient) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 1. Check that svc account appears in listing
 | 
					
						
							|  |  |  | 	c.assertSvcAccAppearsInListing(ctx, userAdmClient, accessKey, cr.AccessKey) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2. Check that svc account info can be queried
 | 
					
						
							|  |  |  | 	c.assertSvcAccInfoQueryable(ctx, userAdmClient, accessKey, cr.AccessKey, false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 3. Check S3 access
 | 
					
						
							|  |  |  | 	c.assertSvcAccS3Access(ctx, s, cr, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check that session policies do not apply - as policy enforcement is
 | 
					
						
							|  |  |  | 	// delegated to plugin.
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		svcAK, svcSK := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// This policy does not allow listing objects.
 | 
					
						
							|  |  |  | 		policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							|  |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							|  |  |  | 		cr, err := userAdmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ | 
					
						
							|  |  |  | 			Policy:     policyBytes, | 
					
						
							|  |  |  | 			TargetUser: accessKey, | 
					
						
							|  |  |  | 			AccessKey:  svcAK, | 
					
						
							|  |  |  | 			SecretKey:  svcSK, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			c.Fatalf("Unable to create svc acc: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") | 
					
						
							|  |  |  | 		// Though the attached policy does not allow listing, it will be
 | 
					
						
							|  |  |  | 		// ignored because the plugin allows it.
 | 
					
						
							|  |  |  | 		c.mustListObjects(ctx, svcClient, bucket) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4. Check that service account's secret key and account status can be
 | 
					
						
							|  |  |  | 	// updated.
 | 
					
						
							|  |  |  | 	c.assertSvcAccSecretKeyAndStatusUpdate(ctx, s, userAdmClient, accessKey, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 5. Check that service account can be deleted.
 | 
					
						
							|  |  |  | 	c.assertSvcAccDeletion(ctx, s, userAdmClient, accessKey, bucket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 6. Check that service account **can** be created for some other user.
 | 
					
						
							|  |  |  | 	// This is possible because of the policy enforced in the plugin.
 | 
					
						
							|  |  |  | 	c.mustCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-11 05:04:21 +08:00
										 |  |  | func (c *check) mustCreateIAMUser(ctx context.Context, admClnt *madmin.AdminClient) madmin.Credentials { | 
					
						
							|  |  |  | 	randUser := mustGetUUID() | 
					
						
							|  |  |  | 	randPass := mustGetUUID() | 
					
						
							|  |  |  | 	err := admClnt.AddUser(ctx, randUser, randPass) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("should be able to create a user: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return madmin.Credentials{ | 
					
						
							|  |  |  | 		AccessKey: randUser, | 
					
						
							|  |  |  | 		SecretKey: randPass, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-11 07:03:39 +08:00
										 |  |  | func (c *check) mustGetIAMUserInfo(ctx context.Context, admClnt *madmin.AdminClient, accessKey string) madmin.UserInfo { | 
					
						
							|  |  |  | 	ui, err := admClnt.GetUserInfo(ctx, accessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("should be able to get user info: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ui | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-11 05:04:21 +08:00
										 |  |  | func (c *check) mustNotCreateIAMUser(ctx context.Context, admClnt *madmin.AdminClient) { | 
					
						
							|  |  |  | 	randUser := mustGetUUID() | 
					
						
							|  |  |  | 	randPass := mustGetUUID() | 
					
						
							|  |  |  | 	err := admClnt.AddUser(ctx, randUser, randPass) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("should not be able to create a user") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | func (c *check) mustCreateSvcAccount(ctx context.Context, tgtUser string, admClnt *madmin.AdminClient) madmin.Credentials { | 
					
						
							|  |  |  | 	cr, err := admClnt.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ | 
					
						
							|  |  |  | 		TargetUser: tgtUser, | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 		c.Fatalf("user should be able to create service accounts %s", err) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	return cr | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *check) mustNotCreateSvcAccount(ctx context.Context, tgtUser string, admClnt *madmin.AdminClient) { | 
					
						
							|  |  |  | 	_, err := admClnt.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ | 
					
						
							|  |  |  | 		TargetUser: tgtUser, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		c.Fatalf("user was able to add service accounts unexpectedly!") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *check) mustNotListObjects(ctx context.Context, client *minio.Client, bucket string) { | 
					
						
							|  |  |  | 	res := client.ListObjects(ctx, bucket, minio.ListObjectsOptions{}) | 
					
						
							|  |  |  | 	v, ok := <-res | 
					
						
							|  |  |  | 	if !ok || v.Err == nil { | 
					
						
							| 
									
										
										
										
											2022-05-18 10:58:47 +08:00
										 |  |  | 		c.Fatalf("user was able to list unexpectedly! on %s", bucket) | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *check) mustListObjects(ctx context.Context, client *minio.Client, bucket string) { | 
					
						
							|  |  |  | 	res := client.ListObjects(ctx, bucket, minio.ListObjectsOptions{}) | 
					
						
							|  |  |  | 	v, ok := <-res | 
					
						
							|  |  |  | 	if ok && v.Err != nil { | 
					
						
							| 
									
										
										
										
											2022-05-18 10:58:47 +08:00
										 |  |  | 		c.Fatalf("user was unable to list: %v", v.Err) | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-14 03:48:02 +08:00
										 |  |  | func (c *check) mustNotUpload(ctx context.Context, client *minio.Client, bucket string) { | 
					
						
							|  |  |  | 	_, err := client.PutObject(ctx, bucket, "some-object", bytes.NewBuffer([]byte("stuff")), 5, minio.PutObjectOptions{}) | 
					
						
							|  |  |  | 	if e, ok := err.(minio.ErrorResponse); ok { | 
					
						
							|  |  |  | 		if e.Code == "AccessDenied" { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Fatalf("upload did not get an AccessDenied error - got %#v instead", err) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | func (c *check) assertSvcAccS3Access(ctx context.Context, s *TestSuiteIAM, cr madmin.Credentials, bucket string) { | 
					
						
							|  |  |  | 	svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") | 
					
						
							|  |  |  | 	c.mustListObjects(ctx, svcClient, bucket) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *check) assertSvcAccAppearsInListing(ctx context.Context, madmClient *madmin.AdminClient, parentAK, svcAK string) { | 
					
						
							|  |  |  | 	listResp, err := madmClient.ListServiceAccounts(ctx, parentAK) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to list svc accounts: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !set.CreateStringSet(listResp.Accounts...).Contains(svcAK) { | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 		c.Fatalf("service account did not appear in listing!") | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *check) assertSvcAccInfoQueryable(ctx context.Context, madmClient *madmin.AdminClient, parentAK, svcAK string, skipParentUserCheck bool) { | 
					
						
							|  |  |  | 	infoResp, err := madmClient.InfoServiceAccount(ctx, svcAK) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to get svc acc info: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	if !skipParentUserCheck { | 
					
						
							|  |  |  | 		c.Assert(infoResp.ParentUser, parentAK) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	c.Assert(infoResp.AccountStatus, "on") | 
					
						
							|  |  |  | 	c.Assert(infoResp.ImpliedPolicy, true) | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | // This test assumes that the policy for `accessKey` allows listing on the given
 | 
					
						
							|  |  |  | // bucket. It creates a session policy that restricts listing on the bucket and
 | 
					
						
							|  |  |  | // then enables it again in a session policy update call.
 | 
					
						
							|  |  |  | func (c *check) assertSvcAccSessionPolicyUpdate(ctx context.Context, s *TestSuiteIAM, madmClient *madmin.AdminClient, accessKey, bucket string) { | 
					
						
							|  |  |  | 	svcAK, svcSK := mustGenerateCredentials(c) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	// This policy does not allow listing objects.
 | 
					
						
							|  |  |  | 	policyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:PutObject", | 
					
						
							|  |  |  |     "s3:GetObject" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	cr, err := madmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ | 
					
						
							|  |  |  | 		Policy:     policyBytes, | 
					
						
							|  |  |  | 		TargetUser: accessKey, | 
					
						
							|  |  |  | 		AccessKey:  svcAK, | 
					
						
							|  |  |  | 		SecretKey:  svcSK, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to create svc acc: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") | 
					
						
							|  |  |  | 	c.mustNotListObjects(ctx, svcClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	// This policy allows listing objects.
 | 
					
						
							|  |  |  | 	newPolicyBytes := []byte(fmt.Sprintf(`{ | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  |  "Version": "2012-10-17", | 
					
						
							|  |  |  |  "Statement": [ | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |    "Effect": "Allow", | 
					
						
							|  |  |  |    "Action": [ | 
					
						
							|  |  |  |     "s3:ListBucket" | 
					
						
							|  |  |  |    ], | 
					
						
							|  |  |  |    "Resource": [ | 
					
						
							|  |  |  |     "arn:aws:s3:::%s/*" | 
					
						
							|  |  |  |    ] | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |  ] | 
					
						
							|  |  |  | }`, bucket)) | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	err = madmClient.UpdateServiceAccount(ctx, svcAK, madmin.UpdateServiceAccountReq{ | 
					
						
							|  |  |  | 		NewPolicy: newPolicyBytes, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to update session policy for svc acc: %v", err) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.mustListObjects(ctx, svcClient, bucket) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | func (c *check) assertSvcAccSecretKeyAndStatusUpdate(ctx context.Context, s *TestSuiteIAM, madmClient *madmin.AdminClient, accessKey, bucket string) { | 
					
						
							|  |  |  | 	svcAK, svcSK := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	cr, err := madmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ | 
					
						
							|  |  |  | 		TargetUser: accessKey, | 
					
						
							|  |  |  | 		AccessKey:  svcAK, | 
					
						
							|  |  |  | 		SecretKey:  svcSK, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to create svc acc: %v", err) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") | 
					
						
							|  |  |  | 	c.mustListObjects(ctx, svcClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	_, svcSK2 := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	err = madmClient.UpdateServiceAccount(ctx, svcAK, madmin.UpdateServiceAccountReq{ | 
					
						
							|  |  |  | 		NewSecretKey: svcSK2, | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 		c.Fatalf("unable to update secret key for svc acc: %v", err) | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	// old creds should not work:
 | 
					
						
							|  |  |  | 	c.mustNotListObjects(ctx, svcClient, bucket) | 
					
						
							|  |  |  | 	// new creds work:
 | 
					
						
							|  |  |  | 	svcClient2 := s.getUserClient(c, cr.AccessKey, svcSK2, "") | 
					
						
							|  |  |  | 	c.mustListObjects(ctx, svcClient2, bucket) | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	// update status to disabled
 | 
					
						
							|  |  |  | 	err = madmClient.UpdateServiceAccount(ctx, svcAK, madmin.UpdateServiceAccountReq{ | 
					
						
							|  |  |  | 		NewStatus: "off", | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to update secret key for svc acc: %v", err) | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.mustNotListObjects(ctx, svcClient2, bucket) | 
					
						
							| 
									
										
										
										
											2021-11-15 22:57:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | func (c *check) assertSvcAccDeletion(ctx context.Context, s *TestSuiteIAM, madmClient *madmin.AdminClient, accessKey, bucket string) { | 
					
						
							|  |  |  | 	svcAK, svcSK := mustGenerateCredentials(c) | 
					
						
							|  |  |  | 	cr, err := madmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{ | 
					
						
							|  |  |  | 		TargetUser: accessKey, | 
					
						
							|  |  |  | 		AccessKey:  svcAK, | 
					
						
							|  |  |  | 		SecretKey:  svcSK, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("Unable to create svc acc: %v", err) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "") | 
					
						
							|  |  |  | 	c.mustListObjects(ctx, svcClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	err = madmClient.DeleteServiceAccount(ctx, svcAK) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to delete svc acc: %v", err) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-20 18:07:16 +08:00
										 |  |  | 	c.mustNotListObjects(ctx, svcClient, bucket) | 
					
						
							| 
									
										
										
										
											2021-10-24 00:36:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-22 16:33:28 +08:00
										 |  |  | func mustGenerateCredentials(c *check) (string, string) { | 
					
						
							|  |  |  | 	ak, sk, err := auth.GenerateCredentials() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.Fatalf("unable to generate credentials: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ak, sk | 
					
						
							|  |  |  | } |