Как перевести AWS Task 1: Create a Canonical Request for Signature Version 4

(Заявление об отказе от ответственности: это «Практическое руководство», поскольку я не смог найти никаких примеров CF, когда я внедрял AWS Signature Version 4)

Как реализовать Задачу 1. Создание канонического запроса для подписи версии 4 в CF?

Резюме:

  1. Начните с метода HTTP-запроса (GET, PUT, POST и т. Д.), За которым следует символ новой строки.
  2. Добавьте канонический параметр URI, за которым следует символ новой строки.
  3. Добавьте каноническую строку запроса, за которой следует символ новой строки
  4. Добавьте канонические заголовки, за которыми следует символ новой строки.
  5. Добавьте подписанные заголовки, за которыми следует символ новой строки.
  6. Используйте хеш-функцию (дайджест), такую ​​как SHA256, чтобы создать хешированное значение из полезной нагрузки в теле запроса.
  7. Создайте законченный канонический запрос, объединив компоненты с каждого шага в одну строку.
  8. Создайте дайджест (хэш) канонического запроса с тем же алгоритмом, который использовался для хеширования полезной нагрузки.

person Leigh    schedule 30.04.2016    source источник


Ответы (1)


Ниже приведена реализация cfscript Задача 1. Создание Канонический запрос на подпись версии 4

Результат:

f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59

Код:

  1. Начните с метода HTTP-запроса (GET, PUT, POST и т. Д.)

    requestMethod = "GET";
    writeOutput("<br>requestMethod: <code>"& requestMethod &"</code>");
    
  2. Добавьте (закодированный) канонический параметр URI, за которым следует символ новой строки.

    originalURI = "";
    // If the absolute path is empty, use a forward slash (/)
    originalURI  = len(trim(originalURI)) ? originalURI : "/"& originalURI;
    // Encode URI and preserve forward slashes 
    canonicalURI = replace( encodeRFC3986( originalURI ), "%2F", "/", "all");
    writeOutput("<br>canonicalURI: <code>"& canonicalURI &"</code>");
    
  3. Добавьте каноническую строку запроса, за которой следует символ новой строки

    queryParams = { "Action"="ListUsers", "Version"="2010-05-08" };
    
    // a) Encode parameter names and values 
    encodedParams = {};
    structEach( queryParams, function(key, value) {
        encodedParams[ encodeRFC3986(arguments.key) ] = encodeRFC3986( arguments.value);
    });
    
    // b) Sort the encoded parameter in ascending order (ASCII order)
    encodedKeyNames = structKeyArray( encodedParams );
    arraySort( encodedKeyNames, "text" );
    
    // c) Build the canonical query string. Starting with first parameter, append encoded 
    // parameter name, followed by character '=' (ASCII code 61), followed by the encoded value
    encodedPairs  = [];
    for (key in encodedKeyNames) {
        arrayAppend( encodedPairs, key &"="& encodedParams[ key ] ); 
    }
    // d) Append the character '&' (ASCII code 38) after each parameter value, except for the last value in the list. 
    canonicalQueryString = arrayToList( encodedPairs, "&");
    writeOutput("<br>canonicalQueryString: <code>"& canonicalQueryString &"</code>");
    
  4. Добавьте канонические заголовки, за которыми следует символ новой строки.

    requestHeaders = { "Content-type"= "application/x-www-form-urlencoded; charset=utf-8"
                        , "Host" = "iam.amazonaws.com"
                        , "X-Amz-Date" = "20150830T123600Z"
                    };
    
    // a) Convert all header names to lowercase and remove leading spaces and trailing spaces. 
    // Convert sequential spaces in the header value to a single space.         
    cleanedHeaders = {};
    structEach( requestHeaders, function(key, value) {
        headerName = reReplace( trim(arguments.key), "\s+", " ", "all");
        headerValue = reReplace( trim(arguments.value), "\s+", " ", "all");
        cleanedHeaders[ lcase(headerName) ] = headerValue;
    });
    
    // b) [sort] the (lowercase) headers by character code
    sortedHeaderNames = structKeyArray( cleanedHeaders );
    arraySort( sortedHeaderNames, "text" );
    
    // c) Append the lowercase header name followed by a colon.
    // Do not sort the values in headers that have multiple values.
    cleanedPairs  = [];
    for (key in sortedHeaderNames) {
        arrayAppend( cleanedPairs, key &":"& cleanedHeaders[ key ] ); 
    }
    
    // d) Append new line after each header pair. Should END WITH a new line
    canonicalHeaderString = arrayToList( cleanedPairs, chr(10) ) & chr(10) ;
    writeOutput("<br> canonicalHeaderString: <code>"& canonicalHeaderString &"</code>");
    
  5. Добавьте подписанные заголовки, за которыми следует символ новой строки

    // To create the signed headers list, convert all header names to lowercase, 
    // sort them by character code, and use a semicolon to separate the header names. 
    // Note, we already have the sorted names from the canonical header logic (step 4)
    signedHeaderString = arrayToList( sortedHeaderNames, ";" );
    writeOutput("<br>signedHeaderString: <code>"& signedHeaderString &"</code>");
    
  6. Создайте хеш полезной нагрузки в теле запроса http / https

    requestPayload = "";
    payloadChecksum = lcase( hash( requestPayload , "SHA256" ) );
    writeOutput("<br>payloadChecksum: <code>"& payloadChecksum &"</code>");
    
  7. Создайте канонический запрос, объединив компоненты с каждого шага в одну строку

    canonicalRequest = requestMethod & chr(10)
                        & canonicalURI & chr(10)
                        & canonicalQueryString & chr(10)
                        & canonicalHeaderString & chr(10)
                        & signedHeaderString & chr(10)
                        & payloadChecksum ;
    
    writeOutput("<br>canonicalRequest: <pre>"& canonicalRequest &"</pre>");
    
  8. Создайте дайджест (хэш) канонического запроса с тем же алгоритмом, который использовался для хеширования полезной нагрузки

    requestDigest = lcase( hash( canonicalRequest , "SHA256" ) );
    writeOutput("<br>requestDigest: <code>"& requestDigest &"</code>");
    

UDF encodeRFC3986:

    /**
    * URI encoding per RFC 3986:
    *  <ul>
    *     <li>Unreserved characters that should not be escaped: ALPHA / DIGIT / "-" / "." / "_" / "~" </li>
    *     <li>Spaces should be encoded as %20 instead of +</li>
    *     <li>Reserved characters that should be escaped include:   ? ## [ ] @ ! $ & ' ( ) * + , ; =</li>
    *  </ul>
    *  
    * @text String to encode
    * @returns URI encoded text
    */
    public function encodeRFC3986(required string text) {
        // Requires CF10+
        Local.encoded = encodeForURL(arguments.text);

        // Undo encoding of tilde "~"
        Local.encoded = replace( Local.encoded, "%7E", "~", "all" );
        // Change space encoding from "+" to "%20"
        Local.encoded = replace( Local.encoded, "+", "%20", "all" );
        // URL encode asterisk "*" 
        Local.encoded = replace( Local.encoded, "*", "%2A", "all" );

        return Local.encoded;
    }
person Leigh    schedule 30.04.2016
comment
Спасибо, знаете ли вы об этом в Java-версии? - person fullmoon; 08.07.2019