Как перевести AWS Задача 1. Создание канонического запроса на подпись версии 4
(Отказ от ответственности: это подразумевается как "практическое руководство", так как я не мог найти никаких примеров CF, когда я реализовывал AWS Signature Version 4)
Как реализовать задачу 1: создать канонический запрос на подпись версии 4 в CF?
Резюме:
- Начните с метода HTTP-запроса (GET, PUT, POST и т. Д.), За которым следует символ новой строки.
- Добавьте канонический параметр URI, за которым следует символ новой строки.
- Добавьте строку канонического запроса, за которой следует символ новой строки
- Добавьте канонические заголовки, за которыми следует символ новой строки.
- Добавьте подписанные заголовки, за которыми следует символ новой строки.
- Используйте хеш-функцию (дайджест), например SHA256, чтобы создать хеш-значение из полезной нагрузки в теле запроса.
- Создайте законченный канонический запрос, объединив компоненты из каждого шага в одну строку.
- Создайте дайджест (хеш) канонического запроса с тем же алгоритмом, который использовался для хэширования полезной нагрузки.
1 ответ
Ниже приведена реализация задачи 1 в cfscript : создание канонического запроса на подпись версии 4
Результат:
f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59
Код:
Начните с метода HTTP-запроса (GET, PUT, POST и т. Д.)
requestMethod = "GET"; writeOutput("<br>requestMethod: <code>"& requestMethod &"</code>");
Добавьте (закодированный) канонический параметр 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>");
Добавьте строку канонического запроса, за которой следует символ новой строки
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>");
Добавьте канонические заголовки, за которыми следует символ новой строки.
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>");
Добавьте подписанные заголовки с последующим символом перевода строки
// 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>");
Создайте хэш полезной нагрузки в теле запроса http/https.
requestPayload = ""; payloadChecksum = lcase( hash( requestPayload , "SHA256" ) ); writeOutput("<br>payloadChecksum: <code>"& payloadChecksum &"</code>");
Построить канонический запрос, объединив компоненты из каждого шага в одну строку
canonicalRequest = requestMethod & chr(10) & canonicalURI & chr(10) & canonicalQueryString & chr(10) & canonicalHeaderString & chr(10) & signedHeaderString & chr(10) & payloadChecksum ; writeOutput("<br>canonicalRequest: <pre>"& canonicalRequest &"</pre>");
Создайте дайджест (хеш) канонического запроса с тем же алгоритмом, который использовался для хэширования полезной нагрузки.
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;
}