Skip to content

Instantly share code, notes, and snippets.

@ruiwen
Last active December 19, 2015 14:59
Show Gist options
  • Save ruiwen/5972909 to your computer and use it in GitHub Desktop.
Save ruiwen/5972909 to your computer and use it in GitHub Desktop.
Self Signed S3 REST API Request
import boto
import os
import base64
import hashlib
import requests
import datetime
import hmac
sts_conn = boto.connect_sts(AWS_ACCESS_KEY, AWS_SECRET_KEY)
s3_policy ='''{
"Statement": [
{
"Sid": "AllowOnlyPutToBucket",
"Action": ["s3:PutObject"],
"Effect": "Allow",
"Resource": "arn:aws:s3:::bp-%(bucket_name)s/%(wrapper_id)s/*"
},
{
"Sid": "AllowOnlyDeleteToBucket",
"Action": ["s3:DeleteObject"],
"Effect": "Allow",
"Resource": "arn:aws:s3:::bp-%(bucket_name)s/%(wrapper_id)s/*"
}
]
}'''
data = {
"bucket_name": "usermedia",
"wrapper_id": "abc123"
}
ft = sts_conn.get_federation_token(name=data['wrapper_id'], policy=s3_policy % data, duration=3600)
creds = ft.credentials
print "Credentials obtained"
print "Clients should implement the process below this line"
print "#" * 30
print "\n\n"
# Assuming we want to PUT a file of name 'img_thumb.jpg'
filename = "img_thumb.jpg"
f = open(filename, "rb")
upload_name = "%s/%s_%s" % (data['wrapper_id'], hashlib.new("sha1", "%s%s" % (datetime.datetime.utcnow().isoformat(), data['wrapper_id'])).hexdigest(), filename)
print "Upload name: %s" % upload_name
# Certain assumptions
content_type = "image/jpeg"
content_md5 = base64.b64encode(hashlib.new("md5", f.read()).digest())
f.seek(0)
# Headers
headers = {
'Host': 'bp-%s.s3.amazonaws.com' % data['bucket_name'],
'Date': (datetime.datetime.utcnow()).strftime("%a, %d %b %Y %H:%M:%S +0000"),
'Content-MD5': content_md5,
'Content-Type': content_type,
'Content-Length': os.fstat(f.fileno()).st_size, # Get file size
'x-amz-meta-uploadedby': data['wrapper_id'],
'x-amz-meta-transaction': "txn01",
'x-amz-security-token': creds.session_token,
'x-amz-meta-agent': "Test/0.0.1/Code",
'x-amz-server-side-encryption': 'AES256'
}
# CanonicalizedResource Element
# /<bucket_name>/<file_name.ext>
canonicalized_resource = "/bp-%s/%s" % (data['bucket_name'], upload_name)
# CanonicalizedAmzHeaders
prepped_headers = {}
for h in headers:
if not h.lower().startswith("x-amz"):
continue
hl = h.lower()
prepped_headers[hl] = prepped_headers[hl] + "," + headers[h] if hl in prepped_headers else headers[h]
header_names = map(lambda x: x.lower(), prepped_headers.keys())
header_names.sort()
canonicalized_amz_headers = ["%s:%s" % (h, prepped_headers[h]) for h in header_names]
canonicalized_amz_headers = u"\u000a".join(canonicalized_amz_headers)
# StringToSign = HTTP-Verb + "\n" +
# Content-MD5 + "\n" +
# Content-Type + "\n" +
# Date + "\n" +
# CanonicalizedAmzHeaders +
# CanonicalizedResource;
items_to_sign = [
"PUT",
content_md5,
content_type,
headers['Date'],
canonicalized_amz_headers,
canonicalized_resource
]
string_to_sign = u'\u000a'.join(items_to_sign)
print string_to_sign
# Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) );
signature = base64.b64encode(hmac.new(creds.secret_key.encode("utf-8"), string_to_sign.encode("utf-8"), hashlib.sha1).digest())
# Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
auth_header = "AWS %s:%s" % (creds.access_key, signature)
print "Authorization: %s" % auth_header
print "Making the PUT"
headers['Authorization'] = auth_header
f.seek(0)
r = requests.put('https://bp-%s.s3.amazonaws.com/%s' % (data['bucket_name'], upload_name), data=f, headers=headers)
print r.headers
print r.status_code
print r.text
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment