From 44f47669bb4d00d0bef1872d88c8e55da7644425 Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Thu, 14 Dec 2023 16:16:21 -0500 Subject: [PATCH 1/5] add support for IAM authorizers --- Sources/AWSLambdaEvents/APIGateway+V2.swift | 15 +++- .../APIGateway+V2IAMTests.swift | 85 +++++++++++++++++++ .../APIGateway+V2Tests.swift | 2 + 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift diff --git a/Sources/AWSLambdaEvents/APIGateway+V2.swift b/Sources/AWSLambdaEvents/APIGateway+V2.swift index 8c8bed3..d0406be 100644 --- a/Sources/AWSLambdaEvents/APIGateway+V2.swift +++ b/Sources/AWSLambdaEvents/APIGateway+V2.swift @@ -31,8 +31,19 @@ public struct APIGatewayV2Request: Codable { public let claims: [String: String]? 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, Sendable { + public let accessKey: String? + public let accountId: String? + public let callerId: String? + public let cognitoIdentity: String? + public let principalOrgId: String? + public let userArn: String? + public let userId: String? + } + public let iam: IAM? } public let accountId: String diff --git a/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift b/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift new file mode 100644 index 0000000..07bb893 --- /dev/null +++ b/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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 exampleGetEventBody = """ + { + "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 + } + """ + + // MARK: - Request - + + // MARK: Decoding + + func testRequestDecodingExampleGetRequest() { + let data = APIGatewayV2IAMTests.exampleGetEventBody.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) + } +} 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) } } From 8c603b8ec09e24e93e83b85935b142773f836f10 Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Fri, 15 Dec 2023 08:00:52 -0500 Subject: [PATCH 2/5] swiftformat --- Sources/AWSLambdaEvents/APIGateway+V2.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/AWSLambdaEvents/APIGateway+V2.swift b/Sources/AWSLambdaEvents/APIGateway+V2.swift index d0406be..caf6306 100644 --- a/Sources/AWSLambdaEvents/APIGateway+V2.swift +++ b/Sources/AWSLambdaEvents/APIGateway+V2.swift @@ -31,6 +31,7 @@ public struct APIGatewayV2Request: Codable { public let claims: [String: String]? public let scopes: [String]? } + public let jwt: JWT? /// `IAM` contains AWS IAM authorizer information for the request context. @@ -43,6 +44,7 @@ public struct APIGatewayV2Request: Codable { public let userArn: String? public let userId: String? } + public let iam: IAM? } From bb8ea06d1a1dbed6502fc7edaeef21d4b26ea859 Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Fri, 15 Dec 2023 08:01:10 -0500 Subject: [PATCH 3/5] fix soundness check in docker compose --- docker/docker-compose.al2.56.yaml | 3 +++ docker/docker-compose.al2.57.yaml | 3 +++ docker/docker-compose.al2.58.yaml | 3 +++ docker/docker-compose.al2.59.yaml | 3 +++ docker/docker-compose.al2.main.yaml | 3 +++ 5 files changed, 15 insertions(+) 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 From d728f73daf09220aa4820b28ddb2d702a901d5ce Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Fri, 15 Dec 2023 11:51:27 -0500 Subject: [PATCH 4/5] add support for cognito identities inside IAM authentication block --- Sources/AWSLambdaEvents/APIGateway+V2.swift | 13 ++- .../APIGateway+V2IAMTests.swift | 80 ++++++++++++++++++- 2 files changed, 87 insertions(+), 6 deletions(-) diff --git a/Sources/AWSLambdaEvents/APIGateway+V2.swift b/Sources/AWSLambdaEvents/APIGateway+V2.swift index caf6306..a714ccc 100644 --- a/Sources/AWSLambdaEvents/APIGateway+V2.swift +++ b/Sources/AWSLambdaEvents/APIGateway+V2.swift @@ -34,12 +34,17 @@ public struct APIGatewayV2Request: Codable { public let jwt: JWT? - /// `IAM` contains AWS IAM authorizer information for the request context. - public struct IAM: Codable, Sendable { + // `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: String? + public let cognitoIdentity: CognitoIdentity? public let principalOrgId: String? public let userArn: String? public let userId: String? @@ -126,5 +131,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 index 07bb893..cbec3bc 100644 --- a/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift +++ b/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift @@ -16,7 +16,7 @@ import XCTest class APIGatewayV2IAMTests: XCTestCase { - static let exampleGetEventBody = """ + static let getEventWithIAM = """ { "version": "2.0", "routeKey": "$default", @@ -68,18 +68,92 @@ class APIGatewayV2IAMTests: XCTestCase { } """ + 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 testRequestDecodingExampleGetRequest() { - let data = APIGatewayV2IAMTests.exampleGetEventBody.data(using: .utf8)! + 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) } } From 6b7c2b48910232ed00bf5366c62171de9772f6cd Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Fri, 15 Dec 2023 14:43:49 -0500 Subject: [PATCH 5/5] fix formatting issues / soundness checks --- Sources/AWSLambdaEvents/APIGateway+V2.swift | 1 + Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Sources/AWSLambdaEvents/APIGateway+V2.swift b/Sources/AWSLambdaEvents/APIGateway+V2.swift index a714ccc..9069ac6 100644 --- a/Sources/AWSLambdaEvents/APIGateway+V2.swift +++ b/Sources/AWSLambdaEvents/APIGateway+V2.swift @@ -41,6 +41,7 @@ public struct APIGatewayV2Request: Codable { public let identityId: String? public let identityPoolId: String? } + public let accessKey: String? public let accountId: String? public let callerId: String? diff --git a/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift b/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift index cbec3bc..f745637 100644 --- a/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift +++ b/Tests/AWSLambdaEventsTests/APIGateway+V2IAMTests.swift @@ -127,6 +127,7 @@ class APIGatewayV2IAMTests: XCTestCase { "isBase64Encoded": false } """ + // MARK: - Request - // MARK: Decoding @@ -141,6 +142,7 @@ class APIGatewayV2IAMTests: XCTestCase { XCTAssertEqual(req?.context.authorizer?.iam?.accountId, "012345678912") XCTAssertNil(req?.body) } + func testRequestDecodingGetRequestWithIAMWithCognito() { let data = APIGatewayV2IAMTests.getEventWithIAMAndCognito.data(using: .utf8)! var req: APIGatewayV2Request?