Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Amazon S3 Presigned URLs escape the slashes in the key

I am using the Java Amazon SDK to work with S3 for storing uploaded files. I would like to retain the original filename, and I am putting it at the end of the key, but I am also using virtual directory structure - something like <dirname>/<uuid>/<originalFilename>.

The problem is that when I want to generate a presigned URL for downloading using the api like:

URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
return url.toExternalForm();

The sdk url escapes the entire key, including the slashes. While it still works, it means that the name of the file downloaded includes the entire key instead of just the original filename bit at the end. I know that it should be possible to do this without escaping the slashes, but I'm trying to avoid rewriting a lot of the code already in the SDK. Is there a common solution to this? I know I've used web apps that follow the same pattern and do not have the slash escape problem.

like image 535
Russell Leggett Avatar asked Mar 18 '13 09:03

Russell Leggett


People also ask

How does a Presigned URL work?

A presigned URL gives you access to the object identified in the URL, provided that the creator of the presigned URL has permissions to access that object.

How do I encode a Presigned URL?

Generating pre-signed URL using : var params = { Bucket: bucket, Expires: Settings. UrlGetTimeout, Key: record }; S3. getSignedUrl('getObject', params);

Are Presigned URLs one time use?

The presigned URLs are valid only for the specified duration. If you created a presigned URL using a temporary token, then the URL expires when the token expires, even if the URL was created with a later expiration time. Anyone who receives the presigned URL can then access the object.

What is the key of an S3 object?

The object key (or key name) uniquely identifies the object in an Amazon S3 bucket. Object metadata is a set of name-value pairs. For more information about object metadata, see Working with object metadata. When you create an object, you specify the key name, which uniquely identifies the object in the bucket.


Video Answer


1 Answers

This is a bug in the current Java SDK:

If you look at https://github.com/aws/aws-sdk-java/blob/master/src/main/java/com/amazonaws/services/s3/AmazonS3Client.java#L2820

The method presignRequest which is called internally has the following code:

    String resourcePath = "/" +
        ((bucketName != null) ? bucketName + "/" : "") +
        ((key != null) ? ServiceUtils.urlEncode(key) : "") +
        ((subResource != null) ? "?" + subResource : "");

The key is URL encoded here before signing which I think is the error.

You might be able to inherit from the AmazonS3Client and override the funcion to fix this.

In some places it is suggested to use url.getQuery() and prefix this with your original awsURL (https://forums.aws.amazon.com/thread.jspa?messageID=356271). However as you said yourself this will produce an error, because the resource key will not match the signature.

The following problem might also be related, I did not check out the proposed workarround:

How to generate pre-signed Amazon S3 url for a vanity domain, using amazon sdk?

Amazon recognized and fixed a similar bug before: https://forums.aws.amazon.com/thread.jspa?messageID=418537

So I hope it will be fixed in the next version.

like image 76
aKzenT Avatar answered Sep 27 '22 15:09

aKzenT