From 859f81fb5dd69b804a4343a0d2e7fd480201f002 Mon Sep 17 00:00:00 2001 From: niksis02 Date: Fri, 11 Sep 2026 16:40:51 +0400 Subject: [PATCH] fix: map azure `AuthorizationPermissionMismatch` to `AccessDenied` 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`. --- backend/azure/err.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/azure/err.go b/backend/azure/err.go index 932209e6..ec4d4f97 100644 --- a/backend/azure/err.go +++ b/backend/azure/err.go @@ -43,6 +43,8 @@ func azErrToS3err(azErr *azcore.ResponseError) s3err.APIError { 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, @@ -55,9 +57,16 @@ func parseMpError(mpErr error) error { err := azureErrToS3Err(mpErr) serr, ok := err.(s3err.APIError) - if !ok || serr.Code != "NoSuchKey" { + if !ok { return mpErr } - return s3err.GetAPIError(s3err.ErrNoSuchUpload) + switch serr.Code { + case "NoSuchKey": + return s3err.GetAPIError(s3err.ErrNoSuchUpload) + case "AccessDenied": + return serr + } + + return mpErr }