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 }