github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/sts-handlers_test.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"os"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/minio/madmin-go/v3"
    29  	minio "github.com/minio/minio-go/v7"
    30  	cr "github.com/minio/minio-go/v7/pkg/credentials"
    31  	"github.com/minio/minio-go/v7/pkg/set"
    32  	ldap "github.com/minio/pkg/v2/ldap"
    33  	"golang.org/x/exp/slices"
    34  )
    35  
    36  func runAllIAMSTSTests(suite *TestSuiteIAM, c *check) {
    37  	suite.SetUpSuite(c)
    38  	// The STS for root test needs to be the first one after setup.
    39  	suite.TestSTSForRoot(c)
    40  	suite.TestSTS(c)
    41  	suite.TestSTSWithDenyDeleteVersion(c)
    42  	suite.TestSTSWithTags(c)
    43  	suite.TestSTSServiceAccountsWithUsername(c)
    44  	suite.TestSTSWithGroupPolicy(c)
    45  	suite.TearDownSuite(c)
    46  }
    47  
    48  func TestIAMInternalIDPSTSServerSuite(t *testing.T) {
    49  	baseTestCases := []TestSuiteCommon{
    50  		// Init and run test on ErasureSD backend with signature v4.
    51  		{serverType: "ErasureSD", signer: signerV4},
    52  		// Init and run test on ErasureSD backend, with tls enabled.
    53  		{serverType: "ErasureSD", signer: signerV4, secure: true},
    54  		// Init and run test on Erasure backend.
    55  		{serverType: "Erasure", signer: signerV4},
    56  		// Init and run test on ErasureSet backend.
    57  		{serverType: "ErasureSet", signer: signerV4},
    58  	}
    59  	testCases := []*TestSuiteIAM{}
    60  	for _, bt := range baseTestCases {
    61  		testCases = append(testCases,
    62  			newTestSuiteIAM(bt, false),
    63  			newTestSuiteIAM(bt, true),
    64  		)
    65  	}
    66  	for i, testCase := range testCases {
    67  		etcdStr := ""
    68  		if testCase.withEtcdBackend {
    69  			etcdStr = " (with etcd backend)"
    70  		}
    71  		t.Run(
    72  			fmt.Sprintf("Test: %d, ServerType: %s%s", i+1, testCase.serverType, etcdStr),
    73  			func(t *testing.T) {
    74  				runAllIAMSTSTests(testCase, &check{t, testCase.serverType})
    75  			},
    76  		)
    77  	}
    78  }
    79  
    80  func (s *TestSuiteIAM) TestSTSServiceAccountsWithUsername(c *check) {
    81  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    82  	defer cancel()
    83  
    84  	bucket := "dillon-bucket"
    85  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
    86  	if err != nil {
    87  		c.Fatalf("bucket create error: %v", err)
    88  	}
    89  
    90  	// Create policy
    91  	policy := "mypolicy-username"
    92  	policyBytes := []byte(`{
    93   "Version": "2012-10-17",
    94   "Statement": [
    95    {
    96     "Effect": "Allow",
    97     "Action": [
    98      "s3:*"
    99     ],
   100     "Resource": [
   101      "arn:aws:s3:::${aws:username}-*"
   102     ]
   103    }
   104   ]
   105  }`)
   106  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
   107  	if err != nil {
   108  		c.Fatalf("policy add error: %v", err)
   109  	}
   110  
   111  	if err = s.adm.AddUser(ctx, "dillon", "dillon-123"); err != nil {
   112  		c.Fatalf("policy add error: %v", err)
   113  	}
   114  
   115  	err = s.adm.SetPolicy(ctx, policy, "dillon", false)
   116  	if err != nil {
   117  		c.Fatalf("Unable to set policy: %v", err)
   118  	}
   119  
   120  	assumeRole := cr.STSAssumeRole{
   121  		Client:      s.TestSuiteCommon.client,
   122  		STSEndpoint: s.endPoint,
   123  		Options: cr.STSAssumeRoleOptions{
   124  			AccessKey: "dillon",
   125  			SecretKey: "dillon-123",
   126  			Location:  "",
   127  		},
   128  	}
   129  
   130  	value, err := assumeRole.Retrieve()
   131  	if err != nil {
   132  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
   133  	}
   134  
   135  	// Check that the LDAP sts cred is actually working.
   136  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   137  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   138  		Secure:    s.secure,
   139  		Transport: s.TestSuiteCommon.client.Transport,
   140  	})
   141  	if err != nil {
   142  		c.Fatalf("Error initializing client: %v", err)
   143  	}
   144  
   145  	// Validate that the client from sts creds can access the bucket.
   146  	c.mustListObjects(ctx, minioClient, bucket)
   147  
   148  	// Create an madmin client with user creds
   149  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
   150  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   151  		Secure: s.secure,
   152  	})
   153  	if err != nil {
   154  		c.Fatalf("Err creating user admin client: %v", err)
   155  	}
   156  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
   157  
   158  	// Create svc acc
   159  	cr := c.mustCreateSvcAccount(ctx, value.AccessKeyID, userAdmClient)
   160  
   161  	svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "")
   162  
   163  	// 1. Check S3 access for service account ListObjects()
   164  	c.mustListObjects(ctx, svcClient, bucket)
   165  
   166  	// 2. Check S3 access for upload
   167  	c.mustUpload(ctx, svcClient, bucket)
   168  
   169  	// 3. Check S3 access for download
   170  	c.mustDownload(ctx, svcClient, bucket)
   171  }
   172  
   173  func (s *TestSuiteIAM) TestSTSWithDenyDeleteVersion(c *check) {
   174  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   175  	defer cancel()
   176  
   177  	bucket := getRandomBucketName()
   178  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{ObjectLocking: true})
   179  	if err != nil {
   180  		c.Fatalf("bucket creat error: %v", err)
   181  	}
   182  
   183  	// Create policy, user and associate policy
   184  	policy := "mypolicy"
   185  	policyBytes := []byte(fmt.Sprintf(`{
   186    "Version": "2012-10-17",
   187    "Statement": [
   188     {
   189      "Sid": "ObjectActionsRW",
   190      "Effect": "Allow",
   191      "Action": [
   192       "s3:PutObject",
   193       "s3:PutObjectTagging",
   194       "s3:AbortMultipartUpload",
   195       "s3:DeleteObject",
   196       "s3:GetObject",
   197       "s3:GetObjectTagging",
   198       "s3:GetObjectVersion",
   199       "s3:ListMultipartUploadParts"
   200      ],
   201      "Resource": [
   202       "arn:aws:s3:::%s/*"
   203      ]
   204     },
   205     {
   206      "Sid": "DenyDeleteVersionAction",
   207      "Effect": "Deny",
   208      "Action": [
   209       "s3:DeleteObjectVersion"
   210      ],
   211      "Resource": [
   212       "arn:aws:s3:::%s/*"
   213      ]
   214     }
   215    ]
   216   }
   217  `, bucket, bucket))
   218  
   219  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
   220  	if err != nil {
   221  		c.Fatalf("policy add error: %v", err)
   222  	}
   223  
   224  	accessKey, secretKey := mustGenerateCredentials(c)
   225  	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
   226  	if err != nil {
   227  		c.Fatalf("Unable to set user: %v", err)
   228  	}
   229  
   230  	err = s.adm.SetPolicy(ctx, policy, accessKey, false)
   231  	if err != nil {
   232  		c.Fatalf("Unable to set policy: %v", err)
   233  	}
   234  
   235  	// confirm that the user is able to access the bucket
   236  	uClient := s.getUserClient(c, accessKey, secretKey, "")
   237  	versions := c.mustUploadReturnVersions(ctx, uClient, bucket)
   238  	c.mustNotDelete(ctx, uClient, bucket, versions[0])
   239  
   240  	assumeRole := cr.STSAssumeRole{
   241  		Client:      s.TestSuiteCommon.client,
   242  		STSEndpoint: s.endPoint,
   243  		Options: cr.STSAssumeRoleOptions{
   244  			AccessKey: accessKey,
   245  			SecretKey: secretKey,
   246  			Location:  "",
   247  		},
   248  	}
   249  
   250  	value, err := assumeRole.Retrieve()
   251  	if err != nil {
   252  		c.Fatalf("err calling assumeRole: %v", err)
   253  	}
   254  
   255  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   256  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   257  		Secure:    s.secure,
   258  		Transport: s.TestSuiteCommon.client.Transport,
   259  	})
   260  	if err != nil {
   261  		c.Fatalf("Error initializing client: %v", err)
   262  	}
   263  
   264  	versions = c.mustUploadReturnVersions(ctx, minioClient, bucket)
   265  	c.mustNotDelete(ctx, minioClient, bucket, versions[0])
   266  }
   267  
   268  func (s *TestSuiteIAM) TestSTSWithTags(c *check) {
   269  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   270  	defer cancel()
   271  
   272  	bucket := getRandomBucketName()
   273  	object := getRandomObjectName()
   274  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
   275  	if err != nil {
   276  		c.Fatalf("bucket creat error: %v", err)
   277  	}
   278  
   279  	// Create policy, user and associate policy
   280  	policy := "mypolicy"
   281  	policyBytes := []byte(fmt.Sprintf(`{
   282    "Version": "2012-10-17",
   283    "Statement": [
   284      {
   285        "Effect":     "Allow",
   286        "Action":     "s3:GetObject",
   287        "Resource":    "arn:aws:s3:::%s/*",
   288        "Condition": {  "StringEquals": {"s3:ExistingObjectTag/security": "public" } }
   289      },
   290      {
   291        "Effect":     "Allow",
   292        "Action":     "s3:DeleteObjectTagging",
   293        "Resource":    "arn:aws:s3:::%s/*",
   294        "Condition": {  "StringEquals": {"s3:ExistingObjectTag/security": "public" } }
   295      },
   296      {
   297        "Effect":     "Allow",
   298        "Action":     "s3:DeleteObject",
   299        "Resource":    "arn:aws:s3:::%s/*"
   300      },
   301      {
   302        "Effect": "Allow",
   303        "Action": [
   304          "s3:PutObject"
   305        ],
   306        "Resource": [
   307          "arn:aws:s3:::%s/*"
   308        ],
   309        "Condition": {
   310          "ForAllValues:StringLike": {
   311            "s3:RequestObjectTagKeys": [
   312              "security",
   313              "virus"
   314            ]
   315          }
   316        }
   317      }
   318    ]
   319  }`, bucket, bucket, bucket, bucket))
   320  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
   321  	if err != nil {
   322  		c.Fatalf("policy add error: %v", err)
   323  	}
   324  
   325  	accessKey, secretKey := mustGenerateCredentials(c)
   326  	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
   327  	if err != nil {
   328  		c.Fatalf("Unable to set user: %v", err)
   329  	}
   330  
   331  	err = s.adm.SetPolicy(ctx, policy, accessKey, false)
   332  	if err != nil {
   333  		c.Fatalf("Unable to set policy: %v", err)
   334  	}
   335  
   336  	// confirm that the user is able to access the bucket
   337  	uClient := s.getUserClient(c, accessKey, secretKey, "")
   338  	c.mustPutObjectWithTags(ctx, uClient, bucket, object)
   339  	c.mustGetObject(ctx, uClient, bucket, object)
   340  
   341  	assumeRole := cr.STSAssumeRole{
   342  		Client:      s.TestSuiteCommon.client,
   343  		STSEndpoint: s.endPoint,
   344  		Options: cr.STSAssumeRoleOptions{
   345  			AccessKey: accessKey,
   346  			SecretKey: secretKey,
   347  			Location:  "",
   348  		},
   349  	}
   350  
   351  	value, err := assumeRole.Retrieve()
   352  	if err != nil {
   353  		c.Fatalf("err calling assumeRole: %v", err)
   354  	}
   355  
   356  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   357  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   358  		Secure:    s.secure,
   359  		Transport: s.TestSuiteCommon.client.Transport,
   360  	})
   361  	if err != nil {
   362  		c.Fatalf("Error initializing client: %v", err)
   363  	}
   364  
   365  	// Validate sts creds can access the object
   366  	c.mustPutObjectWithTags(ctx, minioClient, bucket, object)
   367  	c.mustGetObject(ctx, minioClient, bucket, object)
   368  	c.mustHeadObject(ctx, minioClient, bucket, object, 2)
   369  
   370  	// Validate that the client can remove objects
   371  	if err = minioClient.RemoveObjectTagging(ctx, bucket, object, minio.RemoveObjectTaggingOptions{}); err != nil {
   372  		c.Fatalf("user is unable to delete the object tags: %v", err)
   373  	}
   374  
   375  	if err = minioClient.RemoveObject(ctx, bucket, object, minio.RemoveObjectOptions{}); err != nil {
   376  		c.Fatalf("user is unable to delete the object: %v", err)
   377  	}
   378  }
   379  
   380  func (s *TestSuiteIAM) TestSTS(c *check) {
   381  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   382  	defer cancel()
   383  
   384  	bucket := getRandomBucketName()
   385  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
   386  	if err != nil {
   387  		c.Fatalf("bucket creat error: %v", err)
   388  	}
   389  
   390  	// Create policy, user and associate policy
   391  	policy := "mypolicy"
   392  	policyBytes := []byte(fmt.Sprintf(`{
   393   "Version": "2012-10-17",
   394   "Statement": [
   395    {
   396     "Effect": "Allow",
   397     "Action": [
   398      "s3:PutObject",
   399      "s3:GetObject",
   400      "s3:ListBucket"
   401     ],
   402     "Resource": [
   403      "arn:aws:s3:::%s/*"
   404     ]
   405    }
   406   ]
   407  }`, bucket))
   408  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
   409  	if err != nil {
   410  		c.Fatalf("policy add error: %v", err)
   411  	}
   412  
   413  	accessKey, secretKey := mustGenerateCredentials(c)
   414  	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
   415  	if err != nil {
   416  		c.Fatalf("Unable to set user: %v", err)
   417  	}
   418  
   419  	err = s.adm.SetPolicy(ctx, policy, accessKey, false)
   420  	if err != nil {
   421  		c.Fatalf("Unable to set policy: %v", err)
   422  	}
   423  
   424  	// confirm that the user is able to access the bucket
   425  	uClient := s.getUserClient(c, accessKey, secretKey, "")
   426  	c.mustListObjects(ctx, uClient, bucket)
   427  
   428  	assumeRole := cr.STSAssumeRole{
   429  		Client:      s.TestSuiteCommon.client,
   430  		STSEndpoint: s.endPoint,
   431  		Options: cr.STSAssumeRoleOptions{
   432  			AccessKey: accessKey,
   433  			SecretKey: secretKey,
   434  			Location:  "",
   435  		},
   436  	}
   437  
   438  	value, err := assumeRole.Retrieve()
   439  	if err != nil {
   440  		c.Fatalf("err calling assumeRole: %v", err)
   441  	}
   442  
   443  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   444  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   445  		Secure:    s.secure,
   446  		Transport: s.TestSuiteCommon.client.Transport,
   447  	})
   448  	if err != nil {
   449  		c.Fatalf("Error initializing client: %v", err)
   450  	}
   451  
   452  	// Validate that the client from sts creds can access the bucket.
   453  	c.mustListObjects(ctx, minioClient, bucket)
   454  
   455  	// Validate that the client cannot remove any objects
   456  	err = minioClient.RemoveObject(ctx, bucket, "someobject", minio.RemoveObjectOptions{})
   457  	if err.Error() != "Access Denied." {
   458  		c.Fatalf("unexpected non-access-denied err: %v", err)
   459  	}
   460  }
   461  
   462  func (s *TestSuiteIAM) TestSTSWithGroupPolicy(c *check) {
   463  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   464  	defer cancel()
   465  
   466  	bucket := getRandomBucketName()
   467  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
   468  	if err != nil {
   469  		c.Fatalf("bucket creat error: %v", err)
   470  	}
   471  
   472  	// Create policy, user and associate policy
   473  	policy := "mypolicy"
   474  	policyBytes := []byte(fmt.Sprintf(`{
   475   "Version": "2012-10-17",
   476   "Statement": [
   477    {
   478     "Effect": "Allow",
   479     "Action": [
   480      "s3:PutObject",
   481      "s3:GetObject",
   482      "s3:ListBucket"
   483     ],
   484     "Resource": [
   485      "arn:aws:s3:::%s/*"
   486     ]
   487    }
   488   ]
   489  }`, bucket))
   490  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
   491  	if err != nil {
   492  		c.Fatalf("policy add error: %v", err)
   493  	}
   494  
   495  	accessKey, secretKey := mustGenerateCredentials(c)
   496  	err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
   497  	if err != nil {
   498  		c.Fatalf("Unable to set user: %v", err)
   499  	}
   500  
   501  	// confirm that the user is unable to access the bucket - we have not
   502  	// yet set any policy
   503  	uClient := s.getUserClient(c, accessKey, secretKey, "")
   504  	c.mustNotListObjects(ctx, uClient, bucket)
   505  
   506  	err = s.adm.UpdateGroupMembers(ctx, madmin.GroupAddRemove{
   507  		Group:   "test-group",
   508  		Members: []string{accessKey},
   509  	})
   510  	if err != nil {
   511  		c.Fatalf("unable to add user to group: %v", err)
   512  	}
   513  
   514  	err = s.adm.SetPolicy(ctx, policy, "test-group", true)
   515  	if err != nil {
   516  		c.Fatalf("Unable to set policy: %v", err)
   517  	}
   518  
   519  	// confirm that the user is able to access the bucket - permission comes
   520  	// from group.
   521  	c.mustListObjects(ctx, uClient, bucket)
   522  
   523  	// Create STS user.
   524  	assumeRole := cr.STSAssumeRole{
   525  		Client:      s.TestSuiteCommon.client,
   526  		STSEndpoint: s.endPoint,
   527  		Options: cr.STSAssumeRoleOptions{
   528  			AccessKey: accessKey,
   529  			SecretKey: secretKey,
   530  			Location:  "",
   531  		},
   532  	}
   533  	value, err := assumeRole.Retrieve()
   534  	if err != nil {
   535  		c.Fatalf("err calling assumeRole: %v", err)
   536  	}
   537  
   538  	// Check that STS user client has access coming from parent user's
   539  	// group.
   540  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   541  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   542  		Secure:    s.secure,
   543  		Transport: s.TestSuiteCommon.client.Transport,
   544  	})
   545  	if err != nil {
   546  		c.Fatalf("Error initializing client: %v", err)
   547  	}
   548  
   549  	// Validate that the client from sts creds can access the bucket.
   550  	c.mustListObjects(ctx, minioClient, bucket)
   551  
   552  	// Validate that the client cannot remove any objects
   553  	err = minioClient.RemoveObject(ctx, bucket, "someobject", minio.RemoveObjectOptions{})
   554  	if err.Error() != "Access Denied." {
   555  		c.Fatalf("unexpected non-access-denied err: %v", err)
   556  	}
   557  }
   558  
   559  // TestSTSForRoot - needs to be the first test after server setup due to the
   560  // buckets list check.
   561  func (s *TestSuiteIAM) TestSTSForRoot(c *check) {
   562  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   563  	defer cancel()
   564  
   565  	bucket := getRandomBucketName()
   566  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
   567  	if err != nil {
   568  		c.Fatalf("bucket create error: %v", err)
   569  	}
   570  
   571  	assumeRole := cr.STSAssumeRole{
   572  		Client:      s.TestSuiteCommon.client,
   573  		STSEndpoint: s.endPoint,
   574  		Options: cr.STSAssumeRoleOptions{
   575  			AccessKey: globalActiveCred.AccessKey,
   576  			SecretKey: globalActiveCred.SecretKey,
   577  			Location:  "",
   578  		},
   579  	}
   580  
   581  	value, err := assumeRole.Retrieve()
   582  	if err != nil {
   583  		c.Fatalf("err calling assumeRole: %v", err)
   584  	}
   585  
   586  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   587  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   588  		Secure:    s.secure,
   589  		Transport: s.TestSuiteCommon.client.Transport,
   590  	})
   591  	if err != nil {
   592  		c.Fatalf("Error initializing client: %v", err)
   593  	}
   594  
   595  	// Validate that the client from sts creds can access the bucket.
   596  	c.mustListObjects(ctx, minioClient, bucket)
   597  
   598  	// Validate that a bucket can be created
   599  	bucket2 := getRandomBucketName()
   600  	err = minioClient.MakeBucket(ctx, bucket2, minio.MakeBucketOptions{})
   601  	if err != nil {
   602  		c.Fatalf("bucket creat error: %v", err)
   603  	}
   604  
   605  	// Validate that admin APIs can be called - create an madmin client with
   606  	// user creds
   607  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
   608  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   609  		Secure: s.secure,
   610  	})
   611  	if err != nil {
   612  		c.Fatalf("Err creating user admin client: %v", err)
   613  	}
   614  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
   615  
   616  	time.Sleep(2 * time.Second) // wait for listbuckets cache to be invalidated
   617  
   618  	accInfo, err := userAdmClient.AccountInfo(ctx, madmin.AccountOpts{})
   619  	if err != nil {
   620  		c.Fatalf("root user STS should be able to get account info: %v", err)
   621  	}
   622  
   623  	gotBuckets := set.NewStringSet()
   624  	for _, b := range accInfo.Buckets {
   625  		gotBuckets.Add(b.Name)
   626  		if !(b.Access.Read && b.Access.Write) {
   627  			c.Fatalf("root user should have read and write access to bucket: %v", b.Name)
   628  		}
   629  	}
   630  	shouldHaveBuckets := set.CreateStringSet(bucket2, bucket)
   631  	if !gotBuckets.Equals(shouldHaveBuckets) {
   632  		c.Fatalf("root user should have access to all buckets")
   633  	}
   634  
   635  	// This must fail.
   636  	if err := userAdmClient.AddUser(ctx, globalActiveCred.AccessKey, globalActiveCred.SecretKey); err == nil {
   637  		c.Fatal("AddUser() for root credential must fail via root STS creds")
   638  	}
   639  }
   640  
   641  // SetUpLDAP - expects to setup an LDAP test server using the test LDAP
   642  // container and canned data from https://github.com/minio/minio-ldap-testing
   643  func (s *TestSuiteIAM) SetUpLDAP(c *check, serverAddr string) {
   644  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   645  	defer cancel()
   646  
   647  	configCmds := []string{
   648  		"identity_ldap",
   649  		fmt.Sprintf("server_addr=%s", serverAddr),
   650  		"server_insecure=on",
   651  		"lookup_bind_dn=cn=admin,dc=min,dc=io",
   652  		"lookup_bind_password=admin",
   653  		"user_dn_search_base_dn=dc=min,dc=io",
   654  		"user_dn_search_filter=(uid=%s)",
   655  		"group_search_base_dn=ou=swengg,dc=min,dc=io",
   656  		"group_search_filter=(&(objectclass=groupofnames)(member=%d))",
   657  	}
   658  	_, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " "))
   659  	if err != nil {
   660  		c.Fatalf("unable to setup LDAP for tests: %v", err)
   661  	}
   662  
   663  	s.RestartIAMSuite(c)
   664  }
   665  
   666  const (
   667  	EnvTestLDAPServer = "_MINIO_LDAP_TEST_SERVER"
   668  )
   669  
   670  func TestIAMWithLDAPServerSuite(t *testing.T) {
   671  	for i, testCase := range iamTestSuites {
   672  		t.Run(
   673  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
   674  			func(t *testing.T) {
   675  				c := &check{t, testCase.serverType}
   676  				suite := testCase
   677  
   678  				ldapServer := os.Getenv(EnvTestLDAPServer)
   679  				if ldapServer == "" {
   680  					c.Skip("Skipping LDAP test as no LDAP server is provided.")
   681  				}
   682  
   683  				suite.SetUpSuite(c)
   684  				suite.SetUpLDAP(c, ldapServer)
   685  				suite.TestLDAPSTS(c)
   686  				suite.TestLDAPUnicodeVariations(c)
   687  				suite.TestLDAPSTSServiceAccounts(c)
   688  				suite.TestLDAPSTSServiceAccountsWithUsername(c)
   689  				suite.TestLDAPSTSServiceAccountsWithGroups(c)
   690  				suite.TearDownSuite(c)
   691  			},
   692  		)
   693  	}
   694  }
   695  
   696  func (s *TestSuiteIAM) TestLDAPSTS(c *check) {
   697  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   698  	defer cancel()
   699  
   700  	bucket := getRandomBucketName()
   701  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
   702  	if err != nil {
   703  		c.Fatalf("bucket create error: %v", err)
   704  	}
   705  
   706  	// Create policy
   707  	policy := "mypolicy"
   708  	policyBytes := []byte(fmt.Sprintf(`{
   709   "Version": "2012-10-17",
   710   "Statement": [
   711    {
   712     "Effect": "Allow",
   713     "Action": [
   714      "s3:PutObject",
   715      "s3:GetObject",
   716      "s3:ListBucket"
   717     ],
   718     "Resource": [
   719      "arn:aws:s3:::%s/*"
   720     ]
   721    }
   722   ]
   723  }`, bucket))
   724  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
   725  	if err != nil {
   726  		c.Fatalf("policy add error: %v", err)
   727  	}
   728  
   729  	ldapID := cr.LDAPIdentity{
   730  		Client:       s.TestSuiteCommon.client,
   731  		STSEndpoint:  s.endPoint,
   732  		LDAPUsername: "dillon",
   733  		LDAPPassword: "dillon",
   734  	}
   735  
   736  	_, err = ldapID.Retrieve()
   737  	if err == nil {
   738  		c.Fatalf("Expected to fail to create STS cred with no associated policy!")
   739  	}
   740  
   741  	// Attempting to set a non-existent policy should fail.
   742  	userDN := "uid=dillon,ou=people,ou=swengg,dc=min,dc=io"
   743  	err = s.adm.SetPolicy(ctx, policy+"x", userDN, false)
   744  	if err == nil {
   745  		c.Fatalf("should not be able to set non-existent policy")
   746  	}
   747  
   748  	err = s.adm.SetPolicy(ctx, policy, userDN, false)
   749  	if err != nil {
   750  		c.Fatalf("Unable to set policy: %v", err)
   751  	}
   752  
   753  	value, err := ldapID.Retrieve()
   754  	if err != nil {
   755  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
   756  	}
   757  
   758  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   759  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   760  		Secure:    s.secure,
   761  		Transport: s.TestSuiteCommon.client.Transport,
   762  	})
   763  	if err != nil {
   764  		c.Fatalf("Error initializing client: %v", err)
   765  	}
   766  
   767  	// Validate that user listing does not return any entries
   768  	usersList, err := s.adm.ListUsers(ctx)
   769  	if err != nil {
   770  		c.Fatalf("list users should not fail: %v", err)
   771  	}
   772  	if len(usersList) != 1 {
   773  		c.Fatalf("expected user listing output: %v", usersList)
   774  	}
   775  	uinfo := usersList[userDN]
   776  	if uinfo.PolicyName != policy || uinfo.Status != madmin.AccountEnabled {
   777  		c.Fatalf("expected user listing content: %v", uinfo)
   778  	}
   779  
   780  	// Validate that the client from sts creds can access the bucket.
   781  	c.mustListObjects(ctx, minioClient, bucket)
   782  
   783  	// Validate that the client cannot remove any objects
   784  	err = minioClient.RemoveObject(ctx, bucket, "someobject", minio.RemoveObjectOptions{})
   785  	if err.Error() != "Access Denied." {
   786  		c.Fatalf("unexpected non-access-denied err: %v", err)
   787  	}
   788  
   789  	// Remove the policy assignment on the user DN:
   790  	err = s.adm.SetPolicy(ctx, "", userDN, false)
   791  	if err != nil {
   792  		c.Fatalf("Unable to remove policy setting: %v", err)
   793  	}
   794  
   795  	_, err = ldapID.Retrieve()
   796  	if err == nil {
   797  		c.Fatalf("Expected to fail to create a user with no associated policy!")
   798  	}
   799  
   800  	// Set policy via group and validate policy assignment.
   801  	groupDN := "cn=projectb,ou=groups,ou=swengg,dc=min,dc=io"
   802  	err = s.adm.SetPolicy(ctx, policy, groupDN, true)
   803  	if err != nil {
   804  		c.Fatalf("Unable to set group policy: %v", err)
   805  	}
   806  
   807  	value, err = ldapID.Retrieve()
   808  	if err != nil {
   809  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
   810  	}
   811  
   812  	minioClient, err = minio.New(s.endpoint, &minio.Options{
   813  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   814  		Secure:    s.secure,
   815  		Transport: s.TestSuiteCommon.client.Transport,
   816  	})
   817  	if err != nil {
   818  		c.Fatalf("Error initializing client: %v", err)
   819  	}
   820  
   821  	// Validate that the client from sts creds can access the bucket.
   822  	c.mustListObjects(ctx, minioClient, bucket)
   823  
   824  	// Validate that the client cannot remove any objects
   825  	err = minioClient.RemoveObject(ctx, bucket, "someobject", minio.RemoveObjectOptions{})
   826  	c.Assert(err.Error(), "Access Denied.")
   827  }
   828  
   829  func (s *TestSuiteIAM) TestLDAPUnicodeVariations(c *check) {
   830  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
   831  	defer cancel()
   832  
   833  	bucket := getRandomBucketName()
   834  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
   835  	if err != nil {
   836  		c.Fatalf("bucket create error: %v", err)
   837  	}
   838  
   839  	// Create policy
   840  	policy := "mypolicy"
   841  	policyBytes := []byte(fmt.Sprintf(`{
   842   "Version": "2012-10-17",
   843   "Statement": [
   844    {
   845     "Effect": "Allow",
   846     "Action": [
   847      "s3:PutObject",
   848      "s3:GetObject",
   849      "s3:ListBucket"
   850     ],
   851     "Resource": [
   852      "arn:aws:s3:::%s/*"
   853     ]
   854    }
   855   ]
   856  }`, bucket))
   857  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
   858  	if err != nil {
   859  		c.Fatalf("policy add error: %v", err)
   860  	}
   861  
   862  	ldapID := cr.LDAPIdentity{
   863  		Client:       s.TestSuiteCommon.client,
   864  		STSEndpoint:  s.endPoint,
   865  		LDAPUsername: "svc.algorithm",
   866  		LDAPPassword: "example",
   867  	}
   868  
   869  	_, err = ldapID.Retrieve()
   870  	if err == nil {
   871  		c.Fatalf("Expected to fail to create STS cred with no associated policy!")
   872  	}
   873  
   874  	mustNormalizeDN := func(dn string) string {
   875  		normalizedDN, err := ldap.NormalizeDN(dn)
   876  		if err != nil {
   877  			c.Fatalf("normalize err: %v", err)
   878  		}
   879  		return normalizedDN
   880  	}
   881  
   882  	actualUserDN := mustNormalizeDN("uid=svc.algorithm,OU=swengg,DC=min,DC=io")
   883  
   884  	// \uFE52 is the unicode dot SMALL FULL STOP used below:
   885  	userDNWithUnicodeDot := "uid=svc﹒algorithm,OU=swengg,DC=min,DC=io"
   886  
   887  	_, err = s.adm.AttachPolicyLDAP(ctx, madmin.PolicyAssociationReq{
   888  		Policies: []string{policy},
   889  		User:     userDNWithUnicodeDot,
   890  	})
   891  	if err != nil {
   892  		c.Fatalf("Unable to set policy: %v", err)
   893  	}
   894  
   895  	value, err := ldapID.Retrieve()
   896  	if err != nil {
   897  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
   898  	}
   899  
   900  	usersList, err := s.adm.ListUsers(ctx)
   901  	if err != nil {
   902  		c.Fatalf("list users should not fail: %v", err)
   903  	}
   904  	if len(usersList) != 1 {
   905  		c.Fatalf("expected user listing output: %#v", usersList)
   906  	}
   907  	uinfo := usersList[actualUserDN]
   908  	if uinfo.PolicyName != policy || uinfo.Status != madmin.AccountEnabled {
   909  		c.Fatalf("expected user listing content: %v", uinfo)
   910  	}
   911  
   912  	minioClient, err := minio.New(s.endpoint, &minio.Options{
   913  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   914  		Secure:    s.secure,
   915  		Transport: s.TestSuiteCommon.client.Transport,
   916  	})
   917  	if err != nil {
   918  		c.Fatalf("Error initializing client: %v", err)
   919  	}
   920  
   921  	// Validate that the client from sts creds can access the bucket.
   922  	c.mustListObjects(ctx, minioClient, bucket)
   923  
   924  	// Validate that the client cannot remove any objects
   925  	err = minioClient.RemoveObject(ctx, bucket, "someobject", minio.RemoveObjectOptions{})
   926  	if err.Error() != "Access Denied." {
   927  		c.Fatalf("unexpected non-access-denied err: %v", err)
   928  	}
   929  
   930  	// Remove the policy assignment on the user DN:
   931  	_, err = s.adm.DetachPolicyLDAP(ctx, madmin.PolicyAssociationReq{
   932  		Policies: []string{policy},
   933  		User:     userDNWithUnicodeDot,
   934  	})
   935  	if err != nil {
   936  		c.Fatalf("Unable to remove policy setting: %v", err)
   937  	}
   938  
   939  	_, err = ldapID.Retrieve()
   940  	if err == nil {
   941  		c.Fatalf("Expected to fail to create a user with no associated policy!")
   942  	}
   943  
   944  	// Set policy via group and validate policy assignment.
   945  	actualGroupDN := mustNormalizeDN("cn=project.c,ou=groups,ou=swengg,dc=min,dc=io")
   946  	groupDNWithUnicodeDot := "cn=project﹒c,ou=groups,ou=swengg,dc=min,dc=io"
   947  	_, err = s.adm.AttachPolicyLDAP(ctx, madmin.PolicyAssociationReq{
   948  		Policies: []string{policy},
   949  		Group:    groupDNWithUnicodeDot,
   950  	})
   951  	if err != nil {
   952  		c.Fatalf("Unable to attach group policy: %v", err)
   953  	}
   954  
   955  	value, err = ldapID.Retrieve()
   956  	if err != nil {
   957  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
   958  	}
   959  
   960  	policyResult, err := s.adm.GetLDAPPolicyEntities(ctx, madmin.PolicyEntitiesQuery{
   961  		Policy: []string{policy},
   962  	})
   963  	if err != nil {
   964  		c.Fatalf("GetLDAPPolicyEntities should not fail: %v", err)
   965  	}
   966  	{
   967  		// Check that the mapping we created exists.
   968  		idx := slices.IndexFunc(policyResult.PolicyMappings, func(e madmin.PolicyEntities) bool {
   969  			return e.Policy == policy && slices.Contains(e.Groups, actualGroupDN)
   970  		})
   971  		if !(idx >= 0) {
   972  			c.Fatalf("expected groupDN (%s) to be present in mapping list: %#v", actualGroupDN, policyResult)
   973  		}
   974  	}
   975  
   976  	minioClient, err = minio.New(s.endpoint, &minio.Options{
   977  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
   978  		Secure:    s.secure,
   979  		Transport: s.TestSuiteCommon.client.Transport,
   980  	})
   981  	if err != nil {
   982  		c.Fatalf("Error initializing client: %v", err)
   983  	}
   984  
   985  	// Validate that the client from sts creds can access the bucket.
   986  	c.mustListObjects(ctx, minioClient, bucket)
   987  
   988  	// Validate that the client cannot remove any objects
   989  	err = minioClient.RemoveObject(ctx, bucket, "someobject", minio.RemoveObjectOptions{})
   990  	c.Assert(err.Error(), "Access Denied.")
   991  }
   992  
   993  func (s *TestSuiteIAM) TestLDAPSTSServiceAccounts(c *check) {
   994  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   995  	defer cancel()
   996  
   997  	bucket := getRandomBucketName()
   998  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
   999  	if err != nil {
  1000  		c.Fatalf("bucket create error: %v", err)
  1001  	}
  1002  
  1003  	// Create policy
  1004  	policy := "mypolicy"
  1005  	policyBytes := []byte(fmt.Sprintf(`{
  1006   "Version": "2012-10-17",
  1007   "Statement": [
  1008    {
  1009     "Effect": "Allow",
  1010     "Action": [
  1011      "s3:PutObject",
  1012      "s3:GetObject",
  1013      "s3:ListBucket"
  1014     ],
  1015     "Resource": [
  1016      "arn:aws:s3:::%s/*"
  1017     ]
  1018    }
  1019   ]
  1020  }`, bucket))
  1021  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1022  	if err != nil {
  1023  		c.Fatalf("policy add error: %v", err)
  1024  	}
  1025  
  1026  	userDN := "uid=dillon,ou=people,ou=swengg,dc=min,dc=io"
  1027  	err = s.adm.SetPolicy(ctx, policy, userDN, false)
  1028  	if err != nil {
  1029  		c.Fatalf("Unable to set policy: %v", err)
  1030  	}
  1031  
  1032  	ldapID := cr.LDAPIdentity{
  1033  		Client:       s.TestSuiteCommon.client,
  1034  		STSEndpoint:  s.endPoint,
  1035  		LDAPUsername: "dillon",
  1036  		LDAPPassword: "dillon",
  1037  	}
  1038  
  1039  	value, err := ldapID.Retrieve()
  1040  	if err != nil {
  1041  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1042  	}
  1043  
  1044  	// Check that the LDAP sts cred is actually working.
  1045  	minioClient, err := minio.New(s.endpoint, &minio.Options{
  1046  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1047  		Secure:    s.secure,
  1048  		Transport: s.TestSuiteCommon.client.Transport,
  1049  	})
  1050  	if err != nil {
  1051  		c.Fatalf("Error initializing client: %v", err)
  1052  	}
  1053  
  1054  	// Validate that the client from sts creds can access the bucket.
  1055  	c.mustListObjects(ctx, minioClient, bucket)
  1056  
  1057  	// Create an madmin client with user creds
  1058  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
  1059  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1060  		Secure: s.secure,
  1061  	})
  1062  	if err != nil {
  1063  		c.Fatalf("Err creating user admin client: %v", err)
  1064  	}
  1065  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
  1066  
  1067  	// Create svc acc
  1068  	cr := c.mustCreateSvcAccount(ctx, value.AccessKeyID, userAdmClient)
  1069  
  1070  	// 1. Check that svc account appears in listing
  1071  	c.assertSvcAccAppearsInListing(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey)
  1072  
  1073  	// 2. Check that svc account info can be queried
  1074  	c.assertSvcAccInfoQueryable(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey, true)
  1075  
  1076  	// 3. Check S3 access
  1077  	c.assertSvcAccS3Access(ctx, s, cr, bucket)
  1078  
  1079  	// 5. Check that service account can be deleted.
  1080  	c.assertSvcAccDeletion(ctx, s, userAdmClient, value.AccessKeyID, bucket)
  1081  
  1082  	// 6. Check that service account cannot be created for some other user.
  1083  	c.mustNotCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient)
  1084  }
  1085  
  1086  func (s *TestSuiteIAM) TestLDAPSTSServiceAccountsWithUsername(c *check) {
  1087  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1088  	defer cancel()
  1089  
  1090  	bucket := "dillon"
  1091  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1092  	if err != nil {
  1093  		c.Fatalf("bucket create error: %v", err)
  1094  	}
  1095  
  1096  	// Create policy
  1097  	policy := "mypolicy-username"
  1098  	policyBytes := []byte(`{
  1099   "Version": "2012-10-17",
  1100   "Statement": [
  1101    {
  1102     "Effect": "Allow",
  1103     "Action": [
  1104      "s3:PutObject",
  1105      "s3:GetObject",
  1106      "s3:ListBucket"
  1107     ],
  1108     "Resource": [
  1109      "arn:aws:s3:::${ldap:username}/*"
  1110     ]
  1111    }
  1112   ]
  1113  }`)
  1114  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1115  	if err != nil {
  1116  		c.Fatalf("policy add error: %v", err)
  1117  	}
  1118  
  1119  	userDN := "uid=dillon,ou=people,ou=swengg,dc=min,dc=io"
  1120  	err = s.adm.SetPolicy(ctx, policy, userDN, false)
  1121  	if err != nil {
  1122  		c.Fatalf("Unable to set policy: %v", err)
  1123  	}
  1124  
  1125  	ldapID := cr.LDAPIdentity{
  1126  		Client:       s.TestSuiteCommon.client,
  1127  		STSEndpoint:  s.endPoint,
  1128  		LDAPUsername: "dillon",
  1129  		LDAPPassword: "dillon",
  1130  	}
  1131  
  1132  	value, err := ldapID.Retrieve()
  1133  	if err != nil {
  1134  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1135  	}
  1136  
  1137  	// Check that the LDAP sts cred is actually working.
  1138  	minioClient, err := minio.New(s.endpoint, &minio.Options{
  1139  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1140  		Secure:    s.secure,
  1141  		Transport: s.TestSuiteCommon.client.Transport,
  1142  	})
  1143  	if err != nil {
  1144  		c.Fatalf("Error initializing client: %v", err)
  1145  	}
  1146  
  1147  	// Validate that the client from sts creds can access the bucket.
  1148  	c.mustListObjects(ctx, minioClient, bucket)
  1149  
  1150  	// Create an madmin client with user creds
  1151  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
  1152  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1153  		Secure: s.secure,
  1154  	})
  1155  	if err != nil {
  1156  		c.Fatalf("Err creating user admin client: %v", err)
  1157  	}
  1158  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
  1159  
  1160  	// Create svc acc
  1161  	cr := c.mustCreateSvcAccount(ctx, value.AccessKeyID, userAdmClient)
  1162  
  1163  	svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "")
  1164  
  1165  	// 1. Check S3 access for service account ListObjects()
  1166  	c.mustListObjects(ctx, svcClient, bucket)
  1167  
  1168  	// 2. Check S3 access for upload
  1169  	c.mustUpload(ctx, svcClient, bucket)
  1170  
  1171  	// 3. Check S3 access for download
  1172  	c.mustDownload(ctx, svcClient, bucket)
  1173  }
  1174  
  1175  // In this test, the parent users gets their permissions from a group, rather
  1176  // than having a policy set directly on them.
  1177  func (s *TestSuiteIAM) TestLDAPSTSServiceAccountsWithGroups(c *check) {
  1178  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1179  	defer cancel()
  1180  
  1181  	bucket := getRandomBucketName()
  1182  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1183  	if err != nil {
  1184  		c.Fatalf("bucket create error: %v", err)
  1185  	}
  1186  
  1187  	// Create policy
  1188  	policy := "mypolicy"
  1189  	policyBytes := []byte(fmt.Sprintf(`{
  1190   "Version": "2012-10-17",
  1191   "Statement": [
  1192    {
  1193     "Effect": "Allow",
  1194     "Action": [
  1195      "s3:PutObject",
  1196      "s3:GetObject",
  1197      "s3:ListBucket"
  1198     ],
  1199     "Resource": [
  1200      "arn:aws:s3:::%s/*"
  1201     ]
  1202    }
  1203   ]
  1204  }`, bucket))
  1205  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1206  	if err != nil {
  1207  		c.Fatalf("policy add error: %v", err)
  1208  	}
  1209  
  1210  	groupDN := "cn=projecta,ou=groups,ou=swengg,dc=min,dc=io"
  1211  	err = s.adm.SetPolicy(ctx, policy, groupDN, true)
  1212  	if err != nil {
  1213  		c.Fatalf("Unable to set policy: %v", err)
  1214  	}
  1215  
  1216  	ldapID := cr.LDAPIdentity{
  1217  		Client:       s.TestSuiteCommon.client,
  1218  		STSEndpoint:  s.endPoint,
  1219  		LDAPUsername: "dillon",
  1220  		LDAPPassword: "dillon",
  1221  	}
  1222  
  1223  	value, err := ldapID.Retrieve()
  1224  	if err != nil {
  1225  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1226  	}
  1227  
  1228  	// Check that the LDAP sts cred is actually working.
  1229  	minioClient, err := minio.New(s.endpoint, &minio.Options{
  1230  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1231  		Secure:    s.secure,
  1232  		Transport: s.TestSuiteCommon.client.Transport,
  1233  	})
  1234  	if err != nil {
  1235  		c.Fatalf("Error initializing client: %v", err)
  1236  	}
  1237  
  1238  	// Validate that the client from sts creds can access the bucket.
  1239  	c.mustListObjects(ctx, minioClient, bucket)
  1240  
  1241  	// Create an madmin client with user creds
  1242  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
  1243  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1244  		Secure: s.secure,
  1245  	})
  1246  	if err != nil {
  1247  		c.Fatalf("Err creating user admin client: %v", err)
  1248  	}
  1249  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
  1250  
  1251  	// Create svc acc
  1252  	cr := c.mustCreateSvcAccount(ctx, value.AccessKeyID, userAdmClient)
  1253  
  1254  	// 1. Check that svc account appears in listing
  1255  	c.assertSvcAccAppearsInListing(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey)
  1256  
  1257  	// 2. Check that svc account info can be queried
  1258  	c.assertSvcAccInfoQueryable(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey, true)
  1259  
  1260  	// 3. Check S3 access
  1261  	c.assertSvcAccS3Access(ctx, s, cr, bucket)
  1262  
  1263  	// 5. Check that service account can be deleted.
  1264  	c.assertSvcAccDeletion(ctx, s, userAdmClient, value.AccessKeyID, bucket)
  1265  
  1266  	// 6. Check that service account cannot be created for some other user.
  1267  	c.mustNotCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient)
  1268  }
  1269  
  1270  func (s *TestSuiteIAM) TestOpenIDSTS(c *check) {
  1271  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1272  	defer cancel()
  1273  
  1274  	bucket := getRandomBucketName()
  1275  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1276  	if err != nil {
  1277  		c.Fatalf("bucket create error: %v", err)
  1278  	}
  1279  
  1280  	// Generate web identity STS token by interacting with OpenID IDP.
  1281  	token, err := MockOpenIDTestUserInteraction(ctx, testAppParams, "dillon@example.io", "dillon")
  1282  	if err != nil {
  1283  		c.Fatalf("mock user err: %v", err)
  1284  	}
  1285  	// fmt.Printf("TOKEN: %s\n", token)
  1286  
  1287  	webID := cr.STSWebIdentity{
  1288  		Client:      s.TestSuiteCommon.client,
  1289  		STSEndpoint: s.endPoint,
  1290  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  1291  			return &cr.WebIdentityToken{
  1292  				Token: token,
  1293  			}, nil
  1294  		},
  1295  	}
  1296  
  1297  	// Create policy - with name as one of the groups in OpenID the user is
  1298  	// a member of.
  1299  	policy := "projecta"
  1300  	policyBytes := []byte(fmt.Sprintf(`{
  1301   "Version": "2012-10-17",
  1302   "Statement": [
  1303    {
  1304     "Effect": "Allow",
  1305     "Action": [
  1306      "s3:PutObject",
  1307      "s3:GetObject",
  1308      "s3:ListBucket"
  1309     ],
  1310     "Resource": [
  1311      "arn:aws:s3:::%s/*"
  1312     ]
  1313    }
  1314   ]
  1315  }`, bucket))
  1316  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1317  	if err != nil {
  1318  		c.Fatalf("policy add error: %v", err)
  1319  	}
  1320  
  1321  	value, err := webID.Retrieve()
  1322  	if err != nil {
  1323  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1324  	}
  1325  
  1326  	minioClient, err := minio.New(s.endpoint, &minio.Options{
  1327  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1328  		Secure:    s.secure,
  1329  		Transport: s.TestSuiteCommon.client.Transport,
  1330  	})
  1331  	if err != nil {
  1332  		c.Fatalf("Error initializing client: %v", err)
  1333  	}
  1334  
  1335  	// Validate that the client from sts creds can access the bucket.
  1336  	c.mustListObjects(ctx, minioClient, bucket)
  1337  
  1338  	// Validate that the client cannot remove any objects
  1339  	err = minioClient.RemoveObject(ctx, bucket, "someobject", minio.RemoveObjectOptions{})
  1340  	if err.Error() != "Access Denied." {
  1341  		c.Fatalf("unexpected non-access-denied err: %v", err)
  1342  	}
  1343  }
  1344  
  1345  func (s *TestSuiteIAM) TestOpenIDSTSDurationSeconds(c *check) {
  1346  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1347  	defer cancel()
  1348  
  1349  	bucket := getRandomBucketName()
  1350  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1351  	if err != nil {
  1352  		c.Fatalf("bucket create error: %v", err)
  1353  	}
  1354  
  1355  	// Generate web identity STS token by interacting with OpenID IDP.
  1356  	token, err := MockOpenIDTestUserInteraction(ctx, testAppParams, "dillon@example.io", "dillon")
  1357  	if err != nil {
  1358  		c.Fatalf("mock user err: %v", err)
  1359  	}
  1360  	// fmt.Printf("TOKEN: %s\n", token)
  1361  
  1362  	webID := cr.STSWebIdentity{
  1363  		Client:      s.TestSuiteCommon.client,
  1364  		STSEndpoint: s.endPoint,
  1365  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  1366  			return &cr.WebIdentityToken{
  1367  				Token:  token,
  1368  				Expiry: 900,
  1369  			}, nil
  1370  		},
  1371  	}
  1372  
  1373  	// Create policy - with name as one of the groups in OpenID the user is
  1374  	// a member of.
  1375  	policy := "projecta"
  1376  	policyTmpl := `{
  1377   "Version": "2012-10-17",
  1378   "Statement": [
  1379    {
  1380      "Effect": "Deny",
  1381      "Action": ["sts:AssumeRoleWithWebIdentity"],
  1382      "Condition": {"NumericGreaterThan": {"sts:DurationSeconds": "%d"}}
  1383    },
  1384    {
  1385     "Effect": "Allow",
  1386     "Action": [
  1387      "s3:PutObject",
  1388      "s3:GetObject",
  1389      "s3:ListBucket"
  1390     ],
  1391     "Resource": [
  1392      "arn:aws:s3:::%s/*"
  1393     ]
  1394    }
  1395   ]
  1396  }`
  1397  
  1398  	for i, testCase := range []struct {
  1399  		durSecs     int
  1400  		expectedErr bool
  1401  	}{
  1402  		{60, true},
  1403  		{1800, false},
  1404  	} {
  1405  		policyBytes := []byte(fmt.Sprintf(policyTmpl, testCase.durSecs, bucket))
  1406  		err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1407  		if err != nil {
  1408  			c.Fatalf("Test %d: policy add error: %v", i+1, err)
  1409  		}
  1410  
  1411  		value, err := webID.Retrieve()
  1412  		if err != nil && !testCase.expectedErr {
  1413  			c.Fatalf("Test %d: Expected to generate STS creds, got err: %#v", i+1, err)
  1414  		}
  1415  		if err == nil && testCase.expectedErr {
  1416  			c.Fatalf("Test %d: An error is unexpected to generate STS creds, got err: %#v", i+1, err)
  1417  		}
  1418  
  1419  		if err != nil && testCase.expectedErr {
  1420  			continue
  1421  		}
  1422  
  1423  		minioClient, err := minio.New(s.endpoint, &minio.Options{
  1424  			Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1425  			Secure:    s.secure,
  1426  			Transport: s.TestSuiteCommon.client.Transport,
  1427  		})
  1428  		if err != nil {
  1429  			c.Fatalf("Test %d: Error initializing client: %v", i+1, err)
  1430  		}
  1431  
  1432  		c.mustListObjects(ctx, minioClient, bucket)
  1433  	}
  1434  }
  1435  
  1436  func (s *TestSuiteIAM) TestOpenIDSTSAddUser(c *check) {
  1437  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1438  	defer cancel()
  1439  
  1440  	bucket := getRandomBucketName()
  1441  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1442  	if err != nil {
  1443  		c.Fatalf("bucket create error: %v", err)
  1444  	}
  1445  
  1446  	// Generate web identity STS token by interacting with OpenID IDP.
  1447  	token, err := MockOpenIDTestUserInteraction(ctx, testAppParams, "dillon@example.io", "dillon")
  1448  	if err != nil {
  1449  		c.Fatalf("mock user err: %v", err)
  1450  	}
  1451  
  1452  	webID := cr.STSWebIdentity{
  1453  		Client:      s.TestSuiteCommon.client,
  1454  		STSEndpoint: s.endPoint,
  1455  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  1456  			return &cr.WebIdentityToken{
  1457  				Token: token,
  1458  			}, nil
  1459  		},
  1460  	}
  1461  
  1462  	// Create policy - with name as one of the groups in OpenID the user is
  1463  	// a member of.
  1464  	policy := "projecta"
  1465  	policyBytes := []byte(fmt.Sprintf(`{
  1466   "Version": "2012-10-17",
  1467   "Statement": [
  1468    {
  1469     "Effect": "Allow",
  1470     "Action": [
  1471      "s3:PutObject",
  1472      "s3:GetObject",
  1473      "s3:ListBucket"
  1474     ],
  1475     "Resource": [
  1476      "arn:aws:s3:::%s/*"
  1477     ]
  1478    }
  1479   ]
  1480  }`, bucket))
  1481  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1482  	if err != nil {
  1483  		c.Fatalf("policy add error: %v", err)
  1484  	}
  1485  
  1486  	value, err := webID.Retrieve()
  1487  	if err != nil {
  1488  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1489  	}
  1490  
  1491  	// Create an madmin client with user creds
  1492  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
  1493  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1494  		Secure: s.secure,
  1495  	})
  1496  	if err != nil {
  1497  		c.Fatalf("Err creating user admin client: %v", err)
  1498  	}
  1499  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
  1500  
  1501  	c.mustNotCreateIAMUser(ctx, userAdmClient)
  1502  
  1503  	// Create admin user policy.
  1504  	policyBytes = []byte(`{
  1505   "Version": "2012-10-17",
  1506   "Statement": [
  1507    {
  1508     "Effect": "Allow",
  1509     "Action": [
  1510      "admin:*"
  1511     ]
  1512    }
  1513   ]
  1514  }`)
  1515  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1516  	if err != nil {
  1517  		c.Fatalf("policy add error: %v", err)
  1518  	}
  1519  
  1520  	cr := c.mustCreateIAMUser(ctx, userAdmClient)
  1521  
  1522  	userInfo := c.mustGetIAMUserInfo(ctx, userAdmClient, cr.AccessKey)
  1523  	c.Assert(userInfo.Status, madmin.AccountEnabled)
  1524  }
  1525  
  1526  func (s *TestSuiteIAM) TestOpenIDServiceAcc(c *check) {
  1527  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1528  	defer cancel()
  1529  
  1530  	bucket := getRandomBucketName()
  1531  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1532  	if err != nil {
  1533  		c.Fatalf("bucket create error: %v", err)
  1534  	}
  1535  
  1536  	// Generate web identity STS token by interacting with OpenID IDP.
  1537  	token, err := MockOpenIDTestUserInteraction(ctx, testAppParams, "dillon@example.io", "dillon")
  1538  	if err != nil {
  1539  		c.Fatalf("mock user err: %v", err)
  1540  	}
  1541  
  1542  	webID := cr.STSWebIdentity{
  1543  		Client:      s.TestSuiteCommon.client,
  1544  		STSEndpoint: s.endPoint,
  1545  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  1546  			return &cr.WebIdentityToken{
  1547  				Token: token,
  1548  			}, nil
  1549  		},
  1550  	}
  1551  
  1552  	// Create policy - with name as one of the groups in OpenID the user is
  1553  	// a member of.
  1554  	policy := "projecta"
  1555  	policyBytes := []byte(fmt.Sprintf(`{
  1556   "Version": "2012-10-17",
  1557   "Statement": [
  1558    {
  1559     "Effect": "Allow",
  1560     "Action": [
  1561      "s3:PutObject",
  1562      "s3:GetObject",
  1563      "s3:ListBucket"
  1564     ],
  1565     "Resource": [
  1566      "arn:aws:s3:::%s/*"
  1567     ]
  1568    }
  1569   ]
  1570  }`, bucket))
  1571  	err = s.adm.AddCannedPolicy(ctx, policy, policyBytes)
  1572  	if err != nil {
  1573  		c.Fatalf("policy add error: %v", err)
  1574  	}
  1575  
  1576  	value, err := webID.Retrieve()
  1577  	if err != nil {
  1578  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1579  	}
  1580  
  1581  	// Create an madmin client with user creds
  1582  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
  1583  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1584  		Secure: s.secure,
  1585  	})
  1586  	if err != nil {
  1587  		c.Fatalf("Err creating user admin client: %v", err)
  1588  	}
  1589  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
  1590  
  1591  	// Create svc acc
  1592  	cr := c.mustCreateSvcAccount(ctx, value.AccessKeyID, userAdmClient)
  1593  
  1594  	// 1. Check that svc account appears in listing
  1595  	c.assertSvcAccAppearsInListing(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey)
  1596  
  1597  	// 2. Check that svc account info can be queried
  1598  	c.assertSvcAccInfoQueryable(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey, true)
  1599  
  1600  	// 3. Check S3 access
  1601  	c.assertSvcAccS3Access(ctx, s, cr, bucket)
  1602  
  1603  	// 5. Check that service account can be deleted.
  1604  	c.assertSvcAccDeletion(ctx, s, userAdmClient, value.AccessKeyID, bucket)
  1605  
  1606  	// 6. Check that service account cannot be created for some other user.
  1607  	c.mustNotCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient)
  1608  }
  1609  
  1610  var testAppParams = OpenIDClientAppParams{
  1611  	ClientID:     "minio-client-app",
  1612  	ClientSecret: "minio-client-app-secret",
  1613  	ProviderURL:  "http://127.0.0.1:5556/dex",
  1614  	RedirectURL:  "http://127.0.0.1:10000/oauth_callback",
  1615  }
  1616  
  1617  const (
  1618  	EnvTestOpenIDServer  = "_MINIO_OPENID_TEST_SERVER"
  1619  	EnvTestOpenIDServer2 = "_MINIO_OPENID_TEST_SERVER_2"
  1620  )
  1621  
  1622  // SetUpOpenIDs - sets up one or more OpenID test servers using the test OpenID
  1623  // container and canned data from https://github.com/minio/minio-ldap-testing
  1624  //
  1625  // Each set of client app params corresponds to a separate openid server, and
  1626  // the i-th server in this will be applied the i-th policy in `rolePolicies`. If
  1627  // a rolePolicies entry is an empty string, that server will be configured as
  1628  // policy-claim based openid server. NOTE that a valid configuration can have a
  1629  // policy claim based provider only if it is the only OpenID provider.
  1630  func (s *TestSuiteIAM) SetUpOpenIDs(c *check, testApps []OpenIDClientAppParams, rolePolicies []string) error {
  1631  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
  1632  	defer cancel()
  1633  
  1634  	for i, testApp := range testApps {
  1635  		configCmds := []string{
  1636  			fmt.Sprintf("identity_openid:%d", i),
  1637  			fmt.Sprintf("config_url=%s/.well-known/openid-configuration", testApp.ProviderURL),
  1638  			fmt.Sprintf("client_id=%s", testApp.ClientID),
  1639  			fmt.Sprintf("client_secret=%s", testApp.ClientSecret),
  1640  			"scopes=openid,groups",
  1641  			fmt.Sprintf("redirect_uri=%s", testApp.RedirectURL),
  1642  		}
  1643  		if rolePolicies[i] != "" {
  1644  			configCmds = append(configCmds, fmt.Sprintf("role_policy=%s", rolePolicies[i]))
  1645  		} else {
  1646  			configCmds = append(configCmds, "claim_name=groups")
  1647  		}
  1648  		_, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " "))
  1649  		if err != nil {
  1650  			return fmt.Errorf("unable to setup OpenID for tests: %v", err)
  1651  		}
  1652  	}
  1653  
  1654  	s.RestartIAMSuite(c)
  1655  	return nil
  1656  }
  1657  
  1658  // SetUpOpenID - expects to setup an OpenID test server using the test OpenID
  1659  // container and canned data from https://github.com/minio/minio-ldap-testing
  1660  func (s *TestSuiteIAM) SetUpOpenID(c *check, serverAddr string, rolePolicy string) {
  1661  	ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
  1662  	defer cancel()
  1663  
  1664  	configCmds := []string{
  1665  		"identity_openid",
  1666  		fmt.Sprintf("config_url=%s/.well-known/openid-configuration", serverAddr),
  1667  		"client_id=minio-client-app",
  1668  		"client_secret=minio-client-app-secret",
  1669  		"scopes=openid,groups",
  1670  		"redirect_uri=http://127.0.0.1:10000/oauth_callback",
  1671  	}
  1672  	if rolePolicy != "" {
  1673  		configCmds = append(configCmds, fmt.Sprintf("role_policy=%s", rolePolicy))
  1674  	} else {
  1675  		configCmds = append(configCmds, "claim_name=groups")
  1676  	}
  1677  	_, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " "))
  1678  	if err != nil {
  1679  		c.Fatalf("unable to setup OpenID for tests: %v", err)
  1680  	}
  1681  
  1682  	s.RestartIAMSuite(c)
  1683  }
  1684  
  1685  func TestIAMWithOpenIDServerSuite(t *testing.T) {
  1686  	for i, testCase := range iamTestSuites {
  1687  		t.Run(
  1688  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
  1689  			func(t *testing.T) {
  1690  				c := &check{t, testCase.serverType}
  1691  				suite := testCase
  1692  
  1693  				openIDServer := os.Getenv(EnvTestOpenIDServer)
  1694  				if openIDServer == "" {
  1695  					c.Skip("Skipping OpenID test as no OpenID server is provided.")
  1696  				}
  1697  
  1698  				suite.SetUpSuite(c)
  1699  				suite.SetUpOpenID(c, openIDServer, "")
  1700  				suite.TestOpenIDSTS(c)
  1701  				suite.TestOpenIDSTSDurationSeconds(c)
  1702  				suite.TestOpenIDServiceAcc(c)
  1703  				suite.TestOpenIDSTSAddUser(c)
  1704  				suite.TearDownSuite(c)
  1705  			},
  1706  		)
  1707  	}
  1708  }
  1709  
  1710  func TestIAMWithOpenIDWithRolePolicyServerSuite(t *testing.T) {
  1711  	for i, testCase := range iamTestSuites {
  1712  		t.Run(
  1713  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
  1714  			func(t *testing.T) {
  1715  				c := &check{t, testCase.serverType}
  1716  				suite := testCase
  1717  
  1718  				openIDServer := os.Getenv(EnvTestOpenIDServer)
  1719  				if openIDServer == "" {
  1720  					c.Skip("Skipping OpenID test as no OpenID server is provided.")
  1721  				}
  1722  
  1723  				suite.SetUpSuite(c)
  1724  				suite.SetUpOpenID(c, openIDServer, "readwrite")
  1725  				suite.TestOpenIDSTSWithRolePolicy(c, testRoleARNs[0], testRoleMap[testRoleARNs[0]])
  1726  				suite.TestOpenIDServiceAccWithRolePolicy(c)
  1727  				suite.TearDownSuite(c)
  1728  			},
  1729  		)
  1730  	}
  1731  }
  1732  
  1733  func TestIAMWithOpenIDWithRolePolicyWithPolicyVariablesServerSuite(t *testing.T) {
  1734  	for i, testCase := range iamTestSuites {
  1735  		t.Run(
  1736  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
  1737  			func(t *testing.T) {
  1738  				c := &check{t, testCase.serverType}
  1739  				suite := testCase
  1740  
  1741  				openIDServer := os.Getenv(EnvTestOpenIDServer)
  1742  				if openIDServer == "" {
  1743  					c.Skip("Skipping OpenID test as no OpenID server is provided.")
  1744  				}
  1745  
  1746  				suite.SetUpSuite(c)
  1747  				suite.SetUpOpenID(c, openIDServer, "projecta,projectb,projectaorb")
  1748  				suite.TestOpenIDSTSWithRolePolicyWithPolVar(c, testRoleARNs[0], testRoleMap[testRoleARNs[0]])
  1749  				suite.TearDownSuite(c)
  1750  			},
  1751  		)
  1752  	}
  1753  }
  1754  
  1755  const (
  1756  	testRoleARN  = "arn:minio:iam:::role/nOybJqMNzNmroqEKq5D0EUsRZw0"
  1757  	testRoleARN2 = "arn:minio:iam:::role/domXb70kze7Ugc1SaxaeFchhLP4"
  1758  )
  1759  
  1760  var (
  1761  	testRoleARNs = []string{testRoleARN, testRoleARN2}
  1762  
  1763  	// Load test client app and test role mapping depending on test
  1764  	// environment.
  1765  	testClientApps, testRoleMap = func() ([]OpenIDClientAppParams, map[string]OpenIDClientAppParams) {
  1766  		var apps []OpenIDClientAppParams
  1767  		m := map[string]OpenIDClientAppParams{}
  1768  
  1769  		openIDServer := os.Getenv(EnvTestOpenIDServer)
  1770  		if openIDServer != "" {
  1771  			apps = append(apps, OpenIDClientAppParams{
  1772  				ClientID:     "minio-client-app",
  1773  				ClientSecret: "minio-client-app-secret",
  1774  				ProviderURL:  openIDServer,
  1775  				RedirectURL:  "http://127.0.0.1:10000/oauth_callback",
  1776  			})
  1777  			m[testRoleARNs[len(apps)-1]] = apps[len(apps)-1]
  1778  		}
  1779  
  1780  		openIDServer2 := os.Getenv(EnvTestOpenIDServer2)
  1781  		if openIDServer2 != "" {
  1782  			apps = append(apps, OpenIDClientAppParams{
  1783  				ClientID:     "minio-client-app-2",
  1784  				ClientSecret: "minio-client-app-secret-2",
  1785  				ProviderURL:  openIDServer2,
  1786  				RedirectURL:  "http://127.0.0.1:10000/oauth_callback",
  1787  			})
  1788  			m[testRoleARNs[len(apps)-1]] = apps[len(apps)-1]
  1789  		}
  1790  
  1791  		return apps, m
  1792  	}()
  1793  )
  1794  
  1795  func (s *TestSuiteIAM) TestOpenIDSTSWithRolePolicy(c *check, roleARN string, clientApp OpenIDClientAppParams) {
  1796  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1797  	defer cancel()
  1798  
  1799  	bucket := getRandomBucketName()
  1800  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1801  	if err != nil {
  1802  		c.Fatalf("bucket create error: %v", err)
  1803  	}
  1804  
  1805  	// Generate web identity JWT by interacting with OpenID IDP.
  1806  	token, err := MockOpenIDTestUserInteraction(ctx, clientApp, "dillon@example.io", "dillon")
  1807  	if err != nil {
  1808  		c.Fatalf("mock user err: %v", err)
  1809  	}
  1810  
  1811  	// Generate STS credential.
  1812  	webID := cr.STSWebIdentity{
  1813  		Client:      s.TestSuiteCommon.client,
  1814  		STSEndpoint: s.endPoint,
  1815  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  1816  			return &cr.WebIdentityToken{
  1817  				Token: token,
  1818  			}, nil
  1819  		},
  1820  		RoleARN: roleARN,
  1821  	}
  1822  
  1823  	value, err := webID.Retrieve()
  1824  	if err != nil {
  1825  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1826  	}
  1827  	// fmt.Printf("value: %#v\n", value)
  1828  
  1829  	minioClient, err := minio.New(s.endpoint, &minio.Options{
  1830  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1831  		Secure:    s.secure,
  1832  		Transport: s.TestSuiteCommon.client.Transport,
  1833  	})
  1834  	if err != nil {
  1835  		c.Fatalf("Error initializing client: %v", err)
  1836  	}
  1837  
  1838  	// Validate that the client from sts creds can access the bucket.
  1839  	c.mustListObjects(ctx, minioClient, bucket)
  1840  }
  1841  
  1842  func (s *TestSuiteIAM) TestOpenIDServiceAccWithRolePolicy(c *check) {
  1843  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  1844  	defer cancel()
  1845  
  1846  	bucket := getRandomBucketName()
  1847  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  1848  	if err != nil {
  1849  		c.Fatalf("bucket create error: %v", err)
  1850  	}
  1851  
  1852  	// Generate web identity STS token by interacting with OpenID IDP.
  1853  	token, err := MockOpenIDTestUserInteraction(ctx, testAppParams, "dillon@example.io", "dillon")
  1854  	if err != nil {
  1855  		c.Fatalf("mock user err: %v", err)
  1856  	}
  1857  
  1858  	webID := cr.STSWebIdentity{
  1859  		Client:      s.TestSuiteCommon.client,
  1860  		STSEndpoint: s.endPoint,
  1861  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  1862  			return &cr.WebIdentityToken{
  1863  				Token: token,
  1864  			}, nil
  1865  		},
  1866  		RoleARN: testRoleARN,
  1867  	}
  1868  
  1869  	value, err := webID.Retrieve()
  1870  	if err != nil {
  1871  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  1872  	}
  1873  
  1874  	// Create an madmin client with user creds
  1875  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
  1876  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  1877  		Secure: s.secure,
  1878  	})
  1879  	if err != nil {
  1880  		c.Fatalf("Err creating user admin client: %v", err)
  1881  	}
  1882  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
  1883  
  1884  	// Create svc acc
  1885  	cr := c.mustCreateSvcAccount(ctx, value.AccessKeyID, userAdmClient)
  1886  
  1887  	// 1. Check that svc account appears in listing
  1888  	c.assertSvcAccAppearsInListing(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey)
  1889  
  1890  	// 2. Check that svc account info can be queried
  1891  	c.assertSvcAccInfoQueryable(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey, true)
  1892  
  1893  	// 3. Check S3 access
  1894  	c.assertSvcAccS3Access(ctx, s, cr, bucket)
  1895  
  1896  	// 5. Check that service account can be deleted.
  1897  	c.assertSvcAccDeletion(ctx, s, userAdmClient, value.AccessKeyID, bucket)
  1898  }
  1899  
  1900  // Constants for Policy Variables test.
  1901  var (
  1902  	policyProjectA = `{
  1903      "Version": "2012-10-17",
  1904      "Statement": [
  1905          {
  1906              "Effect": "Allow",
  1907              "Action": [
  1908                          "s3:GetBucketLocation",
  1909                          "s3:ListAllMyBuckets"
  1910                        ],
  1911              "Resource": "arn:aws:s3:::*"
  1912          },
  1913          {
  1914              "Effect": "Allow",
  1915              "Action": "s3:*",
  1916              "Resource": [
  1917                  "arn:aws:s3:::projecta",
  1918                  "arn:aws:s3:::projecta/*"
  1919              ],
  1920              "Condition": {
  1921                  "ForAnyValue:StringEquals": {
  1922                      "jwt:groups": [
  1923                          "projecta"
  1924                      ]
  1925                  }
  1926              }
  1927          }
  1928      ]
  1929  }
  1930  `
  1931  	policyProjectB = `{
  1932      "Version": "2012-10-17",
  1933      "Statement": [
  1934          {
  1935              "Effect": "Allow",
  1936              "Action": [
  1937                          "s3:GetBucketLocation",
  1938                          "s3:ListAllMyBuckets"
  1939                        ],
  1940              "Resource": "arn:aws:s3:::*"
  1941          },
  1942          {
  1943              "Effect": "Allow",
  1944              "Action": "s3:*",
  1945              "Resource": [
  1946                  "arn:aws:s3:::projectb",
  1947                  "arn:aws:s3:::projectb/*"
  1948              ],
  1949              "Condition": {
  1950                  "ForAnyValue:StringEquals": {
  1951                      "jwt:groups": [
  1952                          "projectb"
  1953                      ]
  1954                  }
  1955              }
  1956          }
  1957      ]
  1958  }
  1959  `
  1960  	policyProjectAorB = `{
  1961      "Version": "2012-10-17",
  1962      "Statement": [
  1963          {
  1964              "Effect": "Allow",
  1965              "Action": [
  1966                          "s3:GetBucketLocation",
  1967                          "s3:ListAllMyBuckets"
  1968                        ],
  1969              "Resource": "arn:aws:s3:::*"
  1970          },
  1971          {
  1972              "Effect": "Allow",
  1973              "Action": "s3:*",
  1974              "Resource": [
  1975                  "arn:aws:s3:::projectaorb",
  1976                  "arn:aws:s3:::projectaorb/*"
  1977              ],
  1978              "Condition": {
  1979                  "ForAnyValue:StringEquals": {
  1980                      "jwt:groups": [
  1981                          "projecta",
  1982                          "projectb"
  1983                      ]
  1984                  }
  1985              }
  1986          }
  1987      ]
  1988  }`
  1989  
  1990  	policyProjectsMap = map[string]string{
  1991  		// grants access to bucket `projecta` if user is in group `projecta`
  1992  		"projecta": policyProjectA,
  1993  
  1994  		// grants access to bucket `projectb` if user is in group `projectb`
  1995  		"projectb": policyProjectB,
  1996  
  1997  		// grants access to bucket `projectaorb` if user is in either group
  1998  		// `projecta` or `projectb`
  1999  		"projectaorb": policyProjectAorB,
  2000  	}
  2001  )
  2002  
  2003  func (s *TestSuiteIAM) TestOpenIDSTSWithRolePolicyWithPolVar(c *check, roleARN string, clientApp OpenIDClientAppParams) {
  2004  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  2005  	defer cancel()
  2006  
  2007  	// Create project buckets
  2008  	buckets := []string{"projecta", "projectb", "projectaorb", "other"}
  2009  	for _, bucket := range buckets {
  2010  		err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  2011  		if err != nil {
  2012  			c.Fatalf("bucket create error: %v", err)
  2013  		}
  2014  	}
  2015  
  2016  	// Create policies
  2017  	for polName, polContent := range policyProjectsMap {
  2018  		err := s.adm.AddCannedPolicy(ctx, polName, []byte(polContent))
  2019  		if err != nil {
  2020  			c.Fatalf("policy add error: %v", err)
  2021  		}
  2022  	}
  2023  
  2024  	makeSTSClient := func(user, password string) *minio.Client {
  2025  		// Generate web identity JWT by interacting with OpenID IDP.
  2026  		token, err := MockOpenIDTestUserInteraction(ctx, clientApp, user, password)
  2027  		if err != nil {
  2028  			c.Fatalf("mock user err: %v", err)
  2029  		}
  2030  
  2031  		// Generate STS credential.
  2032  		webID := cr.STSWebIdentity{
  2033  			Client:      s.TestSuiteCommon.client,
  2034  			STSEndpoint: s.endPoint,
  2035  			GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  2036  				return &cr.WebIdentityToken{
  2037  					Token: token,
  2038  				}, nil
  2039  			},
  2040  			RoleARN: roleARN,
  2041  		}
  2042  
  2043  		value, err := webID.Retrieve()
  2044  		if err != nil {
  2045  			c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  2046  		}
  2047  		// fmt.Printf("value: %#v\n", value)
  2048  
  2049  		minioClient, err := minio.New(s.endpoint, &minio.Options{
  2050  			Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  2051  			Secure:    s.secure,
  2052  			Transport: s.TestSuiteCommon.client.Transport,
  2053  		})
  2054  		if err != nil {
  2055  			c.Fatalf("Error initializing client: %v", err)
  2056  		}
  2057  
  2058  		return minioClient
  2059  	}
  2060  
  2061  	// user dillon's groups attribute is ["projecta", "projectb"]
  2062  	dillonClient := makeSTSClient("dillon@example.io", "dillon")
  2063  	// Validate client's permissions
  2064  	c.mustListBuckets(ctx, dillonClient)
  2065  	c.mustListObjects(ctx, dillonClient, "projecta")
  2066  	c.mustListObjects(ctx, dillonClient, "projectb")
  2067  	c.mustListObjects(ctx, dillonClient, "projectaorb")
  2068  	c.mustNotListObjects(ctx, dillonClient, "other")
  2069  
  2070  	// this user's groups attribute is ["projectb"]
  2071  	lisaClient := makeSTSClient("ejones@example.io", "liza")
  2072  	// Validate client's permissions
  2073  	c.mustListBuckets(ctx, lisaClient)
  2074  	c.mustNotListObjects(ctx, lisaClient, "projecta")
  2075  	c.mustListObjects(ctx, lisaClient, "projectb")
  2076  	c.mustListObjects(ctx, lisaClient, "projectaorb")
  2077  	c.mustNotListObjects(ctx, lisaClient, "other")
  2078  }
  2079  
  2080  func TestIAMWithOpenIDMultipleConfigsValidation1(t *testing.T) {
  2081  	openIDServer := os.Getenv(EnvTestOpenIDServer)
  2082  	openIDServer2 := os.Getenv(EnvTestOpenIDServer2)
  2083  	if openIDServer == "" || openIDServer2 == "" {
  2084  		t.Skip("Skipping OpenID test as enough OpenID servers are not provided.")
  2085  	}
  2086  	testApps := testClientApps
  2087  
  2088  	rolePolicies := []string{
  2089  		"", // Treated as claim-based provider as no role policy is given.
  2090  		"readwrite",
  2091  	}
  2092  
  2093  	for i, testCase := range iamTestSuites {
  2094  		t.Run(
  2095  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
  2096  			func(t *testing.T) {
  2097  				c := &check{t, testCase.serverType}
  2098  				suite := testCase
  2099  
  2100  				suite.SetUpSuite(c)
  2101  				defer suite.TearDownSuite(c)
  2102  
  2103  				err := suite.SetUpOpenIDs(c, testApps, rolePolicies)
  2104  				if err != nil {
  2105  					c.Fatalf("config with 1 claim based and 1 role based provider should pass but got: %v", err)
  2106  				}
  2107  			},
  2108  		)
  2109  	}
  2110  }
  2111  
  2112  func TestIAMWithOpenIDMultipleConfigsValidation2(t *testing.T) {
  2113  	openIDServer := os.Getenv(EnvTestOpenIDServer)
  2114  	openIDServer2 := os.Getenv(EnvTestOpenIDServer2)
  2115  	if openIDServer == "" || openIDServer2 == "" {
  2116  		t.Skip("Skipping OpenID test as enough OpenID servers are not provided.")
  2117  	}
  2118  	testApps := testClientApps
  2119  
  2120  	rolePolicies := []string{
  2121  		"", // Treated as claim-based provider as no role policy is given.
  2122  		"", // Treated as claim-based provider as no role policy is given.
  2123  	}
  2124  
  2125  	for i, testCase := range iamTestSuites {
  2126  		t.Run(
  2127  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
  2128  			func(t *testing.T) {
  2129  				c := &check{t, testCase.serverType}
  2130  				suite := testCase
  2131  
  2132  				suite.SetUpSuite(c)
  2133  				defer suite.TearDownSuite(c)
  2134  
  2135  				err := suite.SetUpOpenIDs(c, testApps, rolePolicies)
  2136  				if err == nil {
  2137  					c.Fatalf("config with 2 claim based provider should fail")
  2138  				}
  2139  			},
  2140  		)
  2141  	}
  2142  }
  2143  
  2144  func TestIAMWithOpenIDWithMultipleRolesServerSuite(t *testing.T) {
  2145  	openIDServer := os.Getenv(EnvTestOpenIDServer)
  2146  	openIDServer2 := os.Getenv(EnvTestOpenIDServer2)
  2147  	if openIDServer == "" || openIDServer2 == "" {
  2148  		t.Skip("Skipping OpenID test as enough OpenID servers are not provided.")
  2149  	}
  2150  	testApps := testClientApps
  2151  
  2152  	rolePolicies := []string{
  2153  		"consoleAdmin",
  2154  		"readwrite",
  2155  	}
  2156  
  2157  	for i, testCase := range iamTestSuites {
  2158  		t.Run(
  2159  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
  2160  			func(t *testing.T) {
  2161  				c := &check{t, testCase.serverType}
  2162  				suite := testCase
  2163  
  2164  				suite.SetUpSuite(c)
  2165  				err := suite.SetUpOpenIDs(c, testApps, rolePolicies)
  2166  				if err != nil {
  2167  					c.Fatalf("Error setting up openid providers for tests: %v", err)
  2168  				}
  2169  				suite.TestOpenIDSTSWithRolePolicy(c, testRoleARNs[0], testRoleMap[testRoleARNs[0]])
  2170  				suite.TestOpenIDSTSWithRolePolicy(c, testRoleARNs[1], testRoleMap[testRoleARNs[1]])
  2171  				suite.TestOpenIDServiceAccWithRolePolicy(c)
  2172  				suite.TearDownSuite(c)
  2173  			},
  2174  		)
  2175  	}
  2176  }
  2177  
  2178  // Access Management Plugin tests
  2179  func TestIAM_AMPWithOpenIDWithMultipleRolesServerSuite(t *testing.T) {
  2180  	openIDServer := os.Getenv(EnvTestOpenIDServer)
  2181  	openIDServer2 := os.Getenv(EnvTestOpenIDServer2)
  2182  	if openIDServer == "" || openIDServer2 == "" {
  2183  		t.Skip("Skipping OpenID test as enough OpenID servers are not provided.")
  2184  	}
  2185  	testApps := testClientApps
  2186  
  2187  	rolePolicies := []string{
  2188  		"consoleAdmin",
  2189  		"readwrite",
  2190  	}
  2191  
  2192  	for i, testCase := range iamTestSuites {
  2193  		t.Run(
  2194  			fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
  2195  			func(t *testing.T) {
  2196  				c := &check{t, testCase.serverType}
  2197  				suite := testCase
  2198  
  2199  				suite.SetUpSuite(c)
  2200  				defer suite.TearDownSuite(c)
  2201  
  2202  				err := suite.SetUpOpenIDs(c, testApps, rolePolicies)
  2203  				if err != nil {
  2204  					c.Fatalf("Error setting up openid providers for tests: %v", err)
  2205  				}
  2206  
  2207  				suite.SetUpAccMgmtPlugin(c)
  2208  
  2209  				suite.TestOpenIDSTSWithRolePolicyUnderAMP(c, testRoleARNs[0], testRoleMap[testRoleARNs[0]])
  2210  				suite.TestOpenIDSTSWithRolePolicyUnderAMP(c, testRoleARNs[1], testRoleMap[testRoleARNs[1]])
  2211  				suite.TestOpenIDServiceAccWithRolePolicyUnderAMP(c)
  2212  			},
  2213  		)
  2214  	}
  2215  }
  2216  
  2217  func (s *TestSuiteIAM) TestOpenIDSTSWithRolePolicyUnderAMP(c *check, roleARN string, clientApp OpenIDClientAppParams) {
  2218  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  2219  	defer cancel()
  2220  
  2221  	bucket := getRandomBucketName()
  2222  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  2223  	if err != nil {
  2224  		c.Fatalf("bucket create error: %v", err)
  2225  	}
  2226  
  2227  	// Generate web identity JWT by interacting with OpenID IDP.
  2228  	token, err := MockOpenIDTestUserInteraction(ctx, clientApp, "dillon@example.io", "dillon")
  2229  	if err != nil {
  2230  		c.Fatalf("mock user err: %v", err)
  2231  	}
  2232  
  2233  	// Generate STS credential.
  2234  	webID := cr.STSWebIdentity{
  2235  		Client:      s.TestSuiteCommon.client,
  2236  		STSEndpoint: s.endPoint,
  2237  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  2238  			return &cr.WebIdentityToken{
  2239  				Token: token,
  2240  			}, nil
  2241  		},
  2242  		RoleARN: roleARN,
  2243  	}
  2244  
  2245  	value, err := webID.Retrieve()
  2246  	if err != nil {
  2247  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  2248  	}
  2249  	// fmt.Printf("value: %#v\n", value)
  2250  
  2251  	minioClient, err := minio.New(s.endpoint, &minio.Options{
  2252  		Creds:     cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  2253  		Secure:    s.secure,
  2254  		Transport: s.TestSuiteCommon.client.Transport,
  2255  	})
  2256  	if err != nil {
  2257  		c.Fatalf("Error initializing client: %v", err)
  2258  	}
  2259  
  2260  	// Validate that the client from sts creds can access the bucket.
  2261  	c.mustListObjects(ctx, minioClient, bucket)
  2262  
  2263  	// Validate that the client from STS creds cannot upload any object as
  2264  	// it is denied by the plugin.
  2265  	c.mustNotUpload(ctx, minioClient, bucket)
  2266  }
  2267  
  2268  func (s *TestSuiteIAM) TestOpenIDServiceAccWithRolePolicyUnderAMP(c *check) {
  2269  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  2270  	defer cancel()
  2271  
  2272  	bucket := getRandomBucketName()
  2273  	err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
  2274  	if err != nil {
  2275  		c.Fatalf("bucket create error: %v", err)
  2276  	}
  2277  
  2278  	// Generate web identity STS token by interacting with OpenID IDP.
  2279  	token, err := MockOpenIDTestUserInteraction(ctx, testAppParams, "dillon@example.io", "dillon")
  2280  	if err != nil {
  2281  		c.Fatalf("mock user err: %v", err)
  2282  	}
  2283  
  2284  	webID := cr.STSWebIdentity{
  2285  		Client:      s.TestSuiteCommon.client,
  2286  		STSEndpoint: s.endPoint,
  2287  		GetWebIDTokenExpiry: func() (*cr.WebIdentityToken, error) {
  2288  			return &cr.WebIdentityToken{
  2289  				Token: token,
  2290  			}, nil
  2291  		},
  2292  		RoleARN: testRoleARN,
  2293  	}
  2294  
  2295  	value, err := webID.Retrieve()
  2296  	if err != nil {
  2297  		c.Fatalf("Expected to generate STS creds, got err: %#v", err)
  2298  	}
  2299  
  2300  	// Create an madmin client with user creds
  2301  	userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
  2302  		Creds:  cr.NewStaticV4(value.AccessKeyID, value.SecretAccessKey, value.SessionToken),
  2303  		Secure: s.secure,
  2304  	})
  2305  	if err != nil {
  2306  		c.Fatalf("Err creating user admin client: %v", err)
  2307  	}
  2308  	userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
  2309  
  2310  	// Create svc acc
  2311  	cr := c.mustCreateSvcAccount(ctx, value.AccessKeyID, userAdmClient)
  2312  
  2313  	// 1. Check that svc account appears in listing
  2314  	c.assertSvcAccAppearsInListing(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey)
  2315  
  2316  	// 2. Check that svc account info can be queried
  2317  	c.assertSvcAccInfoQueryable(ctx, userAdmClient, value.AccessKeyID, cr.AccessKey, true)
  2318  
  2319  	// 3. Check S3 access
  2320  	c.assertSvcAccS3Access(ctx, s, cr, bucket)
  2321  	// 3.1 Validate that the client from STS creds cannot upload any object as
  2322  	// it is denied by the plugin.
  2323  	c.mustNotUpload(ctx, s.getUserClient(c, cr.AccessKey, cr.SecretKey, ""), bucket)
  2324  
  2325  	// Check that session policies do not apply - as policy enforcement is
  2326  	// delegated to plugin.
  2327  	{
  2328  		svcAK, svcSK := mustGenerateCredentials(c)
  2329  
  2330  		// This policy does not allow listing objects.
  2331  		policyBytes := []byte(fmt.Sprintf(`{
  2332   "Version": "2012-10-17",
  2333   "Statement": [
  2334    {
  2335     "Effect": "Allow",
  2336     "Action": [
  2337      "s3:PutObject",
  2338      "s3:GetObject"
  2339     ],
  2340     "Resource": [
  2341      "arn:aws:s3:::%s/*"
  2342     ]
  2343    }
  2344   ]
  2345  }`, bucket))
  2346  		cr, err := userAdmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
  2347  			Policy:     policyBytes,
  2348  			TargetUser: value.AccessKeyID,
  2349  			AccessKey:  svcAK,
  2350  			SecretKey:  svcSK,
  2351  		})
  2352  		if err != nil {
  2353  			c.Fatalf("Unable to create svc acc: %v", err)
  2354  		}
  2355  		svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "")
  2356  		// Though the attached policy does not allow listing, it will be
  2357  		// ignored because the plugin allows it.
  2358  		c.mustListObjects(ctx, svcClient, bucket)
  2359  	}
  2360  
  2361  	// 4. Check that service account's secret key and account status can be
  2362  	// updated.
  2363  	c.assertSvcAccSecretKeyAndStatusUpdate(ctx, s, userAdmClient, value.AccessKeyID, bucket)
  2364  
  2365  	// 5. Check that service account can be deleted.
  2366  	c.assertSvcAccDeletion(ctx, s, userAdmClient, value.AccessKeyID, bucket)
  2367  }