shrinerb / shrine

File Attachment toolkit for Ruby applications

Home Page:https://shrinerb.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect S3 presigned_url when :host option passed

randaalex opened this issue · comments

Brief Description

URL with incorrect signature built for the private S3 bucket, when host option passed.

Current Shrine::Storage::S3.url implementation replaces host (line 149) after signing (line 144).
And it leads to SignatureDoesNotMatch because now the signature is invalid (checked on minio, but believe the same behavior will be on S3).
I think the host should be changed before signing.

def url(id, public: self.public, host: nil, **options)
if public || signer
url = object(id).public_url(**options)
else
url = object(id).presigned_url(:get, **options)
end
if host
uri = URI.parse(url)
uri.path = uri.path.match(/^\/#{bucket.name}/).post_match unless uri.host.include?(bucket.name)
url = URI.join(host, uri.request_uri[1..-1]).to_s
end

Thanks for reporting. Any idea how to get the AWS SDK to sign the URL with the custom host? I couldn't figure it out, nothing shows up in Google, nor can I see a way in the source code.

Ugh. It looks like maybe you're supposed to pass the hostname as the argument when you create the Bucket object, instead of the bucket name, and then pass virtual_host: true to presigned_url? That is... not nice.

https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#presigned_url-instance_method

bucket = Aws::S3::Bucket.new('my.bucket.com')
bucket.object('key').presigned_url(virtual_host: true) 
#=> "http://my.bucket.com/key?..."