From 084c9d99d1c071c10cec52f49292ae08029a47ff Mon Sep 17 00:00:00 2001 From: Michael Law <1365977+lawmicha@users.noreply.github.com> Date: Tue, 6 Aug 2024 16:07:01 -0400 Subject: [PATCH 1/6] add Amplify components for AppSync --- .../Configuration/AmplifyOutputsData.swift | 3 +- .../AWSCognitoAuthPlugin+AppSyncSigner.swift | 102 ++++++++++++++++++ .../API/AWSAppSyncConfiguration.swift | 33 ++++++ .../AmplifyAWSCredentialsProvider.swift | 3 + 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift create mode 100644 AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift diff --git a/Amplify/Core/Configuration/AmplifyOutputsData.swift b/Amplify/Core/Configuration/AmplifyOutputsData.swift index 93a2f60e6a..57e388a3ba 100644 --- a/Amplify/Core/Configuration/AmplifyOutputsData.swift +++ b/Amplify/Core/Configuration/AmplifyOutputsData.swift @@ -251,7 +251,8 @@ public struct AmplifyOutputsData: Codable { public struct AmplifyOutputs { /// A closure that resolves the `AmplifyOutputsData` configuration - let resolveConfiguration: () throws -> AmplifyOutputsData + @_spi(InternalAmplifyConfiguration) + public let resolveConfiguration: () throws -> AmplifyOutputsData /// Resolves configuration with `amplify_outputs.json` in the main bundle. public static let amplifyOutputs: AmplifyOutputs = { diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift new file mode 100644 index 0000000000..0f7a15d304 --- /dev/null +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift @@ -0,0 +1,102 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation +import AWSClientRuntime // AWSClientRuntime.CredentialsProviding +import ClientRuntime // SdkHttpRequestBuilder +import InternalAmplifyCredentials // AmplifyAWSCredentialsProvider() +import AwsCommonRuntimeKit // CommonRuntimeKit.initialize() + +extension AWSCognitoAuthPlugin { + + public static func createAppSyncSigner(region: String) -> ((URLRequest) async throws -> URLRequest) { + return { request in + try await signAppSyncRequest(request, region: region) + } + } + public static func signAppSyncRequest(_ urlRequest: URLRequest, + region: Swift.String, + credentialsProvider: AWSClientRuntime.CredentialsProviding = AmplifyAWSCredentialsProvider(), + signingName: Swift.String = "appsync", + date: ClientRuntime.Date = Date()) async throws -> URLRequest { + CommonRuntimeKit.initialize() + + // Convert URLRequest to SDK's HTTPRequest + guard let requestBuilder = try createAppSyncSdkHttpRequestBuilder( + urlRequest: urlRequest) else { + return urlRequest + } + + // Retrieve the credentials from credentials provider + let credentials = try await credentialsProvider.getCredentials() + + // Prepare signing + let flags = SigningFlags(useDoubleURIEncode: true, + shouldNormalizeURIPath: true, + omitSessionToken: false) + let signedBodyHeader: AWSSignedBodyHeader = .none + let signedBodyValue: AWSSignedBodyValue = .empty + let signingConfig = AWSSigningConfig(credentials: credentials, + signedBodyHeader: signedBodyHeader, + signedBodyValue: signedBodyValue, + flags: flags, + date: date, + service: signingName, + region: region, + signatureType: .requestHeaders, + signingAlgorithm: .sigv4) + + // Sign request + guard let httpRequest = await AWSSigV4Signer.sigV4SignedRequest( + requestBuilder: requestBuilder, + + signingConfig: signingConfig + ) else { + return urlRequest + } + + // Update original request with new headers + return setHeaders(from: httpRequest, to: urlRequest) + } + + static func setHeaders(from sdkRequest: SdkHttpRequest, to urlRequest: URLRequest) -> URLRequest { + var urlRequest = urlRequest + for header in sdkRequest.headers.headers { + urlRequest.setValue(header.value.joined(separator: ","), forHTTPHeaderField: header.name) + } + return urlRequest + } + + static func createAppSyncSdkHttpRequestBuilder(urlRequest: URLRequest) throws -> SdkHttpRequestBuilder? { + + guard let url = urlRequest.url, + let host = url.host else { + return nil + } + + var headers = urlRequest.allHTTPHeaderFields ?? [:] + headers.updateValue(host, forKey: "host") + + let httpMethod = (urlRequest.httpMethod?.uppercased()) + .flatMap(HttpMethodType.init(rawValue:)) ?? .get + + let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems? + .map { ClientRuntime.SDKURLQueryItem(name: $0.name, value: $0.value)} ?? [] + + let requestBuilder = SdkHttpRequestBuilder() + .withHost(host) + .withPath(url.path) + .withQueryItems(queryItems) + .withMethod(httpMethod) + .withPort(443) + .withProtocol(.https) + .withHeaders(.init(headers)) + .withBody(.data(urlRequest.httpBody)) + + return requestBuilder + } +} diff --git a/AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift b/AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift new file mode 100644 index 0000000000..c83554c04d --- /dev/null +++ b/AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift @@ -0,0 +1,33 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation +@_spi(InternalAmplifyConfiguration) import Amplify + +public struct AWSAppSyncConfiguration { + public let region: String + public let endpoint: URL + public let apiKey: String? + + public init(with amplifyOutputs: AmplifyOutputs) throws { + let resolvedConfiguration = try amplifyOutputs.resolveConfiguration() + + guard let dataCategory = resolvedConfiguration.data else { + throw ConfigurationError.invalidAmplifyOutputsFile( + "Missing data category", "", nil) + } + + self.region = dataCategory.awsRegion + guard let endpoint = URL(string: dataCategory.url) else { + throw ConfigurationError.invalidAmplifyOutputsFile( + "Missing region from data category", "", nil) + } + self.endpoint = endpoint + self.apiKey = dataCategory.apiKey + + } +} diff --git a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift index 63d1197a6d..633ae9e986 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift @@ -13,6 +13,9 @@ import Foundation public class AmplifyAWSCredentialsProvider: AWSClientRuntime.CredentialsProviding { + public init() { + } + public func getCredentials() async throws -> AWSClientRuntime.AWSCredentials { let authSession = try await Amplify.Auth.fetchAuthSession() if let awsCredentialsProvider = authSession as? AuthAWSCredentialsProvider { From 151256a4920e07ca3c18edf0239a7b7dbfd7344d Mon Sep 17 00:00:00 2001 From: Michael Law <1365977+lawmicha@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:47:54 -0400 Subject: [PATCH 2/6] Add AWSAppSyncConfigurationTests --- .../API/AWSAppSyncConfigurationTests.swift | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 AmplifyPlugins/Core/AWSPluginsCoreTests/API/AWSAppSyncConfigurationTests.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCoreTests/API/AWSAppSyncConfigurationTests.swift b/AmplifyPlugins/Core/AWSPluginsCoreTests/API/AWSAppSyncConfigurationTests.swift new file mode 100644 index 0000000000..42813dc3f7 --- /dev/null +++ b/AmplifyPlugins/Core/AWSPluginsCoreTests/API/AWSAppSyncConfigurationTests.swift @@ -0,0 +1,31 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +import AWSPluginsCore +@_spi(InternalAmplifyConfiguration) @testable import Amplify + +final class AWSAppSyncConfigurationTests: XCTestCase { + + func testSuccess() throws { + let config = AmplifyOutputsData(data: .init( + awsRegion: "us-east-1", + url: "http://www.example.com", + modelIntrospection: nil, + apiKey: "apiKey123", + defaultAuthorizationType: .amazonCognitoUserPools, + authorizationTypes: [.apiKey, .awsIAM])) + let encoder = JSONEncoder() + let data = try! encoder.encode(config) + + let configuration = try AWSAppSyncConfiguration(with: .data(data)) + + XCTAssertEqual(configuration.region, "us-east-1") + XCTAssertEqual(configuration.endpoint, URL(string: "http://www.example.com")!) + XCTAssertEqual(configuration.apiKey, "apiKey123") + } +} From 8596b1a5068afd6dccc47761a8e75e424d584c89 Mon Sep 17 00:00:00 2001 From: Michael Law <1365977+lawmicha@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:52:39 -0400 Subject: [PATCH 3/6] Add signing tests --- ...SCognitoAuthPluginAppSyncSignerTests.swift | 40 +++++++++++++++++++ .../AuthHostApp.xcodeproj/project.pbxproj | 12 ++++++ .../AppSyncSignerTests.swift | 36 +++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift create mode 100644 AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift new file mode 100644 index 0000000000..609fe1c774 --- /dev/null +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift @@ -0,0 +1,40 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Amplify +@testable import AWSCognitoAuthPlugin + +class AWSCognitoAuthPluginAppSyncSignerTests: XCTestCase { + + /// Tests translating the URLRequest to the SDKRequest + /// The translation should account for expected fields, as asserted in the test. + func testCreateAppSyncSdkHttpRequestBuilder() throws { + var urlRequest = URLRequest(url: URL(string: "http://graphql.com")!) + urlRequest.httpMethod = "post" + let dataObject = Data() + urlRequest.httpBody = dataObject + guard let sdkRequestBuilder = try AWSCognitoAuthPlugin.createAppSyncSdkHttpRequestBuilder(urlRequest: urlRequest) else { + XCTFail("Could not create SDK request") + return + } + + let request = sdkRequestBuilder.build() + XCTAssertEqual(request.host, "graphql.com") + XCTAssertEqual(request.path, "") + XCTAssertEqual(request.queryItems, []) + XCTAssertEqual(request.method, .post) + XCTAssertEqual(request.endpoint.port, 443) + XCTAssertEqual(request.endpoint.protocolType, .https) + XCTAssertEqual(request.endpoint.headers?.headers, [.init(name: "host", value: "graphql.com")]) + guard case let .data(data) = request.body else { + XCTFail("Unexpected body") + return + } + XCTAssertEqual(data, dataObject) + } +} diff --git a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthHostApp.xcodeproj/project.pbxproj b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthHostApp.xcodeproj/project.pbxproj index efe5f198a7..2444c39e1a 100644 --- a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthHostApp.xcodeproj/project.pbxproj +++ b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthHostApp.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 21CFD7C62C7524570071C70F /* AppSyncSignerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21CFD7C52C7524570071C70F /* AppSyncSignerTests.swift */; }; 21F762A52BD6B1AA0048845A /* AuthSessionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 485CB5B727B61F0F006CCEC7 /* AuthSessionHelper.swift */; }; 21F762A62BD6B1AA0048845A /* AsyncTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 681DFEA828E747B80000C36A /* AsyncTesting.swift */; }; 21F762A72BD6B1AA0048845A /* AuthSRPSignInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 485CB5BE27B61F1D006CCEC7 /* AuthSRPSignInTests.swift */; }; @@ -169,6 +170,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 21CFD7C52C7524570071C70F /* AppSyncSignerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSyncSignerTests.swift; sourceTree = ""; }; 21F762CB2BD6B1AA0048845A /* AuthGen2IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AuthGen2IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 21F762CC2BD6B1CD0048845A /* AuthGen2IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = AuthGen2IntegrationTests.xctestplan; sourceTree = ""; }; 4821B2F1286B5F74000EC1D7 /* AuthDeleteUserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthDeleteUserTests.swift; sourceTree = ""; }; @@ -268,6 +270,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 21CFD7C42C75243B0071C70F /* AppSyncSignerTests */ = { + isa = PBXGroup; + children = ( + 21CFD7C52C7524570071C70F /* AppSyncSignerTests.swift */, + ); + path = AppSyncSignerTests; + sourceTree = ""; + }; 4821B2F0286B5F74000EC1D7 /* AuthDeleteUserTests */ = { isa = PBXGroup; children = ( @@ -355,6 +365,7 @@ 485CB5A027B61E04006CCEC7 /* AuthIntegrationTests */ = { isa = PBXGroup; children = ( + 21CFD7C42C75243B0071C70F /* AppSyncSignerTests */, 21F762CC2BD6B1CD0048845A /* AuthGen2IntegrationTests.xctestplan */, 48916F362A412AF800E3E1B1 /* MFATests */, 97B370C32878DA3500F1C088 /* DeviceTests */, @@ -851,6 +862,7 @@ 681DFEAC28E747B80000C36A /* AsyncExpectation.swift in Sources */, 48E3AB3128E52590004EE395 /* GetCurrentUserTests.swift in Sources */, 48916F3A2A412CEE00E3E1B1 /* TOTPHelper.swift in Sources */, + 21CFD7C62C7524570071C70F /* AppSyncSignerTests.swift in Sources */, 485CB5B127B61EAC006CCEC7 /* AWSAuthBaseTest.swift in Sources */, 485CB5C027B61F1E006CCEC7 /* SignedOutAuthSessionTests.swift in Sources */, 485CB5BA27B61F10006CCEC7 /* AuthSignInHelper.swift in Sources */, diff --git a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift new file mode 100644 index 0000000000..d4311b4885 --- /dev/null +++ b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift @@ -0,0 +1,36 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Amplify +import AWSCognitoAuthPlugin + +class AppSyncSignerTests: AWSAuthBaseTest { + + /// Test signing an AppSync request with a live credentials provider + /// + /// - Given: Base test configures Amplify and adds AWSCognitoAuthPlugin + /// - When: + /// - I invoke AWSCognitoAuthPlugin.signAppSyncRequest(request, region) + /// - Then: + /// - I should get a signed request. + /// + func testSignAppSyncRequest() async throws { + let request = URLRequest(url: URL(string: "http://graphql.com")!) + let signedRequest = try await AWSCognitoAuthPlugin.signAppSyncRequest(request, region: "us-east-1") + + guard let headers = signedRequest.allHTTPHeaderFields else { + XCTFail("Missing headers") + return + } + XCTAssertEqual(headers.count, 4) + let containsExpectedHeaders = headers.keys.contains(where: { key in + key == "Authorization" || key == "Host" || key == "X-Amz-Security-Token" || key == "X-Amz-Date" + }) + XCTAssertTrue(containsExpectedHeaders) + } +} From f7cf339859a521004ca476691618a87c0c0c5787 Mon Sep 17 00:00:00 2001 From: Michael Law <1365977+lawmicha@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:44:35 -0400 Subject: [PATCH 4/6] remove unnecessary public apis --- .../AWSCognitoAuthPlugin+AppSyncSigner.swift | 45 +++++++++++++++---- .../AppSyncSignerTests.swift | 6 +-- .../AmplifyAWSCredentialsProvider.swift | 5 +-- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift index 0f7a15d304..c0fb27d26a 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift @@ -6,23 +6,25 @@ // import Foundation +import Amplify // Amplify.Auth +import AWSPluginsCore // AuthAWSCredentialsProvider import AWSClientRuntime // AWSClientRuntime.CredentialsProviding import ClientRuntime // SdkHttpRequestBuilder -import InternalAmplifyCredentials // AmplifyAWSCredentialsProvider() import AwsCommonRuntimeKit // CommonRuntimeKit.initialize() extension AWSCognitoAuthPlugin { public static func createAppSyncSigner(region: String) -> ((URLRequest) async throws -> URLRequest) { return { request in - try await signAppSyncRequest(request, region: region) + try await signAppSyncRequest(request, + region: region) } } - public static func signAppSyncRequest(_ urlRequest: URLRequest, - region: Swift.String, - credentialsProvider: AWSClientRuntime.CredentialsProviding = AmplifyAWSCredentialsProvider(), - signingName: Swift.String = "appsync", - date: ClientRuntime.Date = Date()) async throws -> URLRequest { + + static func signAppSyncRequest(_ urlRequest: URLRequest, + region: Swift.String, + signingName: Swift.String = "appsync", + date: ClientRuntime.Date = Date()) async throws -> URLRequest { CommonRuntimeKit.initialize() // Convert URLRequest to SDK's HTTPRequest @@ -32,7 +34,15 @@ extension AWSCognitoAuthPlugin { } // Retrieve the credentials from credentials provider - let credentials = try await credentialsProvider.getCredentials() + let credentials: AWSClientRuntime.AWSCredentials + let authSession = try await Amplify.Auth.fetchAuthSession() + if let awsCredentialsProvider = authSession as? AuthAWSCredentialsProvider { + let awsCredentials = try awsCredentialsProvider.getAWSCredentials().get() + credentials = awsCredentials.toAWSSDKCredentials() + } else { + let error = AuthError.unknown("Auth session does not include AWS credentials information") + throw error + } // Prepare signing let flags = SigningFlags(useDoubleURIEncode: true, @@ -100,3 +110,22 @@ extension AWSCognitoAuthPlugin { return requestBuilder } } + +extension AWSPluginsCore.AWSCredentials { + + func toAWSSDKCredentials() -> AWSClientRuntime.AWSCredentials { + if let tempCredentials = self as? AWSTemporaryCredentials { + return AWSClientRuntime.AWSCredentials( + accessKey: tempCredentials.accessKeyId, + secret: tempCredentials.secretAccessKey, + expirationTimeout: tempCredentials.expiration, + sessionToken: tempCredentials.sessionToken) + } else { + return AWSClientRuntime.AWSCredentials( + accessKey: accessKeyId, + secret: secretAccessKey, + expirationTimeout: Date()) + } + + } +} diff --git a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift index d4311b4885..02cedefdfb 100644 --- a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift +++ b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift @@ -15,14 +15,14 @@ class AppSyncSignerTests: AWSAuthBaseTest { /// /// - Given: Base test configures Amplify and adds AWSCognitoAuthPlugin /// - When: - /// - I invoke AWSCognitoAuthPlugin.signAppSyncRequest(request, region) + /// - I invoke AWSCognitoAuthPlugin's AppSync signer /// - Then: /// - I should get a signed request. /// func testSignAppSyncRequest() async throws { let request = URLRequest(url: URL(string: "http://graphql.com")!) - let signedRequest = try await AWSCognitoAuthPlugin.signAppSyncRequest(request, region: "us-east-1") - + let signer = AWSCognitoAuthPlugin.createAppSyncSigner(region: "us-east-1") + let signedRequest = try await signer(request) guard let headers = signedRequest.allHTTPHeaderFields else { XCTFail("Missing headers") return diff --git a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift index 633ae9e986..8a45c1d64a 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift @@ -12,10 +12,7 @@ import AWSPluginsCore import Foundation public class AmplifyAWSCredentialsProvider: AWSClientRuntime.CredentialsProviding { - - public init() { - } - + public func getCredentials() async throws -> AWSClientRuntime.AWSCredentials { let authSession = try await Amplify.Auth.fetchAuthSession() if let awsCredentialsProvider = authSession as? AuthAWSCredentialsProvider { From 77bdbbb6e1fd64e40e6c9925245974cb7633aea9 Mon Sep 17 00:00:00 2001 From: Michael Law <1365977+lawmicha@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:52:17 -0400 Subject: [PATCH 5/6] add doc comments --- .../AWSCognitoAuthPlugin+AppSyncSigner.swift | 9 +++++++++ .../API/AWSAppSyncConfiguration.swift | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift index c0fb27d26a..b77c3ad92e 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift @@ -14,6 +14,15 @@ import AwsCommonRuntimeKit // CommonRuntimeKit.initialize() extension AWSCognitoAuthPlugin { + + /// Creates a AWS IAM SigV4 signer capable of signing AWS AppSync requests. + /// + /// **Note**. Although this method is static, **Amplify.Auth** is required to be configured with **AWSCognitoAuthPlugin** as + /// it depends on the credentials provider from Cognito through `Amplify.Auth.fetchAuthSession()`. The static type allows + /// developers to simplify their callsite without having to access the method on the plugin instance. + /// + /// - Parameter region: The region of the AWS AppSync API + /// - Returns: A closure that takes in a requestand returns a signed request. public static func createAppSyncSigner(region: String) -> ((URLRequest) async throws -> URLRequest) { return { request in try await signAppSyncRequest(request, diff --git a/AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift b/AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift index c83554c04d..e7d41af6d7 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/API/AWSAppSyncConfiguration.swift @@ -8,11 +8,25 @@ import Foundation @_spi(InternalAmplifyConfiguration) import Amplify + +/// Hold necessary AWS AppSync configuration values to interact with the AppSync API public struct AWSAppSyncConfiguration { + + /// The region of the AWS AppSync API public let region: String + + /// The endpoint of the AWS AppSync API public let endpoint: URL + + /// API key for API Key authentication. public let apiKey: String? + + /// Initializes an `AWSAppSyncConfiguration` instance using the provided AmplifyOutputs file. + /// AmplifyOutputs support multiple ways to read the `amplify_outputs.json` configuration file + /// + /// For example, `try AWSAppSyncConfiguraton(with: .amplifyOutputs)` will read the + /// `amplify_outputs.json` file from the main bundle. public init(with amplifyOutputs: AmplifyOutputs) throws { let resolvedConfiguration = try amplifyOutputs.resolveConfiguration() @@ -28,6 +42,5 @@ public struct AWSAppSyncConfiguration { } self.endpoint = endpoint self.apiKey = dataCategory.apiKey - } } From ad009bca54d0147beee285bb76880300637ec181 Mon Sep 17 00:00:00 2001 From: aws-amplify-ops Date: Wed, 21 Aug 2024 16:59:33 +0000 Subject: [PATCH 6/6] Update API dumps for new version --- api-dump/AWSDataStorePlugin.json | 2 +- api-dump/AWSPluginsCore.json | 192 +++++++++++++++++++++++++- api-dump/Amplify.json | 76 +++++++++- api-dump/CoreMLPredictionsPlugin.json | 2 +- 4 files changed, 268 insertions(+), 4 deletions(-) diff --git a/api-dump/AWSDataStorePlugin.json b/api-dump/AWSDataStorePlugin.json index d436f34410..981969d8c6 100644 --- a/api-dump/AWSDataStorePlugin.json +++ b/api-dump/AWSDataStorePlugin.json @@ -8205,7 +8205,7 @@ "-module", "AWSDataStorePlugin", "-o", - "\/var\/folders\/hw\/1f0gcr8d6kn9ms0_wn0_57qc0000gn\/T\/tmp.rjSPtedPzR\/AWSDataStorePlugin.json", + "\/var\/folders\/4d\/0gnh84wj53j7wyk695q0tc_80000gn\/T\/tmp.BZQxGLOyZz\/AWSDataStorePlugin.json", "-I", ".build\/debug", "-sdk-version", diff --git a/api-dump/AWSPluginsCore.json b/api-dump/AWSPluginsCore.json index 76cf8a6e6c..088d2a9ea1 100644 --- a/api-dump/AWSPluginsCore.json +++ b/api-dump/AWSPluginsCore.json @@ -136,6 +136,196 @@ "mangledName": "$s14AWSPluginsCore21AWSAPIAuthInformationP", "moduleName": "AWSPluginsCore" }, + { + "kind": "TypeDecl", + "name": "AWSAppSyncConfiguration", + "printedName": "AWSAppSyncConfiguration", + "children": [ + { + "kind": "Var", + "name": "region", + "printedName": "region", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Var", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV6regionSSvp", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV6regionSSvp", + "moduleName": "AWSPluginsCore", + "declAttributes": [ + "HasStorage" + ], + "isLet": true, + "hasStorage": true, + "accessors": [ + { + "kind": "Accessor", + "name": "Get", + "printedName": "Get()", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Accessor", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV6regionSSvg", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV6regionSSvg", + "moduleName": "AWSPluginsCore", + "implicit": true, + "declAttributes": [ + "Transparent" + ], + "accessorKind": "get" + } + ] + }, + { + "kind": "Var", + "name": "endpoint", + "printedName": "endpoint", + "children": [ + { + "kind": "TypeNominal", + "name": "URL", + "printedName": "Foundation.URL", + "usr": "s:10Foundation3URLV" + } + ], + "declKind": "Var", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV8endpoint10Foundation3URLVvp", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV8endpoint10Foundation3URLVvp", + "moduleName": "AWSPluginsCore", + "declAttributes": [ + "HasStorage" + ], + "isLet": true, + "hasStorage": true, + "accessors": [ + { + "kind": "Accessor", + "name": "Get", + "printedName": "Get()", + "children": [ + { + "kind": "TypeNominal", + "name": "URL", + "printedName": "Foundation.URL", + "usr": "s:10Foundation3URLV" + } + ], + "declKind": "Accessor", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV8endpoint10Foundation3URLVvg", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV8endpoint10Foundation3URLVvg", + "moduleName": "AWSPluginsCore", + "implicit": true, + "declAttributes": [ + "Transparent" + ], + "accessorKind": "get" + } + ] + }, + { + "kind": "Var", + "name": "apiKey", + "printedName": "apiKey", + "children": [ + { + "kind": "TypeNominal", + "name": "Optional", + "printedName": "Swift.String?", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "usr": "s:Sq" + } + ], + "declKind": "Var", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV6apiKeySSSgvp", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV6apiKeySSSgvp", + "moduleName": "AWSPluginsCore", + "declAttributes": [ + "HasStorage" + ], + "isLet": true, + "hasStorage": true, + "accessors": [ + { + "kind": "Accessor", + "name": "Get", + "printedName": "Get()", + "children": [ + { + "kind": "TypeNominal", + "name": "Optional", + "printedName": "Swift.String?", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "usr": "s:Sq" + } + ], + "declKind": "Accessor", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV6apiKeySSSgvg", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV6apiKeySSSgvg", + "moduleName": "AWSPluginsCore", + "implicit": true, + "declAttributes": [ + "Transparent" + ], + "accessorKind": "get" + } + ] + }, + { + "kind": "Constructor", + "name": "init", + "printedName": "init(with:)", + "children": [ + { + "kind": "TypeNominal", + "name": "AWSAppSyncConfiguration", + "printedName": "AWSPluginsCore.AWSAppSyncConfiguration", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV" + }, + { + "kind": "TypeNominal", + "name": "AmplifyOutputs", + "printedName": "Amplify.AmplifyOutputs", + "usr": "s:7Amplify0A7OutputsV" + } + ], + "declKind": "Constructor", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV4withAC7Amplify0G7OutputsV_tKcfc", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV4withAC7Amplify0G7OutputsV_tKcfc", + "moduleName": "AWSPluginsCore", + "throwing": true, + "init_kind": "Designated" + } + ], + "declKind": "Struct", + "usr": "s:14AWSPluginsCore23AWSAppSyncConfigurationV", + "mangledName": "$s14AWSPluginsCore23AWSAppSyncConfigurationV", + "moduleName": "AWSPluginsCore" + }, { "kind": "TypeDecl", "name": "AppSyncErrorType", @@ -24273,7 +24463,7 @@ "-module", "AWSPluginsCore", "-o", - "\/var\/folders\/hw\/1f0gcr8d6kn9ms0_wn0_57qc0000gn\/T\/tmp.rjSPtedPzR\/AWSPluginsCore.json", + "\/var\/folders\/4d\/0gnh84wj53j7wyk695q0tc_80000gn\/T\/tmp.BZQxGLOyZz\/AWSPluginsCore.json", "-I", ".build\/debug", "-sdk-version", diff --git a/api-dump/Amplify.json b/api-dump/Amplify.json index c8b9c833c4..70967c7128 100644 --- a/api-dump/Amplify.json +++ b/api-dump/Amplify.json @@ -155992,6 +155992,80 @@ "name": "AmplifyOutputs", "printedName": "AmplifyOutputs", "children": [ + { + "kind": "Var", + "name": "resolveConfiguration", + "printedName": "resolveConfiguration", + "children": [ + { + "kind": "TypeFunc", + "name": "Function", + "printedName": "() throws -> Amplify.AmplifyOutputsData", + "children": [ + { + "kind": "TypeNominal", + "name": "AmplifyOutputsData", + "printedName": "Amplify.AmplifyOutputsData", + "usr": "s:7Amplify0A11OutputsDataV" + }, + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + } + ] + } + ], + "declKind": "Var", + "usr": "s:7Amplify0A7OutputsV20resolveConfigurationAA0aB4DataVyKcvp", + "mangledName": "$s7Amplify0A7OutputsV20resolveConfigurationAA0aB4DataVyKcvp", + "moduleName": "Amplify", + "declAttributes": [ + "SPIAccessControl", + "HasStorage" + ], + "spi_group_names": [ + "InternalAmplifyConfiguration" + ], + "isLet": true, + "hasStorage": true, + "accessors": [ + { + "kind": "Accessor", + "name": "Get", + "printedName": "Get()", + "children": [ + { + "kind": "TypeFunc", + "name": "Function", + "printedName": "() throws -> Amplify.AmplifyOutputsData", + "children": [ + { + "kind": "TypeNominal", + "name": "AmplifyOutputsData", + "printedName": "Amplify.AmplifyOutputsData", + "usr": "s:7Amplify0A11OutputsDataV" + }, + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + } + ] + } + ], + "declKind": "Accessor", + "usr": "s:7Amplify0A7OutputsV20resolveConfigurationAA0aB4DataVyKcvg", + "mangledName": "$s7Amplify0A7OutputsV20resolveConfigurationAA0aB4DataVyKcvg", + "moduleName": "Amplify", + "implicit": true, + "declAttributes": [ + "Transparent" + ], + "accessorKind": "get" + } + ] + }, { "kind": "Var", "name": "amplifyOutputs", @@ -179735,7 +179809,7 @@ "-module", "Amplify", "-o", - "\/var\/folders\/hw\/1f0gcr8d6kn9ms0_wn0_57qc0000gn\/T\/tmp.rjSPtedPzR\/Amplify.json", + "\/var\/folders\/4d\/0gnh84wj53j7wyk695q0tc_80000gn\/T\/tmp.BZQxGLOyZz\/Amplify.json", "-I", ".build\/debug", "-sdk-version", diff --git a/api-dump/CoreMLPredictionsPlugin.json b/api-dump/CoreMLPredictionsPlugin.json index f7aeb94b9c..618df7be0e 100644 --- a/api-dump/CoreMLPredictionsPlugin.json +++ b/api-dump/CoreMLPredictionsPlugin.json @@ -430,7 +430,7 @@ "-module", "CoreMLPredictionsPlugin", "-o", - "\/var\/folders\/hw\/1f0gcr8d6kn9ms0_wn0_57qc0000gn\/T\/tmp.rjSPtedPzR\/CoreMLPredictionsPlugin.json", + "\/var\/folders\/4d\/0gnh84wj53j7wyk695q0tc_80000gn\/T\/tmp.BZQxGLOyZz\/CoreMLPredictionsPlugin.json", "-I", ".build\/debug", "-sdk-version",