storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/bucket-policy-handlers_test.go (about)

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