mirror of
https://github.com/versity/versitygw.git
synced 2026-09-23 08:24:17 +00:00
Originated from #2302 When the Azure credential is valid but its RBAC role does not grant a data action, Azure answers with `403 AuthorizationPermissionMismatch`. This code had no mapping, so the gateway returned `500 InternalError` to the S3 client. A common case is `CompleteMultipartUpload` under a managed identity with `Storage Blob Data Contributor`: the Get Blob Tags call on the `.sgwtmp` multipart staging blob needs `blobs/tags/read`, which that role does not include. `azErrToS3err` now maps `AuthorizationPermissionMismatch` to `AccessDenied`. `parseMpError` used to return the raw Azure error for every code except `NoSuchKey`, so the new mapping never reached the multipart paths. It now also passes `AccessDenied` through, and the client gets a `403 AccessDenied` instead of a `500 InternalError`.
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
// Copyright 2023 Versity Software
|
|
// This file is licensed under the Apache License, Version 2.0
|
|
// (the "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package azure
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
|
"github.com/versity/versitygw/s3err"
|
|
)
|
|
|
|
// Parses azure ResponseError into AWS APIError
|
|
func azureErrToS3Err(apiErr error) error {
|
|
var azErr *azcore.ResponseError
|
|
if !errors.As(apiErr, &azErr) {
|
|
return apiErr
|
|
}
|
|
|
|
return azErrToS3err(azErr)
|
|
}
|
|
|
|
func azErrToS3err(azErr *azcore.ResponseError) s3err.APIError {
|
|
switch azErr.ErrorCode {
|
|
case "ContainerAlreadyExists":
|
|
return s3err.GetAPIError(s3err.ErrBucketAlreadyExists)
|
|
case "InvalidResourceName", "ContainerNotFound":
|
|
return s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
|
case "BlobNotFound":
|
|
return s3err.GetAPIError(s3err.ErrNoSuchKey)
|
|
case "TagsTooLarge":
|
|
return s3err.GetAPIError(s3err.ErrInvalidTagValue)
|
|
case "Requested Range Not Satisfiable":
|
|
return s3err.GetAPIError(s3err.ErrInvalidRange)
|
|
case "AuthorizationPermissionMismatch":
|
|
return s3err.GetAPIError(s3err.ErrAccessDenied)
|
|
}
|
|
return s3err.APIError{
|
|
Code: azErr.ErrorCode,
|
|
Description: azErr.RawResponse.Status,
|
|
HTTPStatusCode: azErr.StatusCode,
|
|
}
|
|
}
|
|
|
|
func parseMpError(mpErr error) error {
|
|
err := azureErrToS3Err(mpErr)
|
|
|
|
serr, ok := err.(s3err.APIError)
|
|
if !ok {
|
|
return mpErr
|
|
}
|
|
|
|
switch serr.Code {
|
|
case "NoSuchKey":
|
|
return s3err.GetAPIError(s3err.ErrNoSuchUpload)
|
|
case "AccessDenied":
|
|
return serr
|
|
}
|
|
|
|
return mpErr
|
|
}
|