diff --git a/events/apigw.go b/events/apigw.go index ce7fa1cf..83b4cbc8 100644 --- a/events/apigw.go +++ b/events/apigw.go @@ -80,7 +80,9 @@ type APIGatewayV2HTTPRequestContext struct { // APIGatewayV2HTTPRequestContextAuthorizerDescription contains authorizer information for the request context. type APIGatewayV2HTTPRequestContextAuthorizerDescription struct { - JWT APIGatewayV2HTTPRequestContextAuthorizerJWTDescription `json:"jwt"` + JWT *APIGatewayV2HTTPRequestContextAuthorizerJWTDescription `json:"jwt,omitempty"` + Lambda map[string]interface{} `json:"lambda,omitempty"` + IAM *APIGatewayV2HTTPRequestContextAuthorizerIAMDescription `json:"iam,omitempty"` } // APIGatewayV2HTTPRequestContextAuthorizerJWTDescription contains JWT authorizer information for the request context. @@ -89,6 +91,24 @@ type APIGatewayV2HTTPRequestContextAuthorizerJWTDescription struct { Scopes []string `json:"scopes,omitempty"` } +// APIGatewayV2HTTPRequestContextAuthorizerIAMDescription contains IAM information for the request context. +type APIGatewayV2HTTPRequestContextAuthorizerIAMDescription struct { + AccessKey string `json:"accessKey"` + AccountID string `json:"accountId"` + CallerID string `json:"callerId"` + CognitoIdentity APIGatewayV2HTTPRequestContextAuthorizerCognitoIdentity `json:"cognitoIdentity,omitempty"` + PrincipalOrgID string `json:"principalOrgId"` + UserARN string `json:"userArn"` + UserID string `json:"userId"` +} + +// APIGatewayV2HTTPRequestContextAuthorizerCognitoIdentity contains Cognito identity information for the request context. +type APIGatewayV2HTTPRequestContextAuthorizerCognitoIdentity struct { + AMR []string `json:"amr"` + IdentityID string `json:"identityId"` + IdentityPoolID string `json:"identityPoolId"` +} + // APIGatewayV2HTTPRequestContextHTTPDescription contains HTTP information for the request context. type APIGatewayV2HTTPRequestContextHTTPDescription struct { Method string `json:"method"` diff --git a/events/apigw_test.go b/events/apigw_test.go index 913306c3..cf1b82af 100644 --- a/events/apigw_test.go +++ b/events/apigw_test.go @@ -210,10 +210,10 @@ func TestApiGatewayRestApiOpenApiRequestMarshaling(t *testing.T) { assert.JSONEq(t, string(inputJSON), string(outputJSON)) } -func TestApiGatewayV2HTTPRequestMarshaling(t *testing.T) { +func TestApiGatewayV2HTTPRequestJWTAuthorizerMarshaling(t *testing.T) { // read json from file - inputJSON, err := ioutil.ReadFile("./testdata/apigw-v2-request.json") + inputJSON, err := ioutil.ReadFile("./testdata/apigw-v2-request-jwt-authorizer.json") if err != nil { t.Errorf("could not open test file. details: %v", err) } @@ -245,6 +245,100 @@ func TestApiGatewayV2HTTPRequestMarshaling(t *testing.T) { assert.JSONEq(t, string(inputJSON), string(outputJSON)) } +func TestApiGatewayV2HTTPRequestLambdaAuthorizerMarshaling(t *testing.T) { + + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/apigw-v2-request-lambda-authorizer.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into Go object + var inputEvent APIGatewayV2HTTPRequest + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + // validate custom authorizer context + authContext := inputEvent.RequestContext.Authorizer + if authContext.Lambda["key"] != "value" { + t.Errorf("could not extract authorizer information from Lambda authorizer: %v", authContext) + } + + // validate HTTP details + http := inputEvent.RequestContext.HTTP + if http.Path != "/my/path" { + t.Errorf("could not extract HTTP details: %v", http) + } + + // serialize to json + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) +} + +func TestApiGatewayV2HTTPRequestIAMMarshaling(t *testing.T) { + + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/apigw-v2-request-iam.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into Go object + var inputEvent APIGatewayV2HTTPRequest + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + // validate custom authorizer context + authContext := inputEvent.RequestContext.Authorizer + if authContext.IAM.AccessKey != "ARIA2ZJZYVUEREEIHAKY" { + t.Errorf("could not extract accessKey from IAM authorizer: %v", authContext) + } + if authContext.IAM.AccountID != "1234567890" { + t.Errorf("could not extract accountId from IAM authorizer: %v", authContext) + } + if authContext.IAM.CallerID != "AROA7ZJZYVRE7C3DUXHH6:CognitoIdentityCredentials" { + t.Errorf("could not extract callerId from IAM authorizer: %v", authContext) + } + if authContext.IAM.CognitoIdentity.AMR[0] != "foo" { + t.Errorf("could not extract amr from CognitoIdentity: %v", authContext) + } + if authContext.IAM.CognitoIdentity.IdentityID != "us-east-1:3f291106-8703-466b-8f2b-3ecee1ca56ce" { + t.Errorf("could not extract identityId from CognitoIdentity: %v", authContext) + } + if authContext.IAM.CognitoIdentity.IdentityPoolID != "us-east-1:4f291106-8703-466b-8f2b-3ecee1ca56ce" { + t.Errorf("could not extract identityPoolId from CognitoIdentity: %v", authContext) + } + if authContext.IAM.PrincipalOrgID != "AwsOrgId" { + t.Errorf("could not extract principalOrgId from IAM authorizer: %v", authContext) + } + if authContext.IAM.UserARN != "arn:aws:iam::1234567890:user/Admin" { + t.Errorf("could not extract userArn from IAM authorizer: %v", authContext) + } + if authContext.IAM.UserID != "AROA2ZJZYVRE7Y3TUXHH6" { + t.Errorf("could not extract userId from IAM authorizer: %v", authContext) + } + + // validate HTTP details + http := inputEvent.RequestContext.HTTP + if http.Path != "/my/path" { + t.Errorf("could not extract HTTP details: %v", http) + } + + // serialize to json + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) +} + func TestApiGatewayV2HTTPRequestNoAuthorizerMarshaling(t *testing.T) { // read json from file diff --git a/events/testdata/apigw-v2-request-iam.json b/events/testdata/apigw-v2-request-iam.json new file mode 100644 index 00000000..73d50d78 --- /dev/null +++ b/events/testdata/apigw-v2-request-iam.json @@ -0,0 +1,60 @@ +{ + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "Header1": "value1", + "Header2": "value2" + }, + "queryStringParameters": { + "parameter1": "value1,value2", + "parameter2": "value" + }, + "pathParameters": { + "proxy": "hello/world" + }, + "requestContext": { + "routeKey": "$default", + "accountId": "123456789012", + "stage": "$default", + "requestId": "id", + "authorizer": { + "iam": { + "accessKey": "ARIA2ZJZYVUEREEIHAKY", + "accountId": "1234567890", + "callerId": "AROA7ZJZYVRE7C3DUXHH6:CognitoIdentityCredentials", + "cognitoIdentity": { + "amr" : ["foo"], + "identityId": "us-east-1:3f291106-8703-466b-8f2b-3ecee1ca56ce", + "identityPoolId": "us-east-1:4f291106-8703-466b-8f2b-3ecee1ca56ce" + }, + "principalOrgId": "AwsOrgId", + "userArn": "arn:aws:iam::1234567890:user/Admin", + "userId": "AROA2ZJZYVRE7Y3TUXHH6" + } + }, + "apiId": "api-id", + "domainName": "id.execute-api.us-east-1.amazonaws.com", + "domainPrefix": "id", + "time": "12/Mar/2020:19:03:58+0000", + "timeEpoch": 1583348638390, + "http": { + "method": "GET", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "IP", + "userAgent": "agent" + } + }, + "stageVariables": { + "stageVariable1": "value1", + "stageVariable2": "value2" + }, + "body": "{\r\n\t\"a\": 1\r\n}", + "isBase64Encoded": false +} diff --git a/events/testdata/apigw-v2-request.json b/events/testdata/apigw-v2-request-jwt-authorizer.json similarity index 100% rename from events/testdata/apigw-v2-request.json rename to events/testdata/apigw-v2-request-jwt-authorizer.json diff --git a/events/testdata/apigw-v2-request-lambda-authorizer.json b/events/testdata/apigw-v2-request-lambda-authorizer.json new file mode 100644 index 00000000..75d1574f --- /dev/null +++ b/events/testdata/apigw-v2-request-lambda-authorizer.json @@ -0,0 +1,50 @@ +{ + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "Header1": "value1", + "Header2": "value2" + }, + "queryStringParameters": { + "parameter1": "value1,value2", + "parameter2": "value" + }, + "pathParameters": { + "proxy": "hello/world" + }, + "requestContext": { + "routeKey": "$default", + "accountId": "123456789012", + "stage": "$default", + "requestId": "id", + "authorizer": { + "lambda": { + "key": "value" + } + }, + "apiId": "api-id", + "domainName": "id.execute-api.us-east-1.amazonaws.com", + "domainPrefix": "id", + "time": "12/Mar/2020:19:03:58+0000", + "timeEpoch": 1583348638390, + "http": { + "method": "GET", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "IP", + "userAgent": "agent" + } + }, + "stageVariables": { + "stageVariable1": "value1", + "stageVariable2": "value2" + }, + "body": "{\r\n\t\"a\": 1\r\n}", + "isBase64Encoded": false +}