zoukankan      html  css  js  c++  java
  • Python编写AWS Version 4 signing (AWS4-HMAC-SHA256) for execute-api

    官网教程中给了签署AWS请求给了详细的介绍和python的例子,但是例子针对DynamoDB API,本例子针对API Gateway的POST请求,并携带有x-amz-security-token、x-amz-content-sha256两个头。
    例子中经常缺乏这些细节的具体处理,特此记录。最后要注意发送的请求URL是否正确。
    # AWS Version 4 signing example
    
    # DynamoDB API (CreateTable)
    
    # See: http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
    # This version makes a POST request and passes request parameters
    # in the body (payload) of the request. Auth information is passed in
    # an Authorization header.
    
    # POST /dev/v1/user/associations/robots/3147C60040239620 HTTP/1.1
    # X-Amz-Date: 20180502T073321Z
    # Host: njc3321216.execute-api.us-east-1.amazonaws.com
    # x-amz-security-token: AgoGb3JpZ2luENP//////////wEaCXVzLWVhc3QtMSKAAhZ6pzVklfasnpF7+uhEzpnvrRzgXRgFqXvrPWkjtJamALYtWvG0A9sYuKF+b2Jxpitq3UUoatmH1LJtOS3iSXM8RpjiElYd8OZMGqBs7o8Z/7QJV69NUYzKewcVwWrv1HJHGmwTUR/8Oqs7bI9KibLAJclCFBYMgodLd8eYW3m9Oq4kAudQBB7vVQ4hyiGErvwAayA5SqtIvpkr3tR19nH0o57BJHyVNXMuYOKzhPquzxMuuV/wv1XXPGeH+qZNT1a6XAhFZ0LdHmi9A2TgrrmJhlsjvCfsvSA3phBqJhiWNHuM1JHNFF6Vcwg+UV4FdY4qwHP82WPQjiamgiPasEkq9QQIKRAAGgwzMzM0NDAzODkyNDYiDAB/KfmZzmMqsJAwJirSBCTMCqIcagKhuyDzw+1dvIIckZKY5haYIoOB3siUUy7gj2JTTYhxH2GRUSFdPduM05hglqvDHS6L9SyUwctgQ+fBjRIur4k9YtBrWJBI+KFVMEV5UyMr91V0LAMmzQDJfLzIC7av7hEy9LJMNt4axZyrzfKgXqiW2dhmABbREvq/6oBQKIk4x7NbnmOqoCHPfna6Y1QMGXjzZmzG1UYY/u24cyaARnQrMVGmnEPK3hum8RY/Zf/0JlTmz3sapSiRPOhIiDBGg0Cu0mq/arPu1n/nhf6mWdFgWd2pRg3H1WUk5SUystQrBlr1CxnUqQeSEE+IQp9+0HhYdeaMXtEA1V4Ju6ET2p696TZrssxtcd+xoeHUdiq7Rer1QZx04abXVKLVsL0t5KyASNCfLQKbwNBm6su1n2tpqKxdGWt3PmHKTUicOxSpJ+7w7/VVAkyEg3xfCexb7+H2cdhcTKrMvp1225lHkbyW69dgUrdMREvXNyOpu2ludhRZNxZFICCBNKI4xpwZ1PcLq0Wr2H3Uln4GxCTIomx5a7An6dcW6bogzEYTGhZYzEhgTY7GbqAG59zLzJ/NtbZqmYQC4adWolh37OibYuRffkVsDXYFLpJ1qCAw+y7wnwYELCD4QX+VRSOpArYDnmaJp338RjqZSE593LIAR9CR3ihaFsUdFPzRX6LqHCQq7VWA+FVQJCsgHxlcU8+ShHcv0jh745ClcMwi4mCZl1fO1L9HupnobVCXodRwaXJ1ZSDGlSG/qr5BevbKn5KRybg7CHBgcIMwhMfkODDB06XXBQ==
    # Content-type: application/json; charset=utf-8
    # x-amz-content-sha256: d96401ecabf9143f5c90fe37ba177f0de647314bcfd49c698acb132f80749212
    # Accept: application/json; charset=utf-8
    # Authorization: AWS4-HMAC-SHA256 Credential=ASIAJCV4GTJQPYRAYKYQ/20180502/us-east-1/execute-api/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=3bd5e785b3e5110bb4a53b375013ec6888a8fe51ff3f4fa2b05e17ce4457896b
    # Content-Length: 46
    # User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.0; Nexus 9 Build/NRD90M)
    # Connection: Keep-Alive
    # Accept-Encoding: gzip
    #{"password": ":1:1525246193:5aR5eYKn6zsQ6vIp"}
    
    
    # {
    #     "credentials": {
    #         "SecretKey": "JJ+BouOzY53lEkJMuQ/w/PtWQaCgo32sEwzD4mw+",
    #         "SessionToken": "AgoGb3JpZ2luENP//////////wEaCXVzLWVhc3QtMSKAAhZ6pzVklfasnpF7+uhEzpnvrRzgXRgFqXvrPWkjtJamALYtWvG0A9sYuKF+b2Jxpitq3UUoatmH1LJtOS3iSXM8RpjiElYd8OZMGqBs7o8Z/7QJV69NUYzKewcVwWrv1HJHGmwTUR/8Oqs7bI9KibLAJclCFBYMgodLd8eYW3m9Oq4kAudQBB7vVQ4hyiGErvwAayA5SqtIvpkr3tR19nH0o57BJHyVNXMuYOKzhPquzxMuuV/wv1XXPGeH+qZNT1a6XAhFZ0LdHmi9A2TgrrmJhlsjvCfsvSA3phBqJhiWNHuM1JHNFF6Vcwg+UV4FdY4qwHP82WPQjiamgiPasEkq9QQIKRAAGgwzMzM0NDAzODkyNDYiDAB/KfmZzmMqsJAwJirSBCTMCqIcagKhuyDzw+1dvIIckZKY5haYIoOB3siUUy7gj2JTTYhxH2GRUSFdPduM05hglqvDHS6L9SyUwctgQ+fBjRIur4k9YtBrWJBI+KFVMEV5UyMr91V0LAMmzQDJfLzIC7av7hEy9LJMNt4axZyrzfKgXqiW2dhmABbREvq/6oBQKIk4x7NbnmOqoCHPfna6Y1QMGXjzZmzG1UYY/u24cyaARnQrMVGmnEPK3hum8RY/Zf/0JlTmz3sapSiRPOhIiDBGg0Cu0mq/arPu1n/nhf6mWdFgWd2pRg3H1WUk5SUystQrBlr1CxnUqQeSEE+IQp9+0HhYdeaMXtEA1V4Ju6ET2p696TZrssxtcd+xoeHUdiq7Rer1QZx04abXVKLVsL0t5KyASNCfLQKbwNBm6su1n2tpqKxdGWt3PmHKTUicOxSpJ+7w7/VVAkyEg3xfCexb7+H2cdhcTKrMvp1225lHkbyW69dgUrdMREvXNyOpu2ludhRZNxZFICCBNKI4xpwZ1PcLq0Wr2H3Uln4GxCTIomx5a7An6dcW6bogzEYTGhZYzEhgTY7GbqAG59zLzJ/NtbZqmYQC4adWolh37OibYuRffkVsDXYFLpJ1qCAw+y7wnwYELCD4QX+VRSOpArYDnmaJp338RjqZSE593LIAR9CR3ihaFsUdFPzRX6LqHCQq7VWA+FVQJCsgHxlcU8+ShHcv0jh745ClcMwi4mCZl1fO1L9HupnobVCXodRwaXJ1ZSDGlSG/qr5BevbKn5KRybg7CHBgcIMwhMfkODDB06XXBQ==",
    #         "Expiration": "2018-05-02T08:33:21+00:00",
    #         "CognitoId": "us-east-1:c9c81ec4-1c82-4e0c-889d-34df3d144f5a",
    #         "AccessKeyId": "ASIAJCV4GTJQPYRAYKYQ"
    #     }
    # }
    
    import sys, os, base64, datetime, hashlib, hmac 
    import requests # pip install requests
    
    # ************* REQUEST VALUES *************
    method = 'POST'
    service = 'execute-api'
    host = 'njc3321216.execute-api.us-east-1.amazonaws.com'
    region = 'us-east-1'
    endpoint = 'https://njc3321216.execute-api.us-east-1.amazonaws.com'
    amz_security_token = 'AgoGb3JpZ2luENP//////////wEaCXVzLWVhc3QtMSKAAhZ6pzVklfasnpF7+uhEzpnvrRzgXRgFqXvrPWkjtJamALYtWvG0A9sYuKF+b2Jxpitq3UUoatmH1LJtOS3iSXM8RpjiElYd8OZMGqBs7o8Z/7QJV69NUYzKewcVwWrv1HJHGmwTUR/8Oqs7bI9KibLAJclCFBYMgodLd8eYW3m9Oq4kAudQBB7vVQ4hyiGErvwAayA5SqtIvpkr3tR19nH0o57BJHyVNXMuYOKzhPquzxMuuV/wv1XXPGeH+qZNT1a6XAhFZ0LdHmi9A2TgrrmJhlsjvCfsvSA3phBqJhiWNHuM1JHNFF6Vcwg+UV4FdY4qwHP82WPQjiamgiPasEkq9QQIKRAAGgwzMzM0NDAzODkyNDYiDAB/KfmZzmMqsJAwJirSBCTMCqIcagKhuyDzw+1dvIIckZKY5haYIoOB3siUUy7gj2JTTYhxH2GRUSFdPduM05hglqvDHS6L9SyUwctgQ+fBjRIur4k9YtBrWJBI+KFVMEV5UyMr91V0LAMmzQDJfLzIC7av7hEy9LJMNt4axZyrzfKgXqiW2dhmABbREvq/6oBQKIk4x7NbnmOqoCHPfna6Y1QMGXjzZmzG1UYY/u24cyaARnQrMVGmnEPK3hum8RY/Zf/0JlTmz3sapSiRPOhIiDBGg0Cu0mq/arPu1n/nhf6mWdFgWd2pRg3H1WUk5SUystQrBlr1CxnUqQeSEE+IQp9+0HhYdeaMXtEA1V4Ju6ET2p696TZrssxtcd+xoeHUdiq7Rer1QZx04abXVKLVsL0t5KyASNCfLQKbwNBm6su1n2tpqKxdGWt3PmHKTUicOxSpJ+7w7/VVAkyEg3xfCexb7+H2cdhcTKrMvp1225lHkbyW69dgUrdMREvXNyOpu2ludhRZNxZFICCBNKI4xpwZ1PcLq0Wr2H3Uln4GxCTIomx5a7An6dcW6bogzEYTGhZYzEhgTY7GbqAG59zLzJ/NtbZqmYQC4adWolh37OibYuRffkVsDXYFLpJ1qCAw+y7wnwYELCD4QX+VRSOpArYDnmaJp338RjqZSE593LIAR9CR3ihaFsUdFPzRX6LqHCQq7VWA+FVQJCsgHxlcU8+ShHcv0jh745ClcMwi4mCZl1fO1L9HupnobVCXodRwaXJ1ZSDGlSG/qr5BevbKn5KRybg7CHBgcIMwhMfkODDB06XXBQ=='
    # POST requests use a content type header. For DynamoDB,
    # the content is JSON.
    content_type = 'application/json'
    # DynamoDB requires an x-amz-target header that has this format:
    #     DynamoDB_<API version>.<operationName>
    #amz_target = 'DynamoDB_20120810.CreateTable'
    
    # Request parameters for CreateTable--passed in a JSON block.
    request_parameters =  '{'
    request_parameters +=  '"password": ":1:1525246193:5aR5eYKn6zsQ6vIp"'
    request_parameters +=  '}'
    
    # Key derivation functions. See:
    # http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-python
    def sign(key, msg):
        return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()
    
    def getSignatureKey(key, date_stamp, regionName, serviceName):
        kDate = sign(('AWS4' + key).encode('utf-8'), date_stamp)
        kRegion = sign(kDate, regionName)
        kService = sign(kRegion, serviceName)
        kSigning = sign(kService, 'aws4_request')
        return kSigning
    
    # Read AWS access key from env. variables or configuration file. Best practice is NOT
    # to embed credentials in code.
    access_key = "ASIAJCV4GTJQPYRAYKYQ"
    secret_key = "JJ+BouOzY53lEkJMuQ/w/PtWQaCgo32sEwzD4mw+"
    if access_key is None or secret_key is None:
        print 'No access key is available.'
        sys.exit()
    
    # Create a date for headers and the credential string
    t = datetime.datetime.utcnow()
    amz_date = t.strftime('%Y%m%dT%H%M%SZ')
    date_stamp = t.strftime('%Y%m%d') # Date w/o time, used in credential scope
    
    amz_date = "20180502T073321Z"
    date_stamp = "20180502"
    
    # ************* TASK 1: CREATE A CANONICAL REQUEST *************
    # http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
    
    # Step 1 is to define the verb (GET, POST, etc.)--already done.
    
    # Step 2: Create canonical URI--the part of the URI from domain to query 
    # string (use '/' if no path)
    canonical_uri = '/dev/v1/user/associations/robots/3147C60040239620'
    
    ## Step 3: Create the canonical query string. In this example, request
    # parameters are passed in the body of the request and the query string
    # is blank.
    canonical_querystring = ''
    
    # Step 4: Create the canonical headers. Header names must be trimmed
    # and lowercase, and sorted in code point order from low to high.
    # Note that there is a trailing 
    .
    amz_content_sha256 = hashlib.sha256(request_parameters).hexdigest()
    canonical_headers = 'host:' + host + '
    ' + 'x-amz-content-sha256:' + amz_content_sha256 + '
    ' + 'x-amz-date:' + amz_date + '
    ' + 'x-amz-security-token:' + amz_security_token + '
    '
    #SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=3bd5e785b3e5110bb4a53b375013ec6888a8fe51ff3f4fa2b05e17ce4457896b
    # Step 5: Create the list of signed headers. This lists the headers
    # in the canonical_headers list, delimited with ";" and in alpha order.
    # Note: The request can include any headers; canonical_headers and
    # signed_headers include those that you want to be included in the
    # hash of the request. "Host" and "x-amz-date" are always required.
    # For DynamoDB, content-type and x-amz-target are also required.
    signed_headers = 'host;x-amz-content-sha256;x-amz-date;x-amz-security-token'
    
    # Step 6: Create payload hash. In this example, the payload (body of
    # the request) contains the request parameters.
    payload_hash = hashlib.sha256(request_parameters).hexdigest()
    
    # Step 7: Combine elements to create canonical request
    canonical_request = method + '
    ' + canonical_uri + '
    ' + canonical_querystring + '
    ' + canonical_headers + '
    ' + signed_headers + '
    ' + payload_hash
    
    # ************* TASK 2: CREATE THE STRING TO SIGN*************
    # Match the algorithm to the hashing algorithm you use, either SHA-1 or
    # SHA-256 (recommended)
    algorithm = 'AWS4-HMAC-SHA256'
    credential_scope = date_stamp + '/' + region + '/' + service + '/' + 'aws4_request'
    string_to_sign = algorithm + '
    ' +  amz_date + '
    ' +  credential_scope + '
    ' +  hashlib.sha256(canonical_request).hexdigest()
    
    
    # ************* TASK 3: CALCULATE THE SIGNATURE *************
    # Create the signing key using the function defined above.
    signing_key = getSignatureKey(secret_key, date_stamp, region, service)
    
    # Sign the string_to_sign using the signing_key
    signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()
    
    # ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
    # Put the signature information in a header named Authorization.
    authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' +  'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
    
    # For DynamoDB, the request can include any headers, but MUST include "host", "x-amz-date",
    # "x-amz-target", "content-type", and "Authorization". Except for the authorization
    # header, the headers must be included in the canonical_headers and signed_headers values, as
    # noted earlier. Order here is not significant.
    # # Python note: The 'host' header is added automatically by the Python 'requests' library.
    headers = {'X-Amz-Date':amz_date,
                'x-amz-security-token':amz_security_token,
               'Content-Type':content_type,
               'x-amz-content-sha256':amz_content_sha256,
               'Accept': 'application/json; charset=utf-8',
               'Authorization':authorization_header,
               'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 7.0; Nexus 9 Build/NRD90M)'}
    
    # ************* SEND THE REQUEST *************
    print '
    BEGIN REQUEST++++++++++++++++++++++++++++++++++++'
    #GET请求需要适当修改加入?和参数
    #request_url = endpoint + canonical_uri + '?' + canonical_querystring
    print 'Request URL = ' + endpoint + canonical_uri
    print headers
    r = requests.post(endpoint + canonical_uri, data=request_parameters, headers=headers)
    
    print '
    RESPONSE++++++++++++++++++++++++++++++++++++'
    print 'Response code: %d
    ' % r.status_code
    print r.text
     
  • 相关阅读:
    string subscript out of range
    基数树(radix tree)
    改进版的快速排序
    快速排序算法-C语言实现
    归并排序
    用数组名做函数参数(转)
    堆和栈的区别
    给指针malloc分配空间后就等于数组吗?
    codeblocks中添加-std=c99
    堆排序-C语言实现
  • 原文地址:https://www.cnblogs.com/ascii0x03/p/9138200.html
Copyright © 2011-2022 走看看