59254

Generating Amazon S3 CORS signature with Python

I'm having a hell of a time getting S3 to accept uploads via CORS POST request generated by PhoneGap (Cordova) FileTransfer.upload(). Any suggestions as to what I may be missing would be appreciated. Currently I'm getting a 403 AccessDenied response using the code below. I've been over it many times comparing with S3's documentation, and can't figure out the problem.

Here is the Python code that generates the signature:

# Create policy document for S3. policy_obj = {"expiration": "2014-01-01T00:00:00Z", "conditions": [ {"bucket": "<my.bucket.name>"}, ["starts-with", "$key", "story_"], {"acl": "public-read"}, ["eq", "$Content-Type", "audio/mp4"], ["content-length-range", str(0), str(2097152)] ] } policy = base64.b64encode(json.dumps(policy_obj)) # Create signature for S3 signature = base64.b64encode( hmac.new( key=app.config['AWS_SECRET_KEY'], msg=policy, digestmod=hashlib.sha1 ).digest() )

The signature generated by this process matches the signature produced by S3 Signature Tester (converting the base64 policy into Hex and then running that through the Signature Tester with the secret key).

The resulting policy & signature are passed to the client, and the request to S3 is built with this PhoneGap FileTransfer call:

// Upload file to Amazon S3 // r is the response object generated by Python var options = new FileUploadOptions(); options.chunkedMode = false; options.mimeType="audio/mp4"; options.fileKey='file'; options.fileName='story_' + uniqueKey + '.m4a'; options.params={ "key": "${filename}", "acl": "public-read", "AWSAccessKeyId": r.aws_access_key, "Policy": r.policy, "Signature": r.signature, }; var ft = new FileTransfer(); ft.upload(path, "http://<my.bucket.name>.s3.amazonaws.com/", uploadSuccess, uploadFail, options);

This is the CORS configuration (yes, I plan to lock it down once I get the uploads working):

<?xml version="1.0" encoding="UTF-8"?> <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedMethod>POST</AllowedMethod> <MaxAgeSeconds>3000</MaxAgeSeconds> <AllowedHeader>*</AllowedHeader> </CORSRule> </CORSConfiguration>

This is the bucket policy:

{ "Version": "2008-10-17", "Id": "Policy1356975063803", "Statement": [ { "Sid": "Stmt1357234455973", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::<my.bucket.name>/*" }, { "Sid": "Stmt1356975061658", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::293855469575:root" }, "Action": "s3:*", "Resource": "arn:aws:s3:::<my.bucket.name>" } ] }

<strong>UPDATE:</strong>

This is what the policy itself looks like after Python has converted the object into JSON:

{ "conditions": [ { "bucket": "<my.bucket.name>" }, [ "starts-with", "$key", "story_" ], { "acl": "public-read" }, [ "eq", "$Content-Type", "audio/mp4" ], [ "content-length-range", "0", "6291456" ] ], "expiration": "2014-01-01T00:00:00Z" }

Answer1:

Did you try removing newlines in your policy?

Here is the Ruby code for the policy, courtesy of s3_file_upload:

Base64.encode64(policy_data.to_json).gsub("\n", "")

Please let me know if you managed to get your upload to work, as I'm trying to do the same thing.

Recommend

  • Convert image into hexadecimal format with Python
  • “TypeError: a float is required” occurred when using urllib2
  • Python HMAC / Encoding in 3.x vs 2.x
  • What data 'structure' does fs.get_last_version return?
  • Dynamically create button using Tkinter
  • How to Correctly Run Python Script from PHP [duplicate]
  • How to autoplay video in angularjs?
  • SOAP with Attachment / MIME content
  • Implementing HMAC-SHA256 for Keybase in Javascript
  • OAuth and the YouTube API
  • Convert RSA pem key String to der byte[]
  • Serve file to user over http via php
  • Selenium to click on a javascript button corresponding to a text
  • IE11 throwing “SCRIPT1014: invalid character” where all other browsers work
  • Simulate click Geckofx vb,net
  • IE7 and TinyMCE with Plone
  • How to view images from protected folder with php?
  • Moving Android View and preventing onDraw to be called over and over again
  • Calling Worksheet functions from vba in foreign language versions of Excel
  • Parse a date string in a specific locale (not timezone!)
  • Excel's Macro-Recorder usage
  • MonoTouch: How to download pdf incrementally as indicated in the Apple slides “Building Newsstand Ap
  • How to have background script and something similar to a default popup?
  • How to attach a node.js readable stream to a Sendgrid email?
  • Listbox within Listbox and scrolling trouble in Windows Phone 7 Silverlight
  • Align navbar back button on right side
  • DotNetZip - Calculate final zip size before calling Save(stream)
  • How to handle AllServersUnavailable Exception
  • VBA Convert delimiter text file to Excel
  • Warning: Can't call setState (or forceUpdate) on an unmounted component
  • 0x202A in filename: Why?
  • retrieve vertices with no linked edge in arangodb
  • Load html files in TinyMce
  • Free memory of cv::Mat loaded using FileStorage API
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • Change div Background jquery
  • apache spark aggregate function using min value
  • Is it possible to post an object from jquery to bottle.py?
  • Reading document lines to the user (python)
  • Python/Django TangoWithDjango Models and Databases