From d547873b179d10d0bd34ea4e83f5ee544099ef34 Mon Sep 17 00:00:00 2001 From: poornas Date: Fri, 24 Aug 2018 07:56:24 -0700 Subject: [PATCH] webhandler - display encryption errors properly (#6339) For encrypted objects, download errors need to be displayed in web response format instead of xml format. Fixes #6327 --- cmd/encryption-v1.go | 19 +++++++++---------- cmd/encryption-v1_test.go | 16 ++++++++-------- cmd/object-handlers.go | 10 +++++----- cmd/web-handlers.go | 14 ++++++++++---- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/cmd/encryption-v1.go b/cmd/encryption-v1.go index 1d87d4886..f822d6d50 100644 --- a/cmd/encryption-v1.go +++ b/cmd/encryption-v1.go @@ -43,6 +43,8 @@ var ( errKMSNotConfigured = errors.New("KMS not configured for a server side encrypted object") // Additional Minio errors for SSE-C requests. errObjectTampered = errors.New("The requested object was modified and may be compromised") + // error returned when invalid encryption parameters are specified + errInvalidEncryptionParameters = errors.New("The encryption parameters are not applicable to this object") ) const ( @@ -714,28 +716,25 @@ func DecryptCopyObjectInfo(info *ObjectInfo, headers http.Header) (apiErr APIErr // decryption succeeded. // // DecryptObjectInfo also returns whether the object is encrypted or not. -func DecryptObjectInfo(info *ObjectInfo, headers http.Header) (apiErr APIErrorCode, encrypted bool) { +func DecryptObjectInfo(info *ObjectInfo, headers http.Header) (encrypted bool, err error) { // Directories are never encrypted. if info.IsDir { - return ErrNone, false + return false, nil } // disallow X-Amz-Server-Side-Encryption header on HEAD and GET if crypto.S3.IsRequested(headers) { - apiErr = ErrInvalidEncryptionParameters + err = errInvalidEncryptionParameters return } - if apiErr, encrypted = ErrNone, crypto.IsEncrypted(info.UserDefined); !encrypted && crypto.SSEC.IsRequested(headers) { - apiErr = ErrInvalidEncryptionParameters + if err, encrypted = nil, crypto.IsEncrypted(info.UserDefined); !encrypted && crypto.SSEC.IsRequested(headers) { + err = errInvalidEncryptionParameters } else if encrypted { if (crypto.SSEC.IsEncrypted(info.UserDefined) && !crypto.SSEC.IsRequested(headers)) || (crypto.S3.IsEncrypted(info.UserDefined) && crypto.SSEC.IsRequested(headers)) { - apiErr = ErrSSEEncryptedObject + err = errEncryptedObject return } - var err error - if info.Size, err = info.DecryptedSize(); err != nil { - apiErr = toAPIErrorCode(err) - } + info.Size, err = info.DecryptedSize() } return } diff --git a/cmd/encryption-v1_test.go b/cmd/encryption-v1_test.go index ec97e439a..57c6b9ff1 100644 --- a/cmd/encryption-v1_test.go +++ b/cmd/encryption-v1_test.go @@ -521,43 +521,43 @@ func TestDecryptRequest(t *testing.T) { var decryptObjectInfoTests = []struct { info ObjectInfo headers http.Header - expErr APIErrorCode + expErr error }{ { info: ObjectInfo{Size: 100}, headers: http.Header{}, - expErr: ErrNone, + expErr: nil, }, { info: ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256}}, headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, - expErr: ErrNone, + expErr: nil, }, { info: ObjectInfo{Size: 0, UserDefined: map[string]string{crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256}}, headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, - expErr: ErrNone, + expErr: nil, }, { info: ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.SSECSealedKey: "EAAfAAAAAAD7v1hQq3PFRUHsItalxmrJqrOq6FwnbXNarxOOpb8jTWONPPKyM3Gfjkjyj6NCf+aB/VpHCLCTBA=="}}, headers: http.Header{}, - expErr: ErrSSEEncryptedObject, + expErr: errEncryptedObject, }, { info: ObjectInfo{Size: 100, UserDefined: map[string]string{}}, headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, - expErr: ErrInvalidEncryptionParameters, + expErr: errInvalidEncryptionParameters, }, { info: ObjectInfo{Size: 31, UserDefined: map[string]string{crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256}}, headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, - expErr: ErrObjectTampered, + expErr: errObjectTampered, }, } func TestDecryptObjectInfo(t *testing.T) { for i, test := range decryptObjectInfoTests { - if err, encrypted := DecryptObjectInfo(&test.info, test.headers); err != test.expErr { + if encrypted, err := DecryptObjectInfo(&test.info, test.headers); err != test.expErr { t.Errorf("Test %d: Decryption returned wrong error code: got %d , want %d", i, err, test.expErr) } else if enc := crypto.IsEncrypted(test.info.UserDefined); encrypted && enc != encrypted { t.Errorf("Test %d: Decryption thinks object is encrypted but it is not", i) diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 4f7f111c1..56497713b 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -306,8 +306,8 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req } if objectAPI.IsEncryptionSupported() { - if apiErr, _ := DecryptObjectInfo(&objInfo, r.Header); apiErr != ErrNone { - writeErrorResponse(w, apiErr, r.URL) + if _, err = DecryptObjectInfo(&objInfo, r.Header); err != nil { + writeErrorResponse(w, toAPIErrorCode(err), r.URL) return } } @@ -468,10 +468,10 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re writeErrorResponseHeadersOnly(w, toAPIErrorCode(err)) return } - + var encrypted bool if objectAPI.IsEncryptionSupported() { - if apiErr, encrypted := DecryptObjectInfo(&objInfo, r.Header); apiErr != ErrNone { - writeErrorResponse(w, apiErr, r.URL) + if encrypted, err = DecryptObjectInfo(&objInfo, r.Header); err != nil { + writeErrorResponse(w, toAPIErrorCode(err), r.URL) return } else if encrypted { s3Encrypted := crypto.S3.IsEncrypted(objInfo.UserDefined) diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index b101f2d6f..324e932cb 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -715,8 +715,8 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) { } if objectAPI.IsEncryptionSupported() { - if apiErr, _ := DecryptObjectInfo(&objInfo, r.Header); apiErr != ErrNone { - writeErrorResponse(w, apiErr, r.URL) + if _, err = DecryptObjectInfo(&objInfo, r.Header); err != nil { + writeWebErrorResponse(w, err) return } } @@ -818,8 +818,8 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) { return err } if objectAPI.IsEncryptionSupported() { - if apiErr, _ := DecryptObjectInfo(&info, r.Header); apiErr != ErrNone { - writeErrorResponse(w, apiErr, r.URL) + if _, err = DecryptObjectInfo(&info, r.Header); err != nil { + writeWebErrorResponse(w, err) return err } } @@ -1235,6 +1235,12 @@ func toWebAPIError(err error) APIError { HTTPStatusCode: http.StatusBadRequest, Description: err.Error(), } + } else if err == errEncryptedObject { + return getAPIError(ErrSSEEncryptedObject) + } else if err == errInvalidEncryptionParameters { + return getAPIError(ErrInvalidEncryptionParameters) + } else if err == errObjectTampered { + return getAPIError(ErrObjectTampered) } else if err == errMethodNotAllowed { return getAPIError(ErrMethodNotAllowed) }