Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Policy and Signature issues for a rails post form to s3 upload

I'm attempting to follow this "how-to" (form POST to S3 bucket) and appear to be failing on my policy and signature.

I'm not so sure my policy and signature are wrong? But I do know I'm having an issue evaluating the methods I've created in my helper. I've tried converting the Policy & signature values to symbols <%= :S3_UPLOAD_SIGNATURE %> and I've tried <%=h, <%=raw, "#{<%=..}".

I've called helper methods before with no issues so I'm a bit lost.

the error:

NameError in Proj_files#new

Showing /app/views/proj_files/new.html.erb where line #8 raised:

uninitialized constant ActionView::CompiledTemplates::S3_UPLOAD_POLICY
Extracted source (around line #8):

5:       <input type="hidden" name="AWSAccessKeyId" value= <%= ENV['AWS_ACCESS_KEY_ID'] %> > 
6:       <input type="hidden" name="acl" value="private"> 
7:       <input type="hidden" name="success_action_redirect" value="http://localhost/">
8:       <input type="hidden" name="policy" value= <%= S3_UPLOAD_POLICY %> >
9:       <input type="hidden" name="signature" value= <%= S3_UPLOAD_SIGNATURE %> >
10:       <input type="hidden" name="Content-Type" value="image/png">
11:       <!-- Include any additional input fields here -->

I have a proj_files controller with a corresponding new.html.erb:

<form action="https://s3.amazonaws.com/MY_BUCKET" method="post" enctype="multipart/form-data">
  <input type="hidden" name="key" value="uploads/${filename}">
  <input type="hidden" name="AWSAccessKeyId" value= <%= ENV['AWS_ACCESS_KEY_ID'] %> > 
  <input type="hidden" name="acl" value="private"> 
  <input type="hidden" name="success_action_redirect" value="http://localhost/">
  <input type="hidden" name="policy" value= <%= S3_UPLOAD_POLICY %> >
  <input type="hidden" name="signature" value= <%= S3_UPLOAD_SIGNATURE %> >
  <input type="hidden" name="Content-Type" value="image/png">
  <!-- Include any additional input fields here -->

  File to upload to S3: 
  <input name="file" type="file"> 
  <br> 
  <input type="submit" value="Upload File to S3"> 
</form> 

and the proj_files_helper.rb:

module ProjFilesHelper

  def S3_UPLOAD_POLICY options = {}
    options[:content_type] ||= ''
    options[:acl] ||= 'private'
    options[:max_file_size] ||= 500.megabyte
    options[:path] ||= ''

    Base64.encode64(
      "{'expiration': '#{10.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')}',
        'conditions': [
          {'bucket': '#{ENV['S3_BUCKET']}'},
          ['starts-with', '$key', ''],
          {'acl': '#{options[:acl]}'},
          {'success_action_status': '201'},
          ['content-length-range', 0, #{options[:max_file_size]}],
          ['starts-with','$Content-Type','']
        ]
    }").gsub(/\n|\r/, '')
  end


  def S3_UPLOAD_SIGNATURE options = {}
    Base64.encode64(
      OpenSSL::HMAC.digest(
      OpenSSL::Digest::Digest.new('sha1'),
      ENV['AWS_SECRET_ACCESS_KEY'], s3_policy(options))).gsub("\n","")
  end

end

Thanks for taking a look!

UPDATE: I changed the method names to lower case and that got me a bit further (I should have realized that!).

Now I get an S3 error:

<Error>
<Code>AccessDenied</Code>
<Message>
Invalid according to Policy: Policy Condition failed: ["eq", "$bucket", "MY_BUCKETS_NAME"]
</Message>

Seems like there may be an ENV variable $bucket bad reference i'll look for... "MY_BUCKETS_NAME" did display the proper buckets name....If anyone can offer any help on getting rails post form to S3 up and running / point out my errors I'd appreciate it.

Thanks

UPDATE2 Per comment below I modified my form action to "https://s3.amazonaws.com/MY_BUCKET" and received this error:

Invalid according to Policy: Policy Condition failed: ["eq", "$acl", "public-read"]

Getting close... Thanks!

UPDATE3 I'm fighting the fight!

I've modified the policy and form ACL to have same consistent value (private or public-read).

Comments below led me to modifying form action to: http://MY_BUCKET.s3.amazonaws.com/ I get this error:

<Code>AccessDenied</Code>
<Message>
Invalid according to Policy: Policy Condition failed: ["eq", "$success_action_status", "201"]
</Message>

Oddly enough when I go to AWS S3 management console and upload a file to my bucket, it tells me the link is of the `http://s3.amazonaws.com/MY_BUCKET' form. I've added MY_BUCKET before and after amazonaws and still received same error...

I'm not sure where there mis-configuration is occurring... I'm going to create a new bucket and see if I setup wrong....

Thanks!

IT WORKS NOW!!! I fixed everything from answer... but then had to make one more change...

My form had a "success_action_redirect" field but my policy had a success_action_status!

Policy and form fields must match! DUH!

Thanks for all the help... time to tweak it a bit further!

like image 357
twinturbotom Avatar asked Dec 26 '12 21:12

twinturbotom


2 Answers

1/ To upload the file you must use this url "http://#{bucket_name}.s3.amazonaws.com/". It's clearly stated in the documentation:

The action defines the URL that will process the request; this must be set to the bucket's URL. For example, if your bucket's name is "johnsmith", then the URL would be "http://johnsmith.s3.amazonaws.com/"

2/ You must have consistent policy, seems you set public-read in the signature and private in the form.

like image 135
apneadiving Avatar answered Oct 22 '22 18:10

apneadiving


I was getting the following error: Invalid according to Policy: Policy Condition failed: [\"eq\", \"$bucket\"

After many hours, I learned that you can't have a bucket with uppercase letters. Changing the bucket to lowercase fixed it.

like image 34
Daniel Roizman Avatar answered Oct 22 '22 18:10

Daniel Roizman