diff --git a/Sources/AWSLambdaEvents/APIGateway+V2.swift b/Sources/AWSLambdaEvents/APIGateway+V2.swift index 8c8bed3..9069ac6 100644 --- a/Sources/AWSLambdaEvents/APIGateway+V2.swift +++ b/Sources/AWSLambdaEvents/APIGateway+V2.swift @@ -32,7 +32,26 @@ public struct APIGatewayV2Request: Codable { public let scopes: [String]? } - public let jwt: JWT + public let jwt: JWT? + + // `IAM` contains AWS IAM authorizer information for the request context. + public struct IAM: Codable { + public struct CognitoIdentity: Codable { + public let amr: [String]? + public let identityId: String? + public let identityPoolId: String? + } + + public let accessKey: String? + public let accountId: String? + public let callerId: String? + public let cognitoIdentity: CognitoIdentity? + public let principalOrgId: String? + public let userArn: String? + public let userId: String? + } + + public let iam: IAM? } public let accountId: String @@ -113,5 +132,7 @@ extension APIGatewayV2Request.Context: Sendable {} extension APIGatewayV2Request.Context.HTTP: Sendable {} extension APIGatewayV2Request.Context.Authorizer: Sendable {} extension APIGatewayV2Request.Context.Authorizer.JWT: Sendable {} +extension APIGatewayV2Request.Context.Authorizer.IAM: Sendable {} +extension APIGatewayV2Request.Context.Authorizer.IAM.CognitoIdentity: Sendable {} extension APIGatewayV2Response: Sendable {} #endif diff --git a/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift b/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift new file mode 100644 index 0000000..f745637 --- /dev/null +++ b/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift @@ -0,0 +1,161 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2017-2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +@testable import AWSLambdaEvents +import XCTest + +class APIGatewayV2IAMTests: XCTestCase { + static let getEventWithIAM = """ + { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/hello", + "rawQueryString": "", + "headers": { + "accept": "*/*", + "authorization": "AWS4-HMAC-SHA256 Credential=ASIA-redacted/us-east-1/execute-api/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=289b5fcef3d1156f019cc1140cb5565cc052880a5a0d5586c753e3e3c75556f9", + "content-length": "0", + "host": "74bxj8iqjc.execute-api.us-east-1.amazonaws.com", + "user-agent": "curl/8.4.0", + "x-amz-date": "20231214T203121Z", + "x-amz-security-token": "IQoJb3JpZ2luX2VjEO3//////////-redacted", + "x-amzn-trace-id": "Root=1-657b6619-3222de40051925dd66e1fd72", + "x-forwarded-for": "191.95.150.52", + "x-forwarded-port": "443", + "x-forwarded-proto": "https" + }, + "requestContext": { + "accountId": "012345678912", + "apiId": "74bxj8iqjc", + "authorizer": { + "iam": { + "accessKey": "ASIA-redacted", + "accountId": "012345678912", + "callerId": "AIDA-redacted", + "cognitoIdentity": null, + "principalOrgId": "aws:PrincipalOrgID", + "userArn": "arn:aws:iam::012345678912:user/sst", + "userId": "AIDA-redacted" + } + }, + "domainName": "74bxj8iqjc.execute-api.us-east-1.amazonaws.com", + "domainPrefix": "74bxj8iqjc", + "http": { + "method": "GET", + "path": "/liveness", + "protocol": "HTTP/1.1", + "sourceIp": "191.95.150.52", + "userAgent": "curl/8.4.0" + }, + "requestId": "P8zkDiQ8oAMEJsQ=", + "routeKey": "$default", + "stage": "$default", + "time": "14/Dec/2023:20:31:21 +0000", + "timeEpoch": 1702585881671 + }, + "isBase64Encoded": false + } + """ + + static let getEventWithIAMAndCognito = """ + { + "version": "2.0", + "routeKey": "$default", + "rawPath": "/hello", + "rawQueryString": "", + "headers": { + "accept": "*/*", + "authorization": "AWS4-HMAC-SHA256 Credential=ASIA-redacted/us-east-1/execute-api/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=289b5fcef3d1156f019cc1140cb5565cc052880a5a0d5586c753e3e3c75556f9", + "content-length": "0", + "host": "74bxj8iqjc.execute-api.us-east-1.amazonaws.com", + "user-agent": "curl/8.4.0", + "x-amz-date": "20231214T203121Z", + "x-amz-security-token": "IQoJb3JpZ2luX2VjEO3//////////-redacted", + "x-amzn-trace-id": "Root=1-657b6619-3222de40051925dd66e1fd72", + "x-forwarded-for": "191.95.150.52", + "x-forwarded-port": "443", + "x-forwarded-proto": "https" + }, + "requestContext": { + "accountId": "012345678912", + "apiId": "74bxj8iqjc", + "authorizer": { + "iam": { + "accessKey": "ASIA-redacted", + "accountId": "012345678912", + "callerId": "AROA-redacted:CognitoIdentityCredentials", + "cognitoIdentity": { + "amr": [ + "authenticated", + "cognito-idp.us-east-1.amazonaws.com/us-east-1_ABCD", + "cognito-idp.us-east-1.amazonaws.com/us-east-1_ABCD:CognitoSignIn:04611e3d--redacted" + ], + "identityId": "us-east-1:68bc0ecd-9d5e--redacted", + "identityPoolId": "us-east-1:e8b526df--redacted" + }, + "principalOrgId": "aws:PrincipalOrgID", + "userArn": "arn:aws:sts::012345678912:assumed-role/authRole/CognitoIdentityCredentials", + "userId": "AROA-redacted:CognitoIdentityCredentials" + } + }, + "domainName": "74bxj8iqjc.execute-api.us-east-1.amazonaws.com", + "domainPrefix": "74bxj8iqjc", + "http": { + "method": "GET", + "path": "/liveness", + "protocol": "HTTP/1.1", + "sourceIp": "191.95.150.52", + "userAgent": "curl/8.4.0" + }, + "requestId": "P8zkDiQ8oAMEJsQ=", + "routeKey": "$default", + "stage": "$default", + "time": "14/Dec/2023:20:31:21 +0000", + "timeEpoch": 1702585881671 + }, + "isBase64Encoded": false + } + """ + + // MARK: - Request - + + // MARK: Decoding + + func testRequestDecodingGetRequestWithIAM() { + let data = APIGatewayV2IAMTests.getEventWithIAM.data(using: .utf8)! + var req: APIGatewayV2Request? + XCTAssertNoThrow(req = try JSONDecoder().decode(APIGatewayV2Request.self, from: data)) + + XCTAssertEqual(req?.rawPath, "/hello") + XCTAssertEqual(req?.context.authorizer?.iam?.accessKey, "ASIA-redacted") + XCTAssertEqual(req?.context.authorizer?.iam?.accountId, "012345678912") + XCTAssertNil(req?.body) + } + + func testRequestDecodingGetRequestWithIAMWithCognito() { + let data = APIGatewayV2IAMTests.getEventWithIAMAndCognito.data(using: .utf8)! + var req: APIGatewayV2Request? + XCTAssertNoThrow(req = try JSONDecoder().decode(APIGatewayV2Request.self, from: data)) + + XCTAssertEqual(req?.rawPath, "/hello") + XCTAssertEqual(req?.context.authorizer?.iam?.accessKey, "ASIA-redacted") + XCTAssertEqual(req?.context.authorizer?.iam?.accountId, "012345678912") + + // test the cognito identity part + XCTAssertEqual(req?.context.authorizer?.iam?.cognitoIdentity?.identityId, "us-east-1:68bc0ecd-9d5e--redacted") + XCTAssertEqual(req?.context.authorizer?.iam?.cognitoIdentity?.amr?.count, 3) + + XCTAssertNil(req?.body) + } +} diff --git a/Tests/AWSLambdaEventsTests/APIGateway+V2Tests.swift b/Tests/AWSLambdaEventsTests/APIGateway+V2Tests.swift index c32c2d8..12f562e 100644 --- a/Tests/AWSLambdaEventsTests/APIGateway+V2Tests.swift +++ b/Tests/AWSLambdaEventsTests/APIGateway+V2Tests.swift @@ -86,6 +86,8 @@ class APIGatewayV2Tests: XCTestCase { XCTAssertEqual(req?.queryStringParameters?.count, 1) XCTAssertEqual(req?.rawQueryString, "foo=bar") XCTAssertEqual(req?.headers.count, 8) + XCTAssertEqual(req?.context.authorizer?.jwt?.claims?["aud"], "customers") + XCTAssertNil(req?.body) } } diff --git a/docker/docker-compose.al2.56.yaml b/docker/docker-compose.al2.56.yaml index 875df5d..56f4004 100644 --- a/docker/docker-compose.al2.56.yaml +++ b/docker/docker-compose.al2.56.yaml @@ -8,6 +8,9 @@ services: args: swift_version: "5.6" + soundness: + image: swift-aws-lambda-events:al2-5.6 + test: image: swift-aws-lambda-events:al2-5.6 diff --git a/docker/docker-compose.al2.57.yaml b/docker/docker-compose.al2.57.yaml index 17c650a..5b768cc 100644 --- a/docker/docker-compose.al2.57.yaml +++ b/docker/docker-compose.al2.57.yaml @@ -8,6 +8,9 @@ services: args: swift_version: "5.7" + soundness: + image: swift-aws-lambda-events:al2-5.7 + test: image: swift-aws-lambda-events:al2-5.7 diff --git a/docker/docker-compose.al2.58.yaml b/docker/docker-compose.al2.58.yaml index 530a30e..18e05b8 100644 --- a/docker/docker-compose.al2.58.yaml +++ b/docker/docker-compose.al2.58.yaml @@ -8,6 +8,9 @@ services: args: swift_version: "5.8" + soundness: + image: swift-aws-lambda-events:al2-5.8 + test: image: swift-aws-lambda-events:al2-5.8 diff --git a/docker/docker-compose.al2.59.yaml b/docker/docker-compose.al2.59.yaml index 0298cd0..b2550c6 100644 --- a/docker/docker-compose.al2.59.yaml +++ b/docker/docker-compose.al2.59.yaml @@ -8,6 +8,9 @@ services: args: base_image: "swiftlang/swift:nightly-5.9-amazonlinux2" + soundness: + image: swift-aws-lambda-events:al2-5.9 + test: image: swift-aws-lambda-events:al2-5.9 diff --git a/docker/docker-compose.al2.main.yaml b/docker/docker-compose.al2.main.yaml index 19f822c..64b24f7 100644 --- a/docker/docker-compose.al2.main.yaml +++ b/docker/docker-compose.al2.main.yaml @@ -8,6 +8,9 @@ services: args: base_image: "swiftlang/swift:nightly-main-amazonlinux2" + soundness: + image: swift-aws-lambda-events:al2-main + test: image: swift-aws-lambda-events:al2-main