2017-10-17 17 views
0

J'utilise le code suivant pour faire une simple demande de PUT à AWS S3 en utilisant une signature version 4:Ce que je fais de mal à S3 demande PUT utilisant AWS Signature Version 4

from collections import OrderedDict 
from dateutil import parser 
import datetime 
import hashlib 
import hmac 
import requests 

key_id = "REDACTED" 
secret = "REDACTED" 
bucket_name = "REDACTED" 

def hashb16(message): 
    return hashlib.sha256(message).hexdigest() 

def HMAC(key, message): 
    return hmac.new(key, message, hashlib.sha256) 

current_time = datetime.datetime.utcnow() 

url = "https://s3-eu-west-2.amazonaws.com/{}/sometest.txt".format(bucket_name) 
payload = "Welcome to Amazon S3." 
headers = { 
    'date': current_time.strftime("%a, %d %b %Y %H:%m:%S GMT"), 
    'host': "s3-eu-west-2.amazonaws.com", 
    'x-amz-content-sha256': hashb16(payload), 
    'x-amz-date': current_time.strftime('%Y%m%dT%H%M%SZ'), 
    'x-amz-storage-class': 'REDUCED_REDUNDANCY' 
} 
sorted_headers = sorted([k for k in headers]) 
region = "eu-west-2" 
service = "s3" 

# step 1 
HTTPRequestMethod = "PUT" 
CanonicalURI = "/sometest.txt" 
CanonicalQueryString = "" 
CanonicalHeaders = "" 
for key in sorted_headers: 
    CanonicalHeaders += "{}:{}\n".format(key.lower(), headers[key]) 
SignedHeaders = "{}".format(";".join(sorted_headers)) 
HexEncondeHashRequestPayload = hashb16(payload) 
CanonicalRequest = "{}\n{}\n{}\n{}{}\n{}".format(HTTPRequestMethod, CanonicalURI, CanonicalQueryString, CanonicalHeaders, SignedHeaders, HexEncondeHashRequestPayload) 

# step 2 
Algorithm = "AWS4-HMAC-SHA256" 
RequestDateTime = current_time.strftime('%Y%m%dT%H%M%SZ') 
CredentialScope = "{}/{}/{}/{}".format(current_time.strftime("%Y%m%d"), region, service, "aws4_request") 
HashedCanonicalRequest = hashb16(CanonicalRequest) 
StringToSign = "{}\n{}\n{}\n{}".format(Algorithm, RequestDateTime, CredentialScope, HashedCanonicalRequest) 

#step 3 
kDate = HMAC("AWS4" + secret,  current_time.strftime("%Y%m%d")).digest() 
kRegion = HMAC(kDate, region).digest() 
kService = HMAC(kRegion, service).digest() 
kSigning = HMAC(kService, "aws4_request").digest() 
signature = HMAC(kSigning, StringToSign).hexdigest() 

#step 4 
Authorization = "AWS4-HMAC-SHA256 Credential={}/{},SignedHeaders={},Signature={}".format(key_id, CredentialScope, ";".join(sorted_headers), signature) 
headers["Authorization"] = Authorization 

response = requests.request("PUT", url, headers=headers) 

print response.status_code 
print response.text 

Les étapes sont ci-dessus par le AWS documentation. J'ai testé les fonctions de hachage en utilisant les exemples de this page et ils vérifient.

Malheureusement, lorsque j'effectue la demande réelle, j'obtiens un code d'état 403 avec le message de signature invalide habituel. Qu'est-ce qui me manque dans le code ci-dessus?

Répondre

1

Votre StringToSign est incorrect. Plus précisément, la requête HashedCanonicalRequest est incorrecte.

La réponse d'erreur Amazon vous montrera exactement le StringToSign. Cela vous aidera à comprendre ce qui ne va pas.

[MODIFIER - J'ai modifié votre code pour qu'il fonctionne. Remarque: j'ai supprimé le calcul de la charge utile et l'ai modifié en UNSIGNED-PAYLOAD. Il y avait deux problèmes mineurs:

1) Dans le StringToSign le nom du godet n'a pas été spécifié dans l'URL (après la ligne current_time)

2) Vous avez été absent \ n dans CanonicalRequest.

from collections import OrderedDict 
from dateutil import parser 
import datetime 
import hashlib 
import hmac 
import requests 

key_id = "" 
secret = "/N6VFTasQCJic3CqL9tj80UGB6Ba1B" 
region = "" 
bucket_name = "" 
service = "s3" 

def hashb16(message): 
    return hashlib.sha256(message).hexdigest() 

def HMAC(key, message): 
    return hmac.new(key, message, hashlib.sha256) 

current_time = datetime.datetime.utcnow() 

url = "https://s3-us-west-2.amazonaws.com/{}/sometest.txt".format(bucket_name) 
payload = "Welcome to Amazon S3." 
headers = { 
    'date': current_time.strftime("%a, %d %b %Y %H:%m:%S GMT"), 
    'host': "s3-us-west-2.amazonaws.com", 
    'x-amz-content-sha256': 'UNSIGNED-PAYLOAD', 
    'x-amz-date': current_time.strftime('%Y%m%dT%H%M%SZ'), 
    'x-amz-storage-class': 'REDUCED_REDUNDANCY' 
} 
sorted_headers = sorted([k for k in headers]) 

# step 1 
HTTPRequestMethod = "PUT" 
CanonicalURI = "/{}/sometest.txt".format(bucket_name) 
CanonicalQueryString = "" 
CanonicalHeaders = "" 
for key in sorted_headers: 
    CanonicalHeaders += "{}:{}\n".format(key.lower(), headers[key]) 
SignedHeaders = "{}".format(";".join(sorted_headers)) 
HexEncondeHashRequestPayload = hashb16(payload) 
CanonicalRequest = "{}\n{}\n{}\n{}\n{}\n{}".format(HTTPRequestMethod, CanonicalURI, CanonicalQueryString, CanonicalHeaders, SignedHeaders, 'UNSIGNED-PAYLOAD') 

# step 2 
Algorithm = "AWS4-HMAC-SHA256" 
RequestDateTime = current_time.strftime('%Y%m%dT%H%M%SZ') 
CredentialScope = "{}/{}/{}/{}".format(current_time.strftime("%Y%m%d"), region, service, "aws4_request") 
HashedCanonicalRequest = hashb16(CanonicalRequest) 
StringToSign = "{}\n{}\n{}\n{}".format(Algorithm, RequestDateTime, CredentialScope, HashedCanonicalRequest) 

#step 3 
kDate = HMAC("AWS4" + secret,  current_time.strftime("%Y%m%d")).digest() 
kRegion = HMAC(kDate, region).digest() 
kService = HMAC(kRegion, service).digest() 
kSigning = HMAC(kService, "aws4_request").digest() 
signature = HMAC(kSigning, StringToSign).hexdigest() 

#step 4 
Authorization = "AWS4-HMAC-SHA256 Credential={}/{},SignedHeaders={},Signature={}".format(key_id, CredentialScope, ";".join(sorted_headers), signature) 
headers["Authorization"] = Authorization 

response = requests.request("PUT", url, headers=headers) 

print response.status_code 
print response.text