Jebil
Jebil

Reputation: 1224

s3 presigned url mandatory custom request headers

I am trying to generate a presigned url with some user data along with, as I understand I need to use custom request headers

GeneratePresignedUrlRequest generatePresignedUrlRequest =
    new GeneratePresignedUrlRequest(bucket, objectKey)
        .withMethod(httpMethod)
        .withExpiration(expiration);
if (params != null) {
  params.forEach(
      (k, v) ->
          generatePresignedUrlRequest.putCustomRequestHeader(
              Headers.S3_USER_METADATA_PREFIX + k.toLowerCase(), v));
}
return s3.generatePresignedUrl(generatePresignedUrlRequest);

Even though the consumer of generated url needs to set the headers. Is there any way we can enforce the consumer to add these headers ? eg : throw Bad Request (400) when required header (custom) is not present

Upvotes: 2

Views: 13289

Answers (2)

Wahap
Wahap

Reputation: 141

I used Parameters.Add() method to add user defined metadata. It generates presignedUrl with newly added parameter. If you use correct key it will add your parameter as metadata.

        var preSignedRequest = new GetPreSignedUrlRequest
        {
            BucketName = bucketName,
            Key = fileUpload.Key + fileUpload.FileName,
            Expires = DateTime.UtcNow.AddMinutes(15),
            Verb = HttpVerb.PUT
        };

        preSignedRequest.Parameters.Add("**x-amz-meta-processorId**", fileUpload.ProcessorId);
        string presignedUrl = _s3Client.GetPreSignedURL(preSignedRequest);

File metadata screenshot

Upvotes: 0

A.Khan
A.Khan

Reputation: 3992

Have you looked into addRequestParameter? This will add query string parameters and without those params request will be failed.

E.g.

generatePresignedUrlRequest.addRequestParameter(Headers.S3_USER_METADATA_PREFIX + "test", "true");

Generated url will contain following param:

https://aws-domain/file.ext?x-amz-meta-test=true&X-Amz-Security-Token=<TOKEN>

Update:

I've been using getSignedUrl API in Node.js to generate signed url with user metadata in query string parameters. I am not a JAVA developer which is why I suggested you to use addRequestParameter which appears to generate signed url with meta data supplied in the method.

Node.js code

const url = s3.getSignedUrl('putObject', {
  'Bucket': 'my-bucket',
  'Key': 'signed.json',
  'Metadata': {
    'my-id': '1234'
  }
});

Signed URL:

https://my-bucket.s3.eu-west-1.amazonaws.com/signed.json?AWSAccessKeyId=<AccessKey>&Expires=1549497606&Signature=<SignatureKey>&x-amz-meta-my-id=1234

Upload file:

curl -k -X PUT -T "signed.json" "https://my-bucket.s3.eu-west-1.amazonaws.com/signed.json?AWSAccessKeyId=<AccessKey>&Expires=1549497606&Signature=<SignatureKey>&x-amz-meta-my-id=1234"

User metadata:

enter image description here

Client won't need to add any headers in order to be able to add user metadata. If client attempts to modify x-amz-meta-* or remove it they will get SignatureDoesNotMatch which is exactly what you want.

Modify x-amz-meta-my-id

curl -k -X PUT -T "signed.json" "https://my-bucket.s3.eu-west-1.amazonaws.com/signed.json?AWSAccessKeyId=<AccessKey>&Expires=1549497606&Signature=<SignatureKey>&x-amz-meta-my-id=123"

Expected error:

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>AKIAJ5PO6T7F772ZPSPQ</AWSAccessKeyId>

Upvotes: 3

Related Questions