github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/bucket-policy-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  	"bytes"
    22  	"fmt"
    23  	"io"
    24  	"net/http"
    25  	"net/http/httptest"
    26  	"reflect"
    27  	"strings"
    28  	"sync"
    29  	"testing"
    30  
    31  	"github.com/minio/minio/internal/auth"
    32  	"github.com/minio/pkg/v2/policy"
    33  	"github.com/minio/pkg/v2/policy/condition"
    34  )
    35  
    36  func getAnonReadOnlyBucketPolicy(bucketName string) *policy.BucketPolicy {
    37  	return &policy.BucketPolicy{
    38  		Version: policy.DefaultVersion,
    39  		Statements: []policy.BPStatement{
    40  			policy.NewBPStatement(
    41  				"",
    42  				policy.Allow,
    43  				policy.NewPrincipal("*"),
    44  				policy.NewActionSet(policy.GetBucketLocationAction, policy.ListBucketAction),
    45  				policy.NewResourceSet(policy.NewResource(bucketName)),
    46  				condition.NewFunctions(),
    47  			),
    48  		},
    49  	}
    50  }
    51  
    52  func getAnonWriteOnlyBucketPolicy(bucketName string) *policy.BucketPolicy {
    53  	return &policy.BucketPolicy{
    54  		Version: policy.DefaultVersion,
    55  		Statements: []policy.BPStatement{
    56  			policy.NewBPStatement(
    57  				"",
    58  				policy.Allow,
    59  				policy.NewPrincipal("*"),
    60  				policy.NewActionSet(
    61  					policy.GetBucketLocationAction,
    62  					policy.ListBucketMultipartUploadsAction,
    63  				),
    64  				policy.NewResourceSet(policy.NewResource(bucketName)),
    65  				condition.NewFunctions(),
    66  			),
    67  		},
    68  	}
    69  }
    70  
    71  func getAnonReadOnlyObjectPolicy(bucketName, prefix string) *policy.BucketPolicy {
    72  	return &policy.BucketPolicy{
    73  		Version: policy.DefaultVersion,
    74  		Statements: []policy.BPStatement{
    75  			policy.NewBPStatement(
    76  				"",
    77  				policy.Allow,
    78  				policy.NewPrincipal("*"),
    79  				policy.NewActionSet(policy.GetObjectAction),
    80  				policy.NewResourceSet(policy.NewResource(bucketName+"/"+prefix)),
    81  				condition.NewFunctions(),
    82  			),
    83  		},
    84  	}
    85  }
    86  
    87  func getAnonWriteOnlyObjectPolicy(bucketName, prefix string) *policy.BucketPolicy {
    88  	return &policy.BucketPolicy{
    89  		Version: policy.DefaultVersion,
    90  		Statements: []policy.BPStatement{
    91  			policy.NewBPStatement(
    92  				"",
    93  				policy.Allow,
    94  				policy.NewPrincipal("*"),
    95  				policy.NewActionSet(
    96  					policy.AbortMultipartUploadAction,
    97  					policy.DeleteObjectAction,
    98  					policy.ListMultipartUploadPartsAction,
    99  					policy.PutObjectAction,
   100  				),
   101  				policy.NewResourceSet(policy.NewResource(bucketName+"/"+prefix)),
   102  				condition.NewFunctions(),
   103  			),
   104  		},
   105  	}
   106  }
   107  
   108  // Wrapper for calling Create Bucket and ensure we get one and only one success.
   109  func TestCreateBucket(t *testing.T) {
   110  	ExecObjectLayerAPITest(t, testCreateBucket, []string{"MakeBucket"})
   111  }
   112  
   113  // testCreateBucket - Test for calling Create Bucket and ensure we get one and only one success.
   114  func testCreateBucket(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
   115  	credentials auth.Credentials, t *testing.T,
   116  ) {
   117  	bucketName1 := fmt.Sprintf("%s-1", bucketName)
   118  
   119  	const n = 100
   120  	start := make(chan struct{})
   121  	var ok, errs int
   122  	var wg sync.WaitGroup
   123  	var mu sync.Mutex
   124  	wg.Add(n)
   125  	for i := 0; i < n; i++ {
   126  		go func() {
   127  			defer wg.Done()
   128  			// Sync start.
   129  			<-start
   130  			if err := obj.MakeBucket(GlobalContext, bucketName1, MakeBucketOptions{}); err != nil {
   131  				if _, ok := err.(BucketExists); !ok {
   132  					t.Logf("unexpected error: %T: %v", err, err)
   133  					return
   134  				}
   135  				mu.Lock()
   136  				errs++
   137  				mu.Unlock()
   138  				return
   139  			}
   140  			mu.Lock()
   141  			ok++
   142  			mu.Unlock()
   143  		}()
   144  	}
   145  	close(start)
   146  	wg.Wait()
   147  	if ok != 1 {
   148  		t.Fatalf("want 1 ok, got %d", ok)
   149  	}
   150  	if errs != n-1 {
   151  		t.Fatalf("want %d errors, got %d", n-1, errs)
   152  	}
   153  }
   154  
   155  // Wrapper for calling Put Bucket Policy HTTP handler tests for both Erasure multiple disks and single node setup.
   156  func TestPutBucketPolicyHandler(t *testing.T) {
   157  	ExecObjectLayerAPITest(t, testPutBucketPolicyHandler, []string{"PutBucketPolicy"})
   158  }
   159  
   160  // testPutBucketPolicyHandler - Test for Bucket policy end point.
   161  func testPutBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
   162  	credentials auth.Credentials, t *testing.T,
   163  ) {
   164  	bucketName1 := fmt.Sprintf("%s-1", bucketName)
   165  	if err := obj.MakeBucket(GlobalContext, bucketName1, MakeBucketOptions{}); err != nil {
   166  		t.Fatal(err)
   167  	}
   168  
   169  	// template for constructing HTTP request body for PUT bucket policy.
   170  	bucketPolicyTemplate := `{"Version":"2012-10-17","Statement":[{"Sid":"","Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:GetBucketLocation","s3:ListBucket"],"Resource":["arn:aws:s3:::%s"]},{"Sid":"","Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:GetObject"],"Resource":["arn:aws:s3:::%s/this*"]}]}`
   171  
   172  	bucketPolicyTemplateWithoutVersion := `{"Version":"","Statement":[{"Sid":"","Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:GetBucketLocation","s3:ListBucket"],"Resource":["arn:aws:s3:::%s"]},{"Sid":"","Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:GetObject"],"Resource":["arn:aws:s3:::%s/this*"]}]}`
   173  
   174  	// test cases with sample input and expected output.
   175  	testCases := []struct {
   176  		bucketName string
   177  		// bucket policy to be set,
   178  		// set as request body.
   179  		bucketPolicyReader io.ReadSeeker
   180  		// length in bytes of the bucket policy being set.
   181  		policyLen int
   182  		accessKey string
   183  		secretKey string
   184  		// expected Response.
   185  		expectedRespStatus int
   186  	}{
   187  		// Test case - 1.
   188  		{
   189  			bucketName:         bucketName,
   190  			bucketPolicyReader: bytes.NewReader([]byte(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName))),
   191  
   192  			policyLen:          len(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName)),
   193  			accessKey:          credentials.AccessKey,
   194  			secretKey:          credentials.SecretKey,
   195  			expectedRespStatus: http.StatusNoContent,
   196  		},
   197  		// Test case - 2.
   198  		// Setting the content length to be more than max allowed size.
   199  		// Expecting StatusBadRequest (400).
   200  		{
   201  			bucketName:         bucketName,
   202  			bucketPolicyReader: bytes.NewReader([]byte(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName))),
   203  
   204  			policyLen:          maxBucketPolicySize + 1,
   205  			accessKey:          credentials.AccessKey,
   206  			secretKey:          credentials.SecretKey,
   207  			expectedRespStatus: http.StatusBadRequest,
   208  		},
   209  		// Test case - 3.
   210  		// Case with content-length of the HTTP request set to 0.
   211  		// Expecting the HTTP response status to be StatusLengthRequired (411).
   212  		{
   213  			bucketName:         bucketName,
   214  			bucketPolicyReader: bytes.NewReader([]byte(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName))),
   215  
   216  			policyLen:          0,
   217  			accessKey:          credentials.AccessKey,
   218  			secretKey:          credentials.SecretKey,
   219  			expectedRespStatus: http.StatusLengthRequired,
   220  		},
   221  		// Test case - 4.
   222  		// setting the readSeeker to `nil`, bucket policy parser will fail.
   223  		{
   224  			bucketName:         bucketName,
   225  			bucketPolicyReader: nil,
   226  
   227  			policyLen:          10,
   228  			accessKey:          credentials.AccessKey,
   229  			secretKey:          credentials.SecretKey,
   230  			expectedRespStatus: http.StatusBadRequest,
   231  		},
   232  		// Test case - 5.
   233  		// setting the keys to be empty.
   234  		// Expecting statusForbidden.
   235  		{
   236  			bucketName:         bucketName,
   237  			bucketPolicyReader: nil,
   238  
   239  			policyLen:          10,
   240  			accessKey:          "",
   241  			secretKey:          "",
   242  			expectedRespStatus: http.StatusForbidden,
   243  		},
   244  		// Test case - 6.
   245  		// setting an invalid bucket policy.
   246  		// the bucket policy parser will fail.
   247  		{
   248  			bucketName:         bucketName,
   249  			bucketPolicyReader: bytes.NewReader([]byte("dummy-policy")),
   250  
   251  			policyLen:          len([]byte("dummy-policy")),
   252  			accessKey:          credentials.AccessKey,
   253  			secretKey:          credentials.SecretKey,
   254  			expectedRespStatus: http.StatusBadRequest,
   255  		},
   256  		// Test case - 7.
   257  		// Different bucket name used in the HTTP request and the policy string.
   258  		// checkBucketPolicyResources should fail.
   259  		{
   260  			bucketName:         bucketName1,
   261  			bucketPolicyReader: bytes.NewReader([]byte(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName))),
   262  
   263  			policyLen:          len(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName)),
   264  			accessKey:          credentials.AccessKey,
   265  			secretKey:          credentials.SecretKey,
   266  			expectedRespStatus: http.StatusBadRequest,
   267  		},
   268  		// Test case - 8.
   269  		// non-existent bucket is used.
   270  		// writing BucketPolicy should fail.
   271  		// should result in 404 StatusNotFound
   272  		{
   273  			bucketName:         "non-existent-bucket",
   274  			bucketPolicyReader: bytes.NewReader([]byte(fmt.Sprintf(bucketPolicyTemplate, "non-existent-bucket", "non-existent-bucket"))),
   275  
   276  			policyLen:          len(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName)),
   277  			accessKey:          credentials.AccessKey,
   278  			secretKey:          credentials.SecretKey,
   279  			expectedRespStatus: http.StatusNotFound,
   280  		},
   281  		// Test case - 9.
   282  		// non-existent bucket is used (with invalid bucket name)
   283  		// writing BucketPolicy should fail.
   284  		// should result in 404 StatusNotFound
   285  		{
   286  			bucketName:         ".invalid-bucket",
   287  			bucketPolicyReader: bytes.NewReader([]byte(fmt.Sprintf(bucketPolicyTemplate, ".invalid-bucket", ".invalid-bucket"))),
   288  
   289  			policyLen:          len(fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName)),
   290  			accessKey:          credentials.AccessKey,
   291  			secretKey:          credentials.SecretKey,
   292  			expectedRespStatus: http.StatusBadRequest,
   293  		},
   294  		// Test case - 10.
   295  		// Existent bucket with policy with Version field empty.
   296  		// writing BucketPolicy should fail.
   297  		// should result in 400 StatusBadRequest.
   298  		{
   299  			bucketName:         bucketName,
   300  			bucketPolicyReader: bytes.NewReader([]byte(fmt.Sprintf(bucketPolicyTemplateWithoutVersion, bucketName, bucketName))),
   301  
   302  			policyLen:          len(fmt.Sprintf(bucketPolicyTemplateWithoutVersion, bucketName, bucketName)),
   303  			accessKey:          credentials.AccessKey,
   304  			secretKey:          credentials.SecretKey,
   305  			expectedRespStatus: http.StatusBadRequest,
   306  		},
   307  	}
   308  
   309  	// Iterating over the test cases, calling the function under test and asserting the response.
   310  	for i, testCase := range testCases {
   311  		// obtain the put bucket policy request body.
   312  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   313  		recV4 := httptest.NewRecorder()
   314  		// construct HTTP request for PUT bucket policy endpoint.
   315  		reqV4, err := newTestSignedRequestV4(http.MethodPut, getPutPolicyURL("", testCase.bucketName),
   316  			int64(testCase.policyLen), testCase.bucketPolicyReader, testCase.accessKey, testCase.secretKey, nil)
   317  		if err != nil {
   318  			t.Fatalf("Test %d: %s: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, instanceType, err)
   319  		}
   320  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   321  		// Call the ServeHTTP to execute the handler.
   322  		apiRouter.ServeHTTP(recV4, reqV4)
   323  		if recV4.Code != testCase.expectedRespStatus {
   324  			t.Errorf("Test %d: %s: Expected the response status to be `%d`, but instead found `%d`", i+1, instanceType, testCase.expectedRespStatus, recV4.Code)
   325  		}
   326  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   327  		recV2 := httptest.NewRecorder()
   328  		// construct HTTP request for PUT bucket policy endpoint.
   329  		reqV2, err := newTestSignedRequestV2(http.MethodPut, getPutPolicyURL("", testCase.bucketName),
   330  			int64(testCase.policyLen), testCase.bucketPolicyReader, testCase.accessKey, testCase.secretKey, nil)
   331  		if err != nil {
   332  			t.Fatalf("Test %d: %s: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, instanceType, err)
   333  		}
   334  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   335  		// Call the ServeHTTP to execute the handler.
   336  		apiRouter.ServeHTTP(recV2, reqV2)
   337  		if recV2.Code != testCase.expectedRespStatus {
   338  			t.Errorf("Test %d: %s: Expected the response status to be `%d`, but instead found `%d`", i+1, instanceType, testCase.expectedRespStatus, recV2.Code)
   339  		}
   340  	}
   341  
   342  	// Test for Anonymous/unsigned http request.
   343  	// Bucket policy related functions doesn't support anonymous requests, setting policies shouldn't make a difference.
   344  	bucketPolicyStr := fmt.Sprintf(bucketPolicyTemplate, bucketName, bucketName)
   345  	// create unsigned HTTP request for PutBucketPolicyHandler.
   346  	anonReq, err := newTestRequest(http.MethodPut, getPutPolicyURL("", bucketName),
   347  		int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)))
   348  	if err != nil {
   349  		t.Fatalf("MinIO %s: Failed to create an anonymous request for bucket \"%s\": <ERROR> %v",
   350  			instanceType, bucketName, err)
   351  	}
   352  
   353  	// ExecObjectLayerAPIAnonTest - Calls the HTTP API handler using the anonymous request, validates the ErrAccessDeniedResponse,
   354  	// sets the bucket policy using the policy statement generated from `getWriteOnlyObjectStatement` so that the
   355  	// unsigned request goes through and its validated again.
   356  	ExecObjectLayerAPIAnonTest(t, obj, "PutBucketPolicyHandler", bucketName, "", instanceType, apiRouter, anonReq, getAnonWriteOnlyBucketPolicy(bucketName))
   357  
   358  	// HTTP request for testing when `objectLayer` is set to `nil`.
   359  	// There is no need to use an existing bucket and valid input for creating the request
   360  	// since the `objectLayer==nil`  check is performed before any other checks inside the handlers.
   361  	// The only aim is to generate an HTTP request in a way that the relevant/registered end point is evoked/called.
   362  	nilBucket := "dummy-bucket"
   363  
   364  	nilReq, err := newTestSignedRequestV4(http.MethodPut, getPutPolicyURL("", nilBucket),
   365  		0, nil, "", "", nil)
   366  	if err != nil {
   367  		t.Errorf("MinIO %s: Failed to create HTTP request for testing the response when object Layer is set to `nil`.", instanceType)
   368  	}
   369  	// execute the object layer set to `nil` test.
   370  	// `ExecObjectLayerAPINilTest` manages the operation.
   371  	ExecObjectLayerAPINilTest(t, nilBucket, "", instanceType, apiRouter, nilReq)
   372  }
   373  
   374  // Wrapper for calling Get Bucket Policy HTTP handler tests for both Erasure multiple disks and single node setup.
   375  func TestGetBucketPolicyHandler(t *testing.T) {
   376  	ExecObjectLayerAPITest(t, testGetBucketPolicyHandler, []string{"PutBucketPolicy", "GetBucketPolicy"})
   377  }
   378  
   379  // testGetBucketPolicyHandler - Test for end point which fetches the access policy json of the given bucket.
   380  func testGetBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
   381  	credentials auth.Credentials, t *testing.T,
   382  ) {
   383  	// template for constructing HTTP request body for PUT bucket policy.
   384  	bucketPolicyTemplate := `{"Version":"2012-10-17","Statement":[{"Action":["s3:GetBucketLocation","s3:ListBucket"],"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::%s"]},{"Action":["s3:GetObject"],"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::%s/this*"]}]}`
   385  
   386  	// Writing bucket policy before running test on GetBucketPolicy.
   387  	putTestPolicies := []struct {
   388  		bucketName string
   389  		accessKey  string
   390  		secretKey  string
   391  		// expected Response.
   392  		expectedRespStatus int
   393  	}{
   394  		{bucketName, credentials.AccessKey, credentials.SecretKey, http.StatusNoContent},
   395  	}
   396  
   397  	// Iterating over the cases and writing the bucket policy.
   398  	// its required to write the policies first before running tests on GetBucketPolicy.
   399  	for i, testPolicy := range putTestPolicies {
   400  		// obtain the put bucket policy request body.
   401  		bucketPolicyStr := fmt.Sprintf(bucketPolicyTemplate, testPolicy.bucketName, testPolicy.bucketName)
   402  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   403  		recV4 := httptest.NewRecorder()
   404  		// construct HTTP request for PUT bucket policy endpoint.
   405  		reqV4, err := newTestSignedRequestV4(http.MethodPut, getPutPolicyURL("", testPolicy.bucketName),
   406  			int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), testPolicy.accessKey, testPolicy.secretKey, nil)
   407  		if err != nil {
   408  			t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, err)
   409  		}
   410  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   411  		// Call the ServeHTTP to execute the handler.
   412  		apiRouter.ServeHTTP(recV4, reqV4)
   413  		if recV4.Code != testPolicy.expectedRespStatus {
   414  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testPolicy.expectedRespStatus, recV4.Code)
   415  		}
   416  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   417  		recV2 := httptest.NewRecorder()
   418  		// construct HTTP request for PUT bucket policy endpoint.
   419  		reqV2, err := newTestSignedRequestV2(http.MethodPut, getPutPolicyURL("", testPolicy.bucketName),
   420  			int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), testPolicy.accessKey, testPolicy.secretKey, nil)
   421  		if err != nil {
   422  			t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, err)
   423  		}
   424  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   425  		// Call the ServeHTTP to execute the handler.
   426  		apiRouter.ServeHTTP(recV2, reqV2)
   427  		if recV2.Code != testPolicy.expectedRespStatus {
   428  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testPolicy.expectedRespStatus, recV2.Code)
   429  		}
   430  	}
   431  
   432  	// test cases with inputs and expected result for GetBucketPolicyHandler.
   433  	testCases := []struct {
   434  		bucketName string
   435  		accessKey  string
   436  		secretKey  string
   437  		// expected output.
   438  		expectedBucketPolicy string
   439  		expectedRespStatus   int
   440  	}{
   441  		// Test case - 1.
   442  		// Case which valid inputs, expected to return success status of 200OK.
   443  		{
   444  			bucketName:           bucketName,
   445  			accessKey:            credentials.AccessKey,
   446  			secretKey:            credentials.SecretKey,
   447  			expectedBucketPolicy: bucketPolicyTemplate,
   448  			expectedRespStatus:   http.StatusOK,
   449  		},
   450  		// Test case - 2.
   451  		// Case with non-existent bucket name.
   452  		{
   453  			bucketName:           "non-existent-bucket",
   454  			accessKey:            credentials.AccessKey,
   455  			secretKey:            credentials.SecretKey,
   456  			expectedBucketPolicy: bucketPolicyTemplate,
   457  			expectedRespStatus:   http.StatusNotFound,
   458  		},
   459  		// Test case - 3.
   460  		// Case with non-existent bucket name.
   461  		{
   462  			bucketName:           ".invalid-bucket-name",
   463  			accessKey:            credentials.AccessKey,
   464  			secretKey:            credentials.SecretKey,
   465  			expectedBucketPolicy: "",
   466  			expectedRespStatus:   http.StatusBadRequest,
   467  		},
   468  	}
   469  	// Iterating over the cases, fetching the policy and validating the response.
   470  	for i, testCase := range testCases {
   471  		// expected bucket policy json string.
   472  		expectedBucketPolicyStr := fmt.Sprintf(testCase.expectedBucketPolicy, testCase.bucketName, testCase.bucketName)
   473  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   474  		recV4 := httptest.NewRecorder()
   475  		// construct HTTP request for PUT bucket policy endpoint.
   476  		reqV4, err := newTestSignedRequestV4(http.MethodGet, getGetPolicyURL("", testCase.bucketName),
   477  			0, nil, testCase.accessKey, testCase.secretKey, nil)
   478  		if err != nil {
   479  			t.Fatalf("Test %d: Failed to create HTTP request for GetBucketPolicyHandler: <ERROR> %v", i+1, err)
   480  		}
   481  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   482  		// Call the ServeHTTP to execute the handler, GetBucketPolicyHandler handles the request.
   483  		apiRouter.ServeHTTP(recV4, reqV4)
   484  		// Assert the response code with the expected status.
   485  		if recV4.Code != testCase.expectedRespStatus {
   486  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testCase.expectedRespStatus, recV4.Code)
   487  		}
   488  		// read the response body.
   489  		bucketPolicyReadBuf, err := io.ReadAll(recV4.Body)
   490  		if err != nil {
   491  			t.Fatalf("Test %d: %s: Failed parsing response body: <ERROR> %v", i+1, instanceType, err)
   492  		}
   493  
   494  		if recV4.Code != testCase.expectedRespStatus {
   495  			// Verify whether the bucket policy fetched is same as the one inserted.
   496  			var expectedPolicy *policy.BucketPolicy
   497  			expectedPolicy, err = policy.ParseBucketPolicyConfig(strings.NewReader(expectedBucketPolicyStr), testCase.bucketName)
   498  			if err != nil {
   499  				t.Fatalf("unexpected error. %v", err)
   500  			}
   501  			var gotPolicy *policy.BucketPolicy
   502  			gotPolicy, err = policy.ParseBucketPolicyConfig(bytes.NewReader(bucketPolicyReadBuf), testCase.bucketName)
   503  			if err != nil {
   504  				t.Fatalf("unexpected error. %v", err)
   505  			}
   506  
   507  			if !reflect.DeepEqual(expectedPolicy, gotPolicy) {
   508  				t.Errorf("Test %d: %s: Bucket policy differs from expected value.", i+1, instanceType)
   509  			}
   510  		}
   511  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   512  		recV2 := httptest.NewRecorder()
   513  		// construct HTTP request for PUT bucket policy endpoint.
   514  		reqV2, err := newTestSignedRequestV2(http.MethodGet, getGetPolicyURL("", testCase.bucketName),
   515  			0, nil, testCase.accessKey, testCase.secretKey, nil)
   516  		if err != nil {
   517  			t.Fatalf("Test %d: Failed to create HTTP request for GetBucketPolicyHandler: <ERROR> %v", i+1, err)
   518  		}
   519  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   520  		// Call the ServeHTTP to execute the handler, GetBucketPolicyHandler handles the request.
   521  		apiRouter.ServeHTTP(recV2, reqV2)
   522  		// Assert the response code with the expected status.
   523  		if recV2.Code != testCase.expectedRespStatus {
   524  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testCase.expectedRespStatus, recV2.Code)
   525  		}
   526  		// read the response body.
   527  		bucketPolicyReadBuf, err = io.ReadAll(recV2.Body)
   528  		if err != nil {
   529  			t.Fatalf("Test %d: %s: Failed parsing response body: <ERROR> %v", i+1, instanceType, err)
   530  		}
   531  		if recV2.Code == http.StatusOK {
   532  			// Verify whether the bucket policy fetched is same as the one inserted.
   533  			expectedPolicy, err := policy.ParseBucketPolicyConfig(strings.NewReader(expectedBucketPolicyStr), testCase.bucketName)
   534  			if err != nil {
   535  				t.Fatalf("unexpected error. %v", err)
   536  			}
   537  			gotPolicy, err := policy.ParseBucketPolicyConfig(bytes.NewReader(bucketPolicyReadBuf), testCase.bucketName)
   538  			if err != nil {
   539  				t.Fatalf("unexpected error. %v", err)
   540  			}
   541  
   542  			if !reflect.DeepEqual(expectedPolicy, gotPolicy) {
   543  				t.Errorf("Test %d: %s: Bucket policy differs from expected value.", i+1, instanceType)
   544  			}
   545  		}
   546  	}
   547  
   548  	// Test for Anonymous/unsigned http request.
   549  	// Bucket policy related functions doesn't support anonymous requests, setting policies shouldn't make a difference.
   550  	// create unsigned HTTP request for PutBucketPolicyHandler.
   551  	anonReq, err := newTestRequest(http.MethodGet, getPutPolicyURL("", bucketName), 0, nil)
   552  	if err != nil {
   553  		t.Fatalf("MinIO %s: Failed to create an anonymous request for bucket \"%s\": <ERROR> %v",
   554  			instanceType, bucketName, err)
   555  	}
   556  
   557  	// ExecObjectLayerAPIAnonTest - Calls the HTTP API handler using the anonymous request, validates the ErrAccessDeniedResponse,
   558  	// sets the bucket policy using the policy statement generated from `getWriteOnlyObjectStatement` so that the
   559  	// unsigned request goes through and its validated again.
   560  	ExecObjectLayerAPIAnonTest(t, obj, "GetBucketPolicyHandler", bucketName, "", instanceType, apiRouter, anonReq, getAnonReadOnlyBucketPolicy(bucketName))
   561  
   562  	// HTTP request for testing when `objectLayer` is set to `nil`.
   563  	// There is no need to use an existing bucket and valid input for creating the request
   564  	// since the `objectLayer==nil`  check is performed before any other checks inside the handlers.
   565  	// The only aim is to generate an HTTP request in a way that the relevant/registered end point is evoked/called.
   566  	nilBucket := "dummy-bucket"
   567  
   568  	nilReq, err := newTestSignedRequestV4(http.MethodGet, getGetPolicyURL("", nilBucket),
   569  		0, nil, "", "", nil)
   570  	if err != nil {
   571  		t.Errorf("MinIO %s: Failed to create HTTP request for testing the response when object Layer is set to `nil`.", instanceType)
   572  	}
   573  	// execute the object layer set to `nil` test.
   574  	// `ExecObjectLayerAPINilTest` manages the operation.
   575  	ExecObjectLayerAPINilTest(t, nilBucket, "", instanceType, apiRouter, nilReq)
   576  }
   577  
   578  // Wrapper for calling Delete Bucket Policy HTTP handler tests for both Erasure multiple disks and single node setup.
   579  func TestDeleteBucketPolicyHandler(t *testing.T) {
   580  	ExecObjectLayerAPITest(t, testDeleteBucketPolicyHandler, []string{"PutBucketPolicy", "DeleteBucketPolicy"})
   581  }
   582  
   583  // testDeleteBucketPolicyHandler - Test for Delete bucket policy end point.
   584  func testDeleteBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
   585  	credentials auth.Credentials, t *testing.T,
   586  ) {
   587  	// template for constructing HTTP request body for PUT bucket policy.
   588  	bucketPolicyTemplate := `{
   589      "Version": "2012-10-17",
   590      "Statement": [
   591          {
   592              "Action": [
   593                  "s3:GetBucketLocation",
   594                  "s3:ListBucket"
   595              ],
   596              "Effect": "Allow",
   597              "Principal": {
   598                  "AWS": [
   599                      "*"
   600                  ]
   601              },
   602              "Resource": [
   603                  "arn:aws:s3:::%s"
   604              ]
   605          },
   606          {
   607              "Action": [
   608                  "s3:GetObject"
   609              ],
   610              "Effect": "Allow",
   611              "Principal": {
   612                  "AWS": [
   613                      "*"
   614                  ]
   615              },
   616              "Resource": [
   617                  "arn:aws:s3:::%s/this*"
   618              ]
   619          }
   620      ]
   621  }`
   622  
   623  	// Writing bucket policy before running test on DeleteBucketPolicy.
   624  	putTestPolicies := []struct {
   625  		bucketName string
   626  		accessKey  string
   627  		secretKey  string
   628  		// expected Response.
   629  		expectedRespStatus int
   630  	}{
   631  		{
   632  			bucketName:         bucketName,
   633  			accessKey:          credentials.AccessKey,
   634  			secretKey:          credentials.SecretKey,
   635  			expectedRespStatus: http.StatusNoContent,
   636  		},
   637  	}
   638  
   639  	// Iterating over the cases and writing the bucket policy.
   640  	// its required to write the policies first before running tests on GetBucketPolicy.
   641  	for i, testPolicy := range putTestPolicies {
   642  		// obtain the put bucket policy request body.
   643  		bucketPolicyStr := fmt.Sprintf(bucketPolicyTemplate, testPolicy.bucketName, testPolicy.bucketName)
   644  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   645  		recV4 := httptest.NewRecorder()
   646  		// construct HTTP request for PUT bucket policy endpoint.
   647  		reqV4, err := newTestSignedRequestV4(http.MethodPut, getPutPolicyURL("", testPolicy.bucketName),
   648  			int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), testPolicy.accessKey, testPolicy.secretKey, nil)
   649  		if err != nil {
   650  			t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, err)
   651  		}
   652  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   653  		// Call the ServeHTTP to execute the handler.
   654  		apiRouter.ServeHTTP(recV4, reqV4)
   655  		if recV4.Code != testPolicy.expectedRespStatus {
   656  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testPolicy.expectedRespStatus, recV4.Code)
   657  		}
   658  	}
   659  
   660  	// testcases with input and expected output for DeleteBucketPolicyHandler.
   661  	testCases := []struct {
   662  		bucketName string
   663  		accessKey  string
   664  		secretKey  string
   665  		// expected response.
   666  		expectedRespStatus int
   667  	}{
   668  		// Test case - 1.
   669  		{
   670  			bucketName:         bucketName,
   671  			accessKey:          credentials.AccessKey,
   672  			secretKey:          credentials.SecretKey,
   673  			expectedRespStatus: http.StatusNoContent,
   674  		},
   675  		// Test case - 2.
   676  		// Case with non-existent-bucket.
   677  		{
   678  			bucketName:         "non-existent-bucket",
   679  			accessKey:          credentials.AccessKey,
   680  			secretKey:          credentials.SecretKey,
   681  			expectedRespStatus: http.StatusNotFound,
   682  		},
   683  		// Test case - 3.
   684  		// Case with non-existent-bucket.
   685  		{
   686  			bucketName:         ".invalid-bucket-name",
   687  			accessKey:          credentials.AccessKey,
   688  			secretKey:          credentials.SecretKey,
   689  			expectedRespStatus: http.StatusBadRequest,
   690  		},
   691  	}
   692  	// Iterating over the cases and deleting the bucket policy and then asserting response.
   693  	for i, testCase := range testCases {
   694  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   695  		recV4 := httptest.NewRecorder()
   696  		// construct HTTP request for Delete bucket policy endpoint.
   697  		reqV4, err := newTestSignedRequestV4(http.MethodDelete, getDeletePolicyURL("", testCase.bucketName),
   698  			0, nil, testCase.accessKey, testCase.secretKey, nil)
   699  		if err != nil {
   700  			t.Fatalf("Test %d: Failed to create HTTP request for GetBucketPolicyHandler: <ERROR> %v", i+1, err)
   701  		}
   702  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   703  		// Call the ServeHTTP to execute the handler, DeleteBucketPolicyHandler  handles the request.
   704  		apiRouter.ServeHTTP(recV4, reqV4)
   705  		// Assert the response code with the expected status.
   706  		if recV4.Code != testCase.expectedRespStatus {
   707  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testCase.expectedRespStatus, recV4.Code)
   708  		}
   709  	}
   710  
   711  	// Iterating over the cases and writing the bucket policy.
   712  	// its required to write the policies first before running tests on GetBucketPolicy.
   713  	for i, testPolicy := range putTestPolicies {
   714  		// obtain the put bucket policy request body.
   715  		bucketPolicyStr := fmt.Sprintf(bucketPolicyTemplate, testPolicy.bucketName, testPolicy.bucketName)
   716  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   717  		recV2 := httptest.NewRecorder()
   718  		// construct HTTP request for PUT bucket policy endpoint.
   719  		reqV2, err := newTestSignedRequestV2(http.MethodPut, getPutPolicyURL("", testPolicy.bucketName),
   720  			int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), testPolicy.accessKey, testPolicy.secretKey, nil)
   721  		if err != nil {
   722  			t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, err)
   723  		}
   724  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   725  		// Call the ServeHTTP to execute the handler.
   726  		apiRouter.ServeHTTP(recV2, reqV2)
   727  		if recV2.Code != testPolicy.expectedRespStatus {
   728  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testPolicy.expectedRespStatus, recV2.Code)
   729  		}
   730  	}
   731  
   732  	for i, testCase := range testCases {
   733  		// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
   734  		recV2 := httptest.NewRecorder()
   735  		// construct HTTP request for Delete bucket policy endpoint.
   736  		reqV2, err := newTestSignedRequestV2(http.MethodDelete, getDeletePolicyURL("", testCase.bucketName),
   737  			0, nil, testCase.accessKey, testCase.secretKey, nil)
   738  		if err != nil {
   739  			t.Fatalf("Test %d: Failed to create HTTP request for GetBucketPolicyHandler: <ERROR> %v", i+1, err)
   740  		}
   741  		// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
   742  		// Call the ServeHTTP to execute the handler, DeleteBucketPolicyHandler  handles the request.
   743  		apiRouter.ServeHTTP(recV2, reqV2)
   744  		// Assert the response code with the expected status.
   745  		if recV2.Code != testCase.expectedRespStatus {
   746  			t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testCase.expectedRespStatus, recV2.Code)
   747  		}
   748  	}
   749  	// Test for Anonymous/unsigned http request.
   750  	// Bucket policy related functions doesn't support anonymous requests, setting policies shouldn't make a difference.
   751  	// create unsigned HTTP request for PutBucketPolicyHandler.
   752  	anonReq, err := newTestRequest(http.MethodDelete, getPutPolicyURL("", bucketName), 0, nil)
   753  	if err != nil {
   754  		t.Fatalf("MinIO %s: Failed to create an anonymous request for bucket \"%s\": <ERROR> %v",
   755  			instanceType, bucketName, err)
   756  	}
   757  
   758  	// ExecObjectLayerAPIAnonTest - Calls the HTTP API handler using the anonymous request, validates the ErrAccessDeniedResponse,
   759  	// sets the bucket policy using the policy statement generated from `getWriteOnlyObjectStatement` so that the
   760  	// unsigned request goes through and its validated again.
   761  	ExecObjectLayerAPIAnonTest(t, obj, "DeleteBucketPolicyHandler", bucketName, "", instanceType, apiRouter, anonReq, getAnonWriteOnlyBucketPolicy(bucketName))
   762  
   763  	// HTTP request for testing when `objectLayer` is set to `nil`.
   764  	// There is no need to use an existing bucket and valid input for creating the request
   765  	// since the `objectLayer==nil`  check is performed before any other checks inside the handlers.
   766  	// The only aim is to generate an HTTP request in a way that the relevant/registered end point is evoked/called.
   767  	nilBucket := "dummy-bucket"
   768  
   769  	nilReq, err := newTestSignedRequestV4(http.MethodDelete, getDeletePolicyURL("", nilBucket),
   770  		0, nil, "", "", nil)
   771  	if err != nil {
   772  		t.Errorf("MinIO %s: Failed to create HTTP request for testing the response when object Layer is set to `nil`.", instanceType)
   773  	}
   774  	// execute the object layer set to `nil` test.
   775  	// `ExecObjectLayerAPINilTest` manages the operation.
   776  	ExecObjectLayerAPINilTest(t, nilBucket, "", instanceType, apiRouter, nilReq)
   777  }