Provide 200 response with per object error listing on access denied for delete multiple object request (#4817)

This commit is contained in:
wd256 2017-08-16 05:49:31 +10:00 committed by Dee Koder
parent a2f2044528
commit 3d21119ec8
2 changed files with 53 additions and 9 deletions

View File

@ -240,9 +240,14 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
return return
} }
if s3Error := checkRequestAuthType(r, bucket, "s3:DeleteObject", serverConfig.GetRegion()); s3Error != ErrNone { var authError APIErrorCode
writeErrorResponse(w, s3Error, r.URL) if authError = checkRequestAuthType(r, bucket, "s3:DeleteObject", serverConfig.GetRegion()); authError != ErrNone {
return // In the event access is denied, a 200 response should still be returned
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
if authError != ErrAccessDenied {
writeErrorResponse(w, authError, r.URL)
return
}
} }
// Content-Length is required and should be non-zero // Content-Length is required and should be non-zero
@ -284,10 +289,19 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
for index, object := range deleteObjects.Objects { for index, object := range deleteObjects.Objects {
wg.Add(1) wg.Add(1)
go func(i int, obj ObjectIdentifier) { go func(i int, obj ObjectIdentifier) {
defer wg.Done()
// If the request is denied access, each item
// should be marked as 'AccessDenied'
if authError == ErrAccessDenied {
dErrs[i] = PrefixAccessDenied{
Bucket: bucket,
Object: obj.ObjectName,
}
return
}
objectLock := globalNSMutex.NewNSLock(bucket, obj.ObjectName) objectLock := globalNSMutex.NewNSLock(bucket, obj.ObjectName)
objectLock.Lock() objectLock.Lock()
defer objectLock.Unlock() defer objectLock.Unlock()
defer wg.Done()
dErr := objectAPI.DeleteObject(bucket, obj.ObjectName) dErr := objectAPI.DeleteObject(bucket, obj.ObjectName)
if dErr != nil { if dErr != nil {

View File

@ -650,6 +650,17 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa
return objectIdentifierList return objectIdentifierList
} }
getDeleteErrorList := func(objects []ObjectIdentifier) (deleteErrorList []DeleteError) {
for _, obj := range objects {
deleteErrorList = append(deleteErrorList, DeleteError{
Code: errorCodeResponse[ErrAccessDenied].Code,
Message: errorCodeResponse[ErrAccessDenied].Description,
Key: obj.ObjectName,
})
}
return deleteErrorList
}
requestList := []DeleteObjectsRequest{ requestList := []DeleteObjectsRequest{
{Quiet: false, Objects: getObjectIdentifierList(objectNames[:5])}, {Quiet: false, Objects: getObjectIdentifierList(objectNames[:5])},
@ -670,6 +681,10 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa
errorResponse := generateMultiDeleteResponse(requestList[1].Quiet, requestList[1].Objects, nil) errorResponse := generateMultiDeleteResponse(requestList[1].Quiet, requestList[1].Objects, nil)
encodedErrorResponse := encodeResponse(errorResponse) encodedErrorResponse := encodeResponse(errorResponse)
anonRequest := encodeResponse(requestList[0])
anonResponse := generateMultiDeleteResponse(requestList[0].Quiet, nil, getDeleteErrorList(requestList[0].Objects))
encodedAnonResponse := encodeResponse(anonResponse)
testCases := []struct { testCases := []struct {
bucket string bucket string
objects []byte objects []byte
@ -718,15 +733,32 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa
expectedContent: encodedErrorResponse, expectedContent: encodedErrorResponse,
expectedRespStatus: http.StatusOK, expectedRespStatus: http.StatusOK,
}, },
// Test case - 5.
// Anonymous user access denied response
// Currently anonymous users cannot delete multiple objects in Minio server
{
bucket: bucketName,
objects: anonRequest,
accessKey: "",
secretKey: "",
expectedContent: encodedAnonResponse,
expectedRespStatus: http.StatusOK,
},
} }
for i, testCase := range testCases { for i, testCase := range testCases {
var req *http.Request var req *http.Request
var actualContent []byte var actualContent []byte
// Indicating that all parts are uploaded and initiating completeMultipartUpload. // Generate a signed or anonymous request based on the testCase
req, err = newTestSignedRequestV4("POST", getDeleteMultipleObjectsURL("", bucketName), if testCase.accessKey != "" {
int64(len(testCase.objects)), bytes.NewReader(testCase.objects), testCase.accessKey, testCase.secretKey) req, err = newTestSignedRequestV4("POST", getDeleteMultipleObjectsURL("", bucketName),
int64(len(testCase.objects)), bytes.NewReader(testCase.objects), testCase.accessKey, testCase.secretKey)
} else {
req, err = newTestRequest("POST", getDeleteMultipleObjectsURL("", bucketName),
int64(len(testCase.objects)), bytes.NewReader(testCase.objects))
}
if err != nil { if err != nil {
t.Fatalf("Failed to create HTTP request for DeleteMultipleObjects: <ERROR> %v", err) t.Fatalf("Failed to create HTTP request for DeleteMultipleObjects: <ERROR> %v", err)
} }
@ -753,8 +785,6 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa
} }
} }
// Currently anonymous user cannot delete multiple objects in Minio server, hence no test case is required.
// HTTP request to test the case of `objectLayer` being set to `nil`. // HTTP request to test the case of `objectLayer` being set to `nil`.
// There is no need to use an existing bucket or valid input for creating the request, // There is no need to use an existing bucket or valid input for creating the request,
// since the `objectLayer==nil` check is performed before any other checks inside the handlers. // since the `objectLayer==nil` check is performed before any other checks inside the handlers.