Skip to content

Instantly share code, notes, and snippets.

@gigyas
Created August 7, 2018 21:42
Show Gist options
  • Save gigyas/0d4392f17e9e810da8b60935ce77fe54 to your computer and use it in GitHub Desktop.
Save gigyas/0d4392f17e9e810da8b60935ce77fe54 to your computer and use it in GitHub Desktop.
S3 Pre Signed URL with Python
import datetime
from hashlib import sha256
import hmac
import urllib.parse
class SignClient(object):
AWSAccessKeyId = ''
AWSSecretAccessKey = ''
AWSRegion = ''
def __init__(self, key_id, secret_key, region):
self.AWSAccessKeyId = key_id
self.AWSSecretAccessKey = secret_key
self.AWSRegion = region
def now(self):
return datetime.datetime.utcnow()
def sign_url(self, bucket, resource, ttl):
if not resource.startswith('/'):
resource = '/' + resource
url = '{}\n{}'.format('GET', resource)
timestamp = self.now()
scope = '{}/{}/s3/aws4_request'.format(timestamp.strftime('%Y%m%d'),
self.AWSRegion)
amz_headers = {}
amz_headers['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'
amz_headers['X-Amz-Credential'] = '{}/{}'.format(self.AWSAccessKeyId, scope)
amz_headers['X-Amz-Date'] = timestamp.strftime('%Y%m%dT%H%M%SZ')
amz_headers['X-Amz-Expires'] = ttl
amz_headers['X-Amz-SignedHeaders'] = 'host'
url = '{}\n{}\nhost:{}.s3.amazonaws.com\n\nhost\nUNSIGNED-PAYLOAD'.format(
url,
urllib.parse.urlencode(amz_headers),
bucket)
string_to_sign = 'AWS4-HMAC-SHA256\n{}\n{}\n{}'.format(timestamp.strftime('%Y%m%dT%H%M%SZ'),
scope, sha256(url.encode('utf-8')).hexdigest())
signing_key = self.__hmac_sha256(
self.__hmac_sha256(
self.__hmac_sha256(
self.__hmac_sha256(key=('AWS4' + self.AWSSecretAccessKey).encode('utf-8'), msg=timestamp.strftime('%Y%m%d').encode('utf-8')),
self.AWSRegion.encode('utf-8')
),
b's3'
),
b'aws4_request'
)
signature = hmac.new(key=signing_key, msg=string_to_sign.encode('utf-8'), digestmod=sha256).hexdigest()
amz_headers['X-Amz-Signature'] = signature
signed_url = 'https://{bucket}.s3.amazonaws.com/{resource}?{query}'.format(bucket=bucket,
resource=resource[1:], query=urllib.parse.urlencode(amz_headers))
return signed_url
def __hmac_sha256(self, key, msg):
return hmac.new(key, msg, digestmod=sha256).digest()
import datetime
import pytest
import sign
canonical_url = '''GET
/test.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
host:examplebucket.s3.amazonaws.com
host
UNSIGNED-PAYLOAD'''
string_to_sign = '''AWS4-HMAC-SHA256
20130524T000000Z
20130524/us-east-1/s3/aws4_request
3bfa292879f6447bbcda7001decf97f4a54dc650c8942174ae0a9121cf58ad04'''
signature = 'aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404'
presigned_url = 'https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404'
@pytest.fixture
def client():
client = sign.SignClient('AKIAIOSFODNN7EXAMPLE', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', 'us-east-1')
return client
def test_sign_url(client, mocker):
mocker.patch('sign.SignClient.now', return_value=datetime.datetime(2013, 5, 24, 0, 0, 0))
print(datetime.datetime.utcnow())
url = client.sign_url('examplebucket', 'test.txt', 86400)
assert(url == presigned_url)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment