1+ #
2+ import datetime
3+ import hashlib
4+ import hmac
5+ import requests
6+ from requests .utils import quote
7+
8+ def generate_aws_signed_url (region , bucket , object_key , access_key , secret_key , expiration , endpoint = None ):
9+
10+ # request elements
11+ http_method = 'GET'
12+ endpoint = endpoint if endpoint else 's3.amazonaws.com'
13+ host = bucket + '.' + endpoint
14+ endpoint = 'https://' + host
15+
16+ # hashing methods
17+ def hash (key , msg ):
18+ return hmac .new (key , msg .encode ('utf-8' ), hashlib .sha256 ).digest ()
19+
20+ # region is a wildcard value that takes the place of the AWS region value
21+ # as COS doen't use regions like AWS, this parameter can accept any string
22+ def createSignatureKey (key , datestamp , region , service ):
23+ keyDate = hash (('AWS4' + key ).encode ('utf-8' ), datestamp )
24+ keyRegion = hash (keyDate , region )
25+ keyService = hash (keyRegion , service )
26+ keySigning = hash (keyService , 'aws4_request' )
27+ return keySigning
28+
29+ # assemble the standardized request
30+ time = datetime .datetime .utcnow ()
31+ timestamp = time .strftime ('%Y%m%dT%H%M%SZ' )
32+ datestamp = time .strftime ('%Y%m%d' )
33+
34+ standardized_querystring = ('X-Amz-Algorithm=AWS4-HMAC-SHA256' +
35+ '&X-Amz-Credential=' + access_key + '/' + datestamp + '/' + region + '/s3/aws4_request' +
36+ '&X-Amz-Date=' + timestamp +
37+ '&X-Amz-Expires=' + str (expiration ) +
38+ '&X-Amz-SignedHeaders=host' )
39+ standardized_querystring_url_encoded = quote (standardized_querystring , safe = '&=' )
40+
41+ standardized_resource = '/' + object_key
42+ standardized_resource_url_encoded = quote (standardized_resource , safe = '&' )
43+
44+ payload_hash = 'UNSIGNED-PAYLOAD'
45+ standardized_headers = 'host:' + host
46+ signed_headers = 'host'
47+
48+ standardized_request = (http_method + '\n ' +
49+ standardized_resource + '\n ' +
50+ standardized_querystring_url_encoded + '\n ' +
51+ standardized_headers + '\n ' +
52+ '\n ' +
53+ signed_headers + '\n ' +
54+ payload_hash ).encode ('utf-8' )
55+
56+ # assemble string-to-sign
57+ hashing_algorithm = 'AWS4-HMAC-SHA256'
58+ credential_scope = datestamp + '/' + region + '/' + 's3' + '/' + 'aws4_request'
59+ sts = (hashing_algorithm + '\n ' +
60+ timestamp + '\n ' +
61+ credential_scope + '\n ' +
62+ hashlib .sha256 (standardized_request ).hexdigest ())
63+
64+ # generate the signature
65+ signature_key = createSignatureKey (secret_key , datestamp , region , 's3' )
66+ signature = hmac .new (signature_key ,
67+ (sts ).encode ('utf-8' ),
68+ hashlib .sha256 ).hexdigest ()
69+
70+ # create and send the request
71+ # the 'requests' package autmatically adds the required 'host' header
72+ request_url = (endpoint + '/' +
73+ object_key + '?' +
74+ standardized_querystring_url_encoded +
75+ '&X-Amz-Signature=' +
76+ signature )
77+
78+ def hex_hash (key , msg ):
79+ return hmac .new (b'key' , msg .encode ('utf-8' ), hashlib .sha256 ).hexdigest ()
80+
81+ def createHexSignatureKey (key , datestamp , region , service ):
82+ keyDate = hex_hash (('AWS4' + key ).encode ('utf-8' ), datestamp )
83+ keyRegion = hex_hash (keyDate , region )
84+ keyService = hex_hash (keyRegion , service )
85+ keySigning = hex_hash (keyService , 'aws4_request' )
86+ return keySigning
87+
88+ signature_key_hex = createHexSignatureKey (secret_key , datestamp , region , 's3' )
89+
90+ # print(request_url)
91+ return request_url
0 commit comments