2016-01-19 32 views
13

我在AWS API網關後面有一個API,需要使用Authorization標頭進行處理。不幸的是我無法將其傳遞給後端進行處理。如何通過API網關將授權標頭傳遞給HTTP端點?

我已經嘗試在我的方法請求中創建授權HTTP請求標頭,然後在集成請求中創建相應的授權HTTP標頭(授權從本例中的method.request.header.Authorization映射)。我記錄了後端收到的所有標題,並從日誌中可以看到集成請求中列出但未授權的其他標題。

我也曾嘗試創建與application/json內容類型的映射模板,並定義爲

{ 
     "AccountID": "$context.identity.accountId", 
     "Caller": "$context.identity.caller", 
     "User": "$context.identity.user", 
     "Authorization": "$input.params().header.get('Authorization')", 
     "UserARN": "$context.identity.userArn" 
    } 

然而,後臺日誌顯示仍然沒有Authorization頭,也沒有任何授權領域的JSON體模板。我也看不到用戶的ARN。我已經看到用戶提到的其他示例和線程訪問傳遞到Lambda函數的事件對象上的授權字段,但我沒有使用Lambda函數。

我已經確保在兩種情況下部署API網關。

有誰知道是否有某種方法可以將授權標頭通過API網關傳遞給我的HTTP端點?有沒有其他方法可以訪問API調用者的用戶名或ID?


編輯 - 下面是我用打API網關的代碼片段:

String awsAccessKey = "myaccesskey"; 
String awsSecretKey = "mysecretkey"; 

URL endpointUrl; 
try { 
    endpointUrl = new URL("https://<host>/<path>/<to>/<resource>?startDate=20151201&endDate=20151231"); 
} catch(Exception e) { 
    throw new RuntimeException("Unable to parse service endpoint: " + e.getMessage()); 
} 

Date now = new Date(); 

SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"); 
sdf1.setTimeZone(new SimpleTimeZone(0, "UTC")); 
String dateTS = sdf1.format(now); 

String headerNames = "host;x-amz-date"; 
String queryParameters = "endDate=20151231&startDate=20151201"; 

String canonicalRequest = "GET\n" + 
     "/<path>/<to>/<resource>\n" + 
     queryParameters + "\n" + 
     "host:<host>\n" + 
     "x-amz-date:" + dateTS + "\n" + 
     "\n" + 
     headerNames + "\n" + 
     "<sha256 hash for empty request body>"; 

System.out.println(canonicalRequest); 

SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd"); 
sdf2.setTimeZone(new SimpleTimeZone(0, "UTC")); 
String dateStr = sdf2.format(now); 
String scope = dateStr + "/us-east-1/execute-api/aws4_request"; 
String stringToSign = 
     "AWS4-HMAC-SHA256\n" + 
       dateTS + "\n" + 
       scope + "\n" + 
       "hex encoded hash of canonicalRequest"; 

System.out.println(stringToSign); 

byte[] kSecret = ("AWS4" + awsSecretKey).getBytes(); 
byte[] kDate = HmacSHA256(dateStr, kSecret); 
byte[] kRegion = HmacSHA256("us-east-1", kDate); 
byte[] kService = HmacSHA256("execute-api", kRegion); 
byte[] kSigning = HmacSHA256("aws4_request", kService); 
byte[] signature = HmacSHA256(stringToSign, kSigning); 
String credentialsAuthorizationHeader = "Credential=" + awsAccessKey + "/" + scope; 
String signedHeadersAuthorizationHeader = "SignedHeaders=" + headerNames; 
String signatureAuthorizationHeader = "Signature=" + "hex encoded signature"; 
String authorization = "AWS4-HMAC-SHA256 " 
     + credentialsAuthorizationHeader + ", " 
     + signedHeadersAuthorizationHeader + ", " 
     + signatureAuthorizationHeader; 

Map<String, String> headers = new HashMap<String, String>(); 
headers.put("x-amz-date", dateTS); 
headers.put("Host", endpointUrl.getHost()); 
headers.put("Authorization", authorization); 
headers.put("Content-Type", "application/json"); 

HttpURLConnection connection = null; 
try { 
    connection = (HttpURLConnection) endpointUrl.openConnection(); 
    connection.setRequestMethod("GET"); 

    for (String headerKey : headers.keySet()) { 
     connection.setRequestProperty(headerKey, headers.get(headerKey)); 
    } 
    connection.setUseCaches(false); 
    connection.setDoInput(true); 
    connection.setDoOutput(true); 

    InputStream is; 
    try { 
     is = connection.getInputStream(); 
    } catch (IOException e) { 
     is = connection.getErrorStream(); 
    } 

    BufferedReader rd = new BufferedReader(new InputStreamReader(is)); 
    String line; 
    StringBuffer response = new StringBuffer(); 
    while ((line = rd.readLine()) != null) { 
     response.append(line); 
     response.append('\r'); 
    } 
    rd.close(); 
    System.out.println(response.toString()); 
} catch (Exception e) { 
    throw new RuntimeException("Error: " + e.getMessage(), e); 
} finally { 
    if (connection != null) { 
     connection.disconnect(); 
    } 
} 

這是不夠好,成功驗證,並砸在後端的HTTP端點。

+0

只是爲了澄清自己的目標GET請求,你想Auhthorization頭或AWS身份驗證的結果?您是否爲該方法啓用AWS_IAM auth? –

+2

我想授權標頭,其中包含簽名,憑證等。如果驗證標頭不能通過,我也可以使用一些關於調用者的信息(例如用戶ID)。是的,AWS_IAM爲資源啓用。 – Nick

+0

您使用什麼驗證方法來訪問API? IAM用戶憑證,基於臨時STS角色的憑證,Cognito憑證? –

回答

6

正如評論中指出的那樣,授權標題包含了您建立用戶的不完整信息,因此我不建議您使用此路線。此外,如果啓用AWS_IAM auth,授權標頭將由API網關使用。

如果AWS_IAM auth已啓用且簽名被正確提供,$ context.identity參數應該反映用於簽署請求的憑證。

如果您在控制檯中使用測試調用功能,您是否看到正在填充的上下文字段?

更新: 我無法重現此問題。 我有以下映射模板的API:

#set($path = $input.params().path) 
#set($qs = $input.params().querystring) 
{ 
    "resource-path": "$context.resourcePath", 
    "http-method": "$context.httpMethod", 
    "identity": { 
     #foreach($key in $context.identity.keySet()) 
      "$key": "$context.identity.get($key)" 
     #if($foreach.hasNext), #end 
     #end 
    }, 
    "params": { 
     #foreach($key in $path.keySet()) 
      "$key": "$path.get($key)" 
     #if($foreach.hasNext), #end 
     #end 
    }, 
    "query": { 
     #foreach($key in $qs.keySet()) 
      "$key": "$qs.get($key)" 
     #if($foreach.hasNext), #end 
     #end 
    }, 
    "body": $input.json('$') 
} 

這只是吐回輸入作爲輸出lambda函數。當我簽名的請求,並調用API,我回來了預期的結果:

{ 
    "resource-path":"/iam", 
    "http-method":"GET", 
    "identity":{ 
    "cognitoIdentityPoolId":"", 
    "accountId":"xxxxxxxx", 
    "cognitoIdentityId":"", 
    "caller":"AIDXXXXXXXXXXX, 
    "apiKey":"", 
    "sourceIp":"54.xx.xx.xx", 
    "cognitoAuthenticationType":"", 
    "cognitoAuthenticationProvider":"", 
    "userArn":"arn:aws:iam::xxxxxxxx:user/hackathon", 
    "userAgent":"Java/1.8.0_31", 
    "user":"AIDXXXXXXXXXXXXXX" 
    }, 
    "params":{}, 
    "query":{}, 
    "body":{} 
} 
+0

感謝您的反饋。我打算從Authorization頭部獲取AccessKey,遍歷我們的用戶並嘗試找到一個具有匹配AccessKey的AccessKey。但是,聽起來這樣做不起作用,因爲AWS_IAM auth啓用時授權標頭被消耗。 我試着用$ context.identity參數進行建議。使用測試調用功能,我可以看到他們被我的API記錄。但是,當我以編程方式點擊API網關時,同樣的API被擊中,但context.identity字段未被填充和記錄。爲什麼只用於測試功能? – Nick

+0

@尼克絕對不應該發生。您是否正面簽署要求?你可以發佈你用來調用API的代碼嗎? –

+0

我使用代碼片段更新了問題。我確信我正在簽署請求。 – Nick

4

目前Authorization頭只能轉發的不需要AWS身份驗證方法。 SigV4簽名過程依賴於授權標題,我們不會爲了安全目的而公開此信息。如果您有需要發送的數據(除了SigV4簽名),您需要發送另一個標頭。

1

在AWS API網關中,GET方法不支持Request Body。

+1

是的,API網關不支持集成端GET方法的請求體。 –

1

在集成請求中,通過將POST指定爲HTTP方法將GET轉換爲POST。然後用指定身體映射模板所提議的@BobKinney

這樣的請求主體將正常進行傳播,但客戶仍然會使得預期

相關問題