简体   繁体   中英

Uploading to AWS S3 using a presigned URL in Ruby on Rails

I need to upload files to S3 from a machine that must have its clock set incorrectly, and the offset from the correct time will vary. You can apparently do this by specifying the X-Amz-Date header (setting it to the current actual time) and uploading using query string authorization. The aws-sdk Ruby gem does not expose this parameter in its presigned_url method, so I'm trying to do it using the aws-sigv4 gem. My PUT s, however, are being rejected with 403 Unauthorized errors.

Here is the code I've tried:

def upload_file_with_time(file, file_path, expires_in_seconds, time)
  region = "us-east-1"
  access_key_id = ENV['AWS_ACCESS_KEY_ID']
  secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']

  obj = s3_bucket.object(file_path)

  signer = Aws::Sigv4::Signer.new(
    service: 's3',
    region: region,
    access_key_id: access_key_id,
    secret_access_key: secret_access_key
  )

  pre_signed_url = signer.presign_url(
    http_method: 'PUT',
    url: obj.public_url,
    expires_in: expires_in_seconds,
    time: time
  )

  Net::HTTP.start(pre_signed_url.host) do |http|
    http.send_request("PUT", pre_signed_url.request_uri, file, "content-type": "")
  end
end

The code generates a presigned URL like this:

https://XXXXX.s3.amazonaws.com/testing/89254661-24de-4bc7-b6e1-7d0018213735.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXX%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190301T213824Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=XXXXX (sensitive information has been redacted with XXXXX ).

I get a 403 Unauthorized from http.send_request when I try to upload to this endpoint. If I hit the URL with a post from curl , I see this as the beginning of the XML response:

<?xml version=“1.0”?>
<Error>
 <Code>SignatureDoesNotMatch</Code>
 <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>

What am I doing wrong?

I need to upload files to S3 from a machine that must have its clock set incorrectly.

Is the time in past or future? Though the possibility is miniscule, this might be causing issues (nothing in the docs indicates the same though).

However, I see that you are using the Net::HTTP package and making a raw PUT request and the method you are using for generating the presigned URL does not look very convincing to me because of the obj.public_url thing.

Anyways, I did have a requirement like this (presigned URL upload but without the 'incorrect time on the machine' part). This is the guide I used and it worked:

https://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjectPreSignedURLRubySDK.html

There is a working code on that page (not pasting it here because it might change in future) which worked for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM