2015-09-10 1 views
3

Я пытаюсь использовать ColdFusion для доступа к веб-службам Amazon (AWS), используя их текущий метод проверки подлинности, известный как Signature Version 4. Я ознакомился с их документацией, которая содержит примеры кода для several programming languages, а также псевдокод для other languages. Они предоставили некоторые тестовые входные значения, чтобы перейти к функции подписи моего скрипта, а также некоторые ожидаемые результаты.Как получить ключ входа для AWS Signature Version 4 (в ColdFusion)?

Вот тестовые входы:

key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' 
dateStamp = '20120215' 
regionName = 'us-east-1' 
serviceName = 'iam' 

Вот ожидаемые результаты:

kSecret = '41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559' 
kDate = '969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d' 
kRegion = '69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c' 
kService = 'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa' 
kSigning = 'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d' 

Правильное значение для "kSigning" должно быть таким:

f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d 

Однако, для «kSigning» мой код генерирует это:

31A84DCE0538A8B15ED68CCFBD803F17947E41BF625EFFD1AD6A67FC821F9BE2 

Я использую Railo 4.2. Может кто-то, пожалуйста, помогите мне решить эту проблему, чтобы ожидаемое значение соответствовало сброшенному значению? Вот мой ColdFusion разметки:

<cfsilent> 

<!--- HMACSHA256 ---> 
<cffunction name="sign" returntype="binary" access="private" output="false" hint="Sign with NSA SHA-256 Algorithm"> 
    <cfargument name="signMessage" type="string" required="true" /> 
    <cfargument name="signKey" type="string" required="true" /> 

    <cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes("utf-8") /> 
    <cfset var jKey = JavaCast("string",arguments.signKey).getBytes("utf-8") /> 
    <cfset var key = createObject("java","javax.crypto.spec.SecretKeySpec") /> 
    <cfset var mac = createObject("java","javax.crypto.Mac") /> 

    <cfset key = key.init(jKey,"HmacSHA256") /> 
    <cfset mac = mac.getInstance(key.getAlgorithm()) /> 
    <cfset mac.init(key) /> 

    <cfreturn mac.doFinal(jMsg) /> 
</cffunction> 

<!--- Get Signature Key ---> 
<cffunction name="getSignatureKey" returntype="binary" access="private" output="false" hint="Derive the sign-in key"> 
    <cfargument name="key" type="string" required="true" /> 
    <cfargument name="dateStamp" type="string" required="true" /> 
    <cfargument name="regionName" type="string" required="true" /> 
    <cfargument name="serviceName" type="string" required="true" /> 

    <cfset var kSecret = "AWS4" & arguments.key /> 
    <cfset var kDate = sign(arguments.dateStamp, kSecret) /> 
    <cfset var kRegion = sign(arguments.regionName, kDate) /> 
    <cfset var kService = sign(arguments.serviceName, kRegion) /> 
    <cfset var kSigning = sign(arguments.serviceName, kService) /> 

    <cfreturn kSigning /> 
</cffunction> 

</cfsilent><!doctype html> 

<html lang="en"> 
<head> 
    <meta charset="utf-8"> 
    <title>AWS Test</title> 
</head> 
<body> 

<cfset kSecret = getSignatureKey( 
    'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY', 
    '20120215', 
    'us-east-1', 
    'iam' 
) /> 
<cfdump var="#BinaryEncode(kSecret, 'hex')#" label="kSecret" /> 

</body> 
</html> 
+0

Я имел в виду обновить свой скрипт от 2 до 4. Но в то же время это может дать вам некоторый прогресс. https://gist.github.com/CFJSGeek/3f6f14ba86049af75361 –

+0

Когда вы выясните, я с удовольствием посмотрю ваши результаты! –

+0

Я провел 72 часа подряд, пытаясь понять подпись версии 4 с помощью aws webservice, я, наконец, получил маркер правильно, как и ожидалось, как образцы кода, и когда я отправил его на службу, у меня все еще была ошибка проверки подлинности. Проработанные последующие часы с поддержкой уровня aws в корпоративной сети (мы назвали учетную запись), и инженер не мог понять, почему служба отклонила вызовы REST. Завершена загрузка java sdk и использование этого. Любовь aws, ненавидьте их реализацию. Это ужасно, черт возьми. Удачи! – rodmunera

ответ

3

<cfset var kRegion = sign(arguments.regionName, kDate) />

Я немного удивлен код выполняется без ошибок, так как функция sign() ожидает две строки, но код на самом деле проходит в массив байтов для второго параметра. (В CF11 это вызывает ошибку). Возможно, происходит какое-то неявное преобразование? В любом случае, после рефакторинга функций немного, пример работал отлично с одним исключением. В последней строке примера используется буквальная строка «aws4_request», а не «arguments.serviceName». См. Пример ниже.

Сказав это, не обладает ли функция Rail HMAC функцией, а не катитесь? Я так думаю, так как HMAC() включен в CF10 +. Обновление: В качестве vrtjason noted in the comments, Railo добавила функцию HMAC() в 4.0.0.011. Однако для обратной совместимости версия java ниже должна работать с большинством любой версии.

Пример:

result = getSignatureKey(key, dateStamp, regionName, serviceName); 
writeDump(binaryEncode(result, "hex")); 

Результаты:

F4780E2D9F65FA895F9C67B32CE1BAF0B0D8A43505A000A1A9E090D414DB404D 

Функции:

<cffunction name="getSignatureKey" returntype="binary" access="private" output="false" hint="Derive the sign-in key"> 
    <cfargument name="key" type="string" required="true" /> 
    <cfargument name="dateStamp" type="string" required="true" /> 
    <cfargument name="regionName" type="string" required="true" /> 
    <cfargument name="serviceName" type="string" required="true" /> 

    <cfset Local.kSecret = charsetDecode("AWS4" & arguments.key, "UTF-8") /> 
    <cfset Local.kDate = sign(arguments.dateStamp, Local.kSecret) /> 
    <cfset Local.kRegion = sign(arguments.regionName, Local.kDate) /> 
    <cfset Local.kService = sign(arguments.serviceName, Local.kRegion) /> 
    <cfset Local.kSigning = sign("aws4_request", Local.kService) /> 

    <cfreturn Local.kSigning /> 
</cffunction> 




<cffunction name="sign" returntype="binary" access="private" output="false" hint="Sign with NSA SHA-256 Algorithm"> 
    <cfargument name="message" type="string" required="true" /> 
    <cfargument name="key" type="binary" required="true" /> 
    <cfargument name="algorithm" type="string" default="HmacSHA256" /> 
    <cfargument name="encoding" type="string" default="UTF-8" /> 

    <cfset Local.keySpec = createObject("java","javax.crypto.spec.SecretKeySpec") /> 
    <cfset Local.keySpec = Local.keySpec.init(arguments.key, arguments.algorithm) /> 
    <cfset Local.mac = createObject("java","javax.crypto.Mac").getInstance(arguments.algorithm) /> 
    <cfset Local.mac.init(Local.keySpec) /> 

    <cfreturn Local.mac.doFinal(charsetDecode(arguments.message, arguments.encoding)) /> 
</cffunction> 
+1

Спасибо, Ли! Я сделал тот же результат в конце. Выдающаяся работа. Кстати, похоже, что [hmac был добавлен в Railo 4.0.0.011] (https://github.com/getrailo/railo/commit/f36bd5c72c3dc084b08aab9edeabba43f5a7548b), поэтому для обратной совместимости я думаю, что полезно использовать в Java для hmac. – vrtjason

+0

Ах, спасибо за публикацию информации о версии. Я добавил его к ответу для большей видимости. – Leigh

1

Я вижу проблему и ожидать, что вы увидите, это тоже, если вы обратите внимание, как похожи эти две строки:

<cfset var kService = sign(arguments.serviceName, kRegion) /> 
<cfset var kSigning = sign(arguments.serviceName, kService) /> 

Красная тревога флаг, имеет смысл hmac имя службы дважды?

Ввод на последний шаг представляет собой строковый литерал.

<cfset var kSigning = sign("aws4_request", kService) /> 
+1

Darn it! Прошло слишком долго, набрав ответ ;-) – Leigh

+1

lol @Leigh Я ненавижу, когда это происходит. По крайней мере, мы пришли к одному и тому же ответу за конкретную ошибку, но +1 для подробного анализа. –

1

Я считаю, что вы можете сделать это в ColdF usion 10+, используя встроенную функцию HMAC() без необходимости создания объекта Java:

function getSignatureKey(key, dateStamp, regionName, serviceName) { 
    var kDate= lCase(HMAC(ARGUMENTS.dateStamp,"AWS4" & ARGUMENTS.key,"hmacsha256")); 
    var kRegion= lCase(HMAC(ARGUMENTS.regionName,binaryDecode(kDate,'hex'),"hmacsha256")); 
    var kService=lCase(HMAC(ARGUMENTS.serviceName,binaryDecode(kRegion,'hex'),"hmacsha256")); 
    var kSigning= lCase(HMAC("aws4_request",binaryDecode(kService,'hex'),"hmacsha256")); 

    return kSigning; 
} 
+0

Абсолютно. Ответчик решил сохранить версию java (для обратной совместимости), но для нового кода с использованием встроенной функции HMAC это путь. – Leigh