API Gateway Custom Authorizer: Control error message and code

时间:2018-06-04 17:39:23

标签: java amazon-web-services http authentication aws-api-gateway

I have a custom authorizer for my Gateway API. I've read many articles on how to customize the error message and code returned to end user when on authentication or authorization errors. This one seemed the most useful.

Problem is the API Gateway doesn't behave as documented.

My custom authorizer implementation (python):

def lambda_handler(event, context):
    raise Exception('the sky is falling!')

When I call the API using curl:

kash@Laptop$ date; curl -i -X GET -H "Authorization: Bearer 1234abcd`date +%s`" https://xxxx.execute-api.us-west-2.amazonaws.com/prod/ticket
Mon Jun  4 12:27:51 CDT 2018
HTTP/1.1 500 Internal Server Error
Date: Mon, 04 Jun 2018 17:27:53 GMT
Content-Type: application/json
Content-Length: 16
Connection: keep-alive
x-amzn-RequestId: 9cc6d7ce-681c-xxxx-8a4a-23a7616ba4a5
x-amzn-ErrorType: AuthorizerConfigurationException
x-amz-apigw-id: xxxx=

{"message":null}
kash@Laptop$ 

How do I make it return HTTP 4xx with {"message": "the sky is falling!"} ?


For debugging: I went to Gateway Responses under my API and updated the "Body Mapping Templates" for "Authorizer Configuration Error (500)" from this:

{"message":$context.error.messageString}

to this:

{
      "errorMessage":"$errorMessage",
      "messageString":"$messageString",

      "context.errorMessage":"$context.errorMessage",
      "context.messageString":"$context.messageString",

      "context.error.errorMessage":"$context.error.errorMessage",
      "context.error.messageString":"$context.error.messageString",

      "context.authorizer.error.errorMessage":"$context.authorizer.error.errorMessage"
      "context.authorizer.error.errorMessage":"$context.authorizer.error.errorMessage"
      "context.authorizer.errorMessage":"$context.authorizer.errorMessage"
      "context.authorizer.messageString":"$context.authorizer.messageString"

      "type": "$context.error.responseType",
      "statusCode": "'404'",
      "stage": "$context.stage",
      "resourcePath": "$context.resourcePath",
      "stageVariables.a": "$stageVariables.a",

      "context.apiId": "$context.apiId",
      "context.authorizer.claims.property": "$context.authorizer.claims.property",
      "context.authorizer.principalId": "$context.authorizer.principalId",
      "context.authorizer.property": "$context.authorizer.property",
      "context.httpMethod": "$context.httpMethod",
      "context.error.message": "$context.error.message",
      "context.error.messageString": "$context.error.messageString",
      "context.error.responseType": "$context.error.responseType",
      "context.extendedRequestId": "$context.extendedRequestId",
      "context.identity.accountId": "$context.identity.accountId",
      "context.identity.apiKey": "$context.identity.apiKey",
      "context.identity.apiKeyId": "$context.identity.apiKeyId",
      "context.identity.caller": "$context.identity.caller",
      "context.identity.cognitoAuthenticationProvider": "$context.identity.cognitoAuthenticationProvider",
      "context.identity.cognitoAuthenticationType": "$context.identity.cognitoAuthenticationType",
      "context.identity.cognitoIdentityId": "$context.identity.cognitoIdentityId",
      "context.identity.cognitoIdentityPoolId": "$context.identity.cognitoIdentityPoolId",
      "context.identity.sourceIp": "$context.identity.sourceIp",
      "context.identity.user": "$context.identity.user",
      "context.identity.userAgent": "$context.identity.userAgent",
      "context.identity.userArn": "$context.identity.userArn",
      "context.integrationLatency": "$context.integrationLatency",
      "context.path": "$context.path",
      "context.protocol": "$context.protocol",
      "context.requestId": "$context.requestId",
      "context.requestTime": "$context.requestTime",
      "context.requestTimeEpoch": "$context.requestTimeEpoch",
      "context.resourceId": "$context.resourceId",
      "context.resourcePath": "$context.resourcePath",
      "context.responseLength": "$context.responseLength",
      "context.responseLatency": "$context.responseLatency",
      "context.status": "$context.status",
      "context.stage": "$context.stage"
 }

and the response is:

 {
      "errorMessage":"",
      "messageString":"",

      "context.errorMessage":"",
      "context.messageString":"",

      "context.error.errorMessage":"",
      "context.error.messageString":"null",

      "context.authorizer.error.errorMessage":""
      "context.authorizer.error.errorMessage":""
      "context.authorizer.errorMessage":""
      "context.authorizer.messageString":""

      "type": "AUTHORIZER_CONFIGURATION_ERROR",
      "statusCode": "'404'",
      "stage": "prod",
      "resourcePath": "/ticket",
      "stageVariables.a": "",

      "context.apiId": "xxxx",
      "context.authorizer.claims.property": "",
      "context.authorizer.principalId": "",
      "context.authorizer.property": "",
      "context.httpMethod": "GET",
      "context.error.message": "",
      "context.error.messageString": "null",
      "context.error.responseType": "AUTHORIZER_CONFIGURATION_ERROR",
      "context.extendedRequestId": "xxxx=",
      "context.identity.accountId": "",
      "context.identity.apiKey": "",
      "context.identity.apiKeyId": "",
      "context.identity.caller": "",
      "context.identity.cognitoAuthenticationProvider": "",
      "context.identity.cognitoAuthenticationType": "",
      "context.identity.cognitoIdentityId": "",
      "context.identity.cognitoIdentityPoolId": "",
      "context.identity.sourceIp": "xxx.244.xxx.2",
      "context.identity.user": "",
      "context.identity.userAgent": "curl/7.47.0",
      "context.identity.userArn": "",
      "context.integrationLatency": "",
      "context.path": "/prod/ticket",
      "context.protocol": "HTTP/1.1",
      "context.requestId": "57e2462d-681c-xxxx-7dd93186dc68",
      "context.requestTime": "04/Jun/2018:17:25:57 +0000",
      "context.requestTimeEpoch": "1528133157762",
      "context.resourceId": "pz9fb8",
      "context.resourcePath": "/ticket",
      "context.responseLength": "",
      "context.responseLatency": "",
      "context.status": "",
      "context.stage": "prod"


 }

I've read:

and some more on AWS forums.

2 个答案:

答案 0 :(得分:5)

以防万一:

CA =自定义授权者

  • 错误代码 :AWS并未完全允许CA实施指示发送回调用方的错误代码。
    • 如果CA返回的Auth Policy中没有使用操作 Allow 的语句之一调用的资源/方法,则用户将收到403,其内容类似于“未授权访问资源” “
    • 如果CA返回的身份验证策略中包含带有被调用的资源/方法的操作 Deny 的语句,则用户将收到403,其中包含诸如“拒绝访问被明确拒绝”之类的内容
    • 如果CA引发的异常具有消息“未经授权”,则用户会收到401,消息为“未经授权”。
    • 如果CA引发任何其他消息异常,则用户会收到HTTP-500内部服务器错误(授权配置错误),并且呼叫被拒绝/未授权。
  • 错误消息 :通过“网关响应”中的“正文映射”模板仅允许静态控制。
    • 例如您可以在“网关响应”中将“未授权[401]”的主体映射模板更新为“我的服务由于某些未知原因不喜欢您”,然后每当CA抛出“未授权”异常时,最终用户都会获得HTTP 401 “由于某些未知原因,我的服务不喜欢您”。
    • 同样,您也可以更新“访问被拒绝[403]”或“授权者配置错误[500]”。但是该消息是静态消息,无法从CA实现中对其进行控制。
    • 不可能可能会有不同的401条消息,例如:
    • 401:由于令牌过期而未经授权。
    • 401:由于缺少范围而未经授权。

其他无关的事情:由于CA在某些情况下会引发异常以传达身份验证失败,因此从度量角度来看,这会增加Lambda ErrorCount度量。因此,该指标不可靠,无法识别“应用程序错误”。

答案 1 :(得分:0)

授权者和网关响应的映射是通过

完成的

https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html

您可以在此处更改退货状态代码以自定义状态代码。

关于错误消息,我只是尝试向授权者在上下文输出中添加一个字段,如此处https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html

所述

并在我的模板映射中为access_denied引用该字段 $ context.authorizer.myErrorMsg

,并且如果我的授权者输出拒绝政策文件,此方法就起作用。

希望有帮助