diff --git a/src/DIRAC/DataManagementSystem/Service/S3GatewayHandler.py b/src/DIRAC/DataManagementSystem/Service/S3GatewayHandler.py index fde22548d77..5f80b9d1355 100644 --- a/src/DIRAC/DataManagementSystem/Service/S3GatewayHandler.py +++ b/src/DIRAC/DataManagementSystem/Service/S3GatewayHandler.py @@ -151,9 +151,9 @@ def export_createPresignedUrl(self, storageName, s3_method, urls, expiration): failed[url] = "Permission denied" continue - res = returnSingleResult( - s3Plugin.createPresignedUrl({url: urls.get("Fields")}, s3_method, expiration=expiration) - ) + # For put_object, urls maps each url to the fields (metadata) of the file + fields = urls[url] if s3_method == "put_object" else None + res = returnSingleResult(s3Plugin.createPresignedUrl({url: fields}, s3_method, expiration=expiration)) log.debug(f"Presigned URL for {url}: {res}") if res["OK"]: diff --git a/src/DIRAC/Resources/Storage/S3Storage.py b/src/DIRAC/Resources/Storage/S3Storage.py index 5826b31c5ad..b904c4f18cc 100644 --- a/src/DIRAC/Resources/Storage/S3Storage.py +++ b/src/DIRAC/Resources/Storage/S3Storage.py @@ -268,7 +268,8 @@ def _presigned_exists(self, urls): # and perform it with requests for url, presignedURL in presignedURLs.items(): try: - response = requests.get(presignedURL) + # The URL is signed for head_object so it must be used with HEAD + response = requests.head(presignedURL) if response.status_code == 200: successful[url] = True elif response.status_code == 404: # not found @@ -768,8 +769,10 @@ def createPresignedUrl(self, urls, s3_method, expiration=3600): fields = keys.get(key) if not isinstance(fields, dict): fields = None + # boto does not add the fields to the policy, without which S3 rejects them + conditions = [{k: v} for k, v in fields.items()] if fields else None response = self.s3_client.generate_presigned_post( - self.bucketName, key, Fields=fields, ExpiresIn=expiration + self.bucketName, key, Fields=fields, Conditions=conditions, ExpiresIn=expiration ) successful[key] = response