Skip to content

Commit

Permalink
finish refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
lawmicha committed Jul 11, 2024
1 parent 802fc16 commit ebd3234
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 129 deletions.
3 changes: 2 additions & 1 deletion Amplify/Core/Configuration/AmplifyOutputsData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import AWSPluginsCore
import AWSClientRuntime // AWSClientRuntime.CredentialsProviding
import ClientRuntime // SdkHttpRequestBuilder
import InternalAmplifyCredentials // AmplifyAWSCredentialsProvider()
import AwsCommonRuntimeKit // CommonRuntimeKit.initialize()

public final class AWSCognitoAuthPlugin: AWSCognitoAuthPluginBehavior {

Expand Down Expand Up @@ -61,7 +62,7 @@ public final class AWSCognitoAuthPlugin: AWSCognitoAuthPluginBehavior {
}

extension AWSCognitoAuthPlugin {
public static func getUserPoolAccessToken() async throws -> String {
public func getUserPoolAccessToken() async throws -> String {
let authSession = try await Amplify.Auth.fetchAuthSession()
guard let tokenResult = getTokenString(from: authSession) else {
let error = AuthError.unknown("Did not receive a valid response from fetchAuthSession for get token.")
Expand All @@ -74,7 +75,8 @@ extension AWSCognitoAuthPlugin {
throw error
}
}
private static func getTokenString(from authSession: AuthSession) -> Result<String, AuthError>? {

private func getTokenString(from authSession: AuthSession) -> Result<String, AuthError>? {
if let result = (authSession as? AuthCognitoTokensProvider)?.getCognitoTokens() {
switch result {
case .success(let tokens):
Expand All @@ -85,132 +87,48 @@ extension AWSCognitoAuthPlugin {
}
return nil
}

}

import AWSClientRuntime // AWSClientRuntime.CredentialsProviding
import ClientRuntime // SdkHttpRequestBuilder
import InternalAmplifyCredentials // AmplifyAWSCredentialsProvider()
import AwsCommonRuntimeKit // CommonRuntimeKit.initialize()

extension AWSCognitoAuthPlugin {
public static func signRequest(_ urlRequest: URLRequest, region: String) async throws -> URLRequest? {

public static func sigV4SignedRequest(_ urlRequest: URLRequest,
region: Swift.String,
credentialsProvider: AWSClientRuntime.CredentialsProviding = AmplifyAWSCredentialsProvider(),
signingName: Swift.String = "appsync",
date: ClientRuntime.Date = Date()) async throws -> URLRequest {
let requestBuilder = try createAppSyncSdkHttpRequestBuilder(
urlRequest: urlRequest,
headers: urlRequest.allHTTPHeaderFields,
body: urlRequest.httpBody)

guard let sdkHttpRequest = try await sigV4SignedRequest(
requestBuilder: requestBuilder,
credentialsProvider: AmplifyAWSCredentialsProvider(),
signingName: "appsync",
signingRegion: region, // region
date: Date()
urlRequest: urlRequest)
CommonRuntimeKit.initialize()
let credentials = try await credentialsProvider.getCredentials()

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)

guard let httpRequest = await AWSSigV4Signer.sigV4SignedRequest(
requestBuilder: requestBuilder,

signingConfig: signingConfig
) else {
//throw APIError.unknown("Unable to sign request", "")
return nil
}

return setHeaders(from: sdkHttpRequest, to: urlRequest)
}
public struct IAM {
let host: String
let authToken: String
let securityToken: String
let amzDate: String
}

public static func getAuthHeader(_ endpoint: URL, with payload: Data, region: String) async throws -> (String, String, String, String)? {
guard let host = endpoint.host else {
return nil
}

/// The process of getting the auth header for an IAM based authentication request is as follows:
///
/// 1. A request is created with the IAM based auth headers (date, accept, content encoding, content type, and
/// additional headers.
let requestBuilder = SdkHttpRequestBuilder()
.withHost(host)
.withPath(endpoint.path)
.withMethod(.post)
.withPort(443)
.withProtocol(.https)
.withHeader(name: "accept", value: "application/json, text/javascript")
.withHeader(name: "content-encoding", value: "amz-1.0")
.withHeader(name: "Content-Type", value: "application/json; charset=UTF-8")
.withHeader(name: "host", value: host)
.withBody(.data(payload))

/// 2. The request is SigV4 signed by using all the available headers on the request. By signing the request, the signature is added to
/// the request headers as authorization and security token.
do {
guard let urlRequest = try await sigV4SignedRequest(
requestBuilder: requestBuilder,
credentialsProvider: AmplifyAWSCredentialsProvider(),
signingName: "appsync",
signingRegion: region, // region
date: Date())
else {
print("Unable to sign request")
return nil
}

// TODO: Using long lived credentials without getting a session with security token will fail
// since the session token does not exist on the signed request, and is an empty string.
// Once Amplify.Auth is ready to be integrated, this code path needs to be re-tested.
let headers = urlRequest.headers.headers.reduce([String: String]()) { partialResult, header in
switch header.name.lowercased() {
case "authorization", "x-amz-date", "x-amz-security-token":
guard let headerValue = header.value.first else {
return partialResult
}
return partialResult.merging([header.name.lowercased(): headerValue]) { $1 }
default:
return partialResult
}
}

return (
host,
headers["authorization"] ?? "",
headers["x-amz-security-token"] ?? "",
headers["x-amz-date"] ?? ""
)
} catch {
print("Unable to sign request")
return nil
}
}


// Helper

public static func sigV4SignedRequest(requestBuilder: SdkHttpRequestBuilder,
credentialsProvider: AWSClientRuntime.CredentialsProviding,
signingName: Swift.String,
signingRegion: Swift.String,
date: ClientRuntime.Date) async throws -> SdkHttpRequest? {
do {
let credentials = try await credentialsProvider.getCredentials()

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: signingRegion,
signatureType: .requestHeaders,
signingAlgorithm: .sigv4)

let httpRequest = await AWSSigV4Signer.sigV4SignedRequest(
requestBuilder: requestBuilder,
signingConfig: signingConfig
)
return httpRequest
} catch let error {
throw AuthError.unknown("Unable to sign request", error)
fatalError("Failed to sign request")
}
return setHeaders(from: httpRequest, to: urlRequest)
}

static func setHeaders(from sdkRequest: SdkHttpRequest, to urlRequest: URLRequest) -> URLRequest {
Expand All @@ -221,15 +139,13 @@ extension AWSCognitoAuthPlugin {
return urlRequest
}

static func createAppSyncSdkHttpRequestBuilder(urlRequest: URLRequest,
headers: [String : String]?,
body: Data?) throws -> SdkHttpRequestBuilder {
static func createAppSyncSdkHttpRequestBuilder(urlRequest: URLRequest) throws -> SdkHttpRequestBuilder {

guard let url = urlRequest.url else {
throw AuthError.unknown("Could not get url from mutable request", nil)
fatalError("Could not get url from mutable request")
}
guard let host = url.host else {
throw AuthError.unknown("Could not get host from mutable request", nil)
fatalError("Could not get host from mutable request")
}
var headers = urlRequest.allHTTPHeaderFields ?? [:]
headers.updateValue(host, forKey: "host")
Expand All @@ -252,4 +168,5 @@ extension AWSCognitoAuthPlugin {

return requestBuilder
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// File.swift
//
//
// Created by Law, Michael on 2024-07-05.
//

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 {
do {
let resolvedConfiguration = try amplifyOutputs.resolveConfiguration()

guard let dataCategory = resolvedConfiguration.data else {
throw ""
}

self.region = dataCategory.awsRegion
guard let endpoint = URL(string: dataCategory.url) else {
throw ""
}
self.endpoint = endpoint
self.apiKey = dataCategory.apiKey

} catch {
throw error
}
}

static var isRunningForSwiftUIPreviews: Bool {
ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] != nil
}
}


extension AWSAppSyncConfiguration: DefaultLogger { }

extension String: Error { }
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Foundation

public class AmplifyAWSCredentialsProvider: AWSClientRuntime.CredentialsProviding {
public init() {
CommonRuntimeKit.initialize()

}
public func getCredentials() async throws -> AWSClientRuntime.AWSCredentials {
let authSession = try await Amplify.Auth.fetchAuthSession()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Amplify
import ClientRuntime
import AWSClientRuntime
import AwsCommonRuntimeKit
import AWSPluginsCore

public protocol AWSSignatureV4Signer {
func sigV4SignedRequest(requestBuilder: SdkHttpRequestBuilder,
Expand Down

0 comments on commit ebd3234

Please sign in to comment.