diff --git a/Package.swift b/Package.swift index 5060669a3..325ed472c 100644 --- a/Package.swift +++ b/Package.swift @@ -36,8 +36,10 @@ let package = Package( .library(name: "SmithyXML", targets: ["SmithyXML"]), .library(name: "SmithyJSON", targets: ["SmithyJSON"]), .library(name: "SmithyFormURL", targets: ["SmithyFormURL"]), + .library(name: "SmithyIdentity", targets: ["SmithyIdentity"]), .library(name: "SmithyIdentityAPI", targets: ["SmithyIdentityAPI"]), .library(name: "SmithyHTTPAPI", targets: ["SmithyHTTPAPI"]), + .library(name: "SmithyHTTPAuth", targets: ["SmithyHTTPAuth"]), .library(name: "SmithyHTTPAuthAPI", targets: ["SmithyHTTPAuthAPI"]), .library(name: "SmithyEventStreamsAPI", targets: ["SmithyEventStreamsAPI"]), .library(name: "SmithyEventStreamsAuthAPI", targets: ["SmithyEventStreamsAuthAPI"]), @@ -65,8 +67,10 @@ let package = Package( "SmithyXML", "SmithyJSON", "SmithyFormURL", + "SmithyIdentity", "SmithyIdentityAPI", "SmithyHTTPAPI", + "SmithyHTTPAuth", "SmithyHTTPAuthAPI", "SmithyEventStreamsAPI", "SmithyEventStreams", @@ -88,10 +92,6 @@ let package = Package( .product(name: "AwsCommonRuntimeKit", package: "aws-crt-swift"), ] ), - .testTarget( - name: "SmithyRetriesTests", - dependencies: ["ClientRuntime", "SmithyRetriesAPI", "SmithyRetries"] - ), .target( name: "SmithyReadWrite", dependencies: ["SmithyTimestamps"] @@ -126,6 +126,13 @@ let package = Package( name: "SmithyTestUtil", dependencies: ["ClientRuntime"] ), + .target( + name: "SmithyIdentity", + dependencies: [ + "SmithyIdentityAPI", + .product(name: "AwsCommonRuntimeKit", package: "aws-crt-swift") + ] + ), .target( name: "SmithyIdentityAPI", dependencies: ["Smithy"] @@ -134,9 +141,19 @@ let package = Package( name: "SmithyHTTPAPI", dependencies: ["Smithy"] ), + .target( + name: "SmithyHTTPAuth", + dependencies: [ + "Smithy", + "SmithyHTTPAuthAPI", + "SmithyIdentity", + "SmithyIdentityAPI", + .product(name: "AwsCommonRuntimeKit", package: "aws-crt-swift") + ] + ), .target( name: "SmithyHTTPAuthAPI", - dependencies: ["Smithy", "SmithyHTTPAPI"] + dependencies: ["Smithy", "SmithyHTTPAPI", "SmithyIdentityAPI"] ), .target( name: "SmithyEventStreamsAPI", @@ -188,6 +205,10 @@ let package = Package( name: "SmithyEventStreamsTests", dependencies: ["SmithyEventStreams"] ), + .testTarget( + name: "SmithyIdentityTests", + dependencies: ["Smithy", "SmithyIdentity"] + ) ].compactMap { $0 } ) diff --git a/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift b/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift index 90412a9e9..9bf90c7a8 100644 --- a/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift +++ b/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift @@ -99,8 +99,8 @@ public class CRTClientEngine: HTTPClient { #endif let httpMonitoringOptions = HTTPMonitoringOptions( minThroughputBytesPerSecond: 1, - // 0 means infinite; sockets won't timeout if no value was provided in config. - allowableThroughputFailureInterval: socketTimeout ?? 0 + // Default to 60 seconds if no value was provided in config. + allowableThroughputFailureInterval: socketTimeout ?? UInt32(60) ) let options = HTTPClientConnectionOptions( diff --git a/Sources/ClientRuntime/Networking/Http/Middlewares/AuthSchemeMiddleware.swift b/Sources/ClientRuntime/Networking/Http/Middlewares/AuthSchemeMiddleware.swift index a93867642..bb337c250 100644 --- a/Sources/ClientRuntime/Networking/Http/Middlewares/AuthSchemeMiddleware.swift +++ b/Sources/ClientRuntime/Networking/Http/Middlewares/AuthSchemeMiddleware.swift @@ -12,6 +12,7 @@ import class Smithy.Context import class SmithyHTTPAPI.SdkHttpRequestBuilder import struct SmithyHTTPAuthAPI.SelectedAuthScheme import protocol SmithyHTTPAuthAPI.AuthScheme +import struct SmithyHTTPAuth.DefaultIdentityResolverConfiguration public struct AuthSchemeMiddleware: Middleware { public let id: String = "AuthSchemeMiddleware" diff --git a/Sources/ClientRuntime/Signing/SigningAlgorithm+CRT.swift b/Sources/ClientRuntime/Signing/SigningAlgorithm+CRT.swift deleted file mode 100644 index d37736826..000000000 --- a/Sources/ClientRuntime/Signing/SigningAlgorithm+CRT.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright Amazon.com Inc. or its affiliates. -// All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 -// - -import SmithyHTTPAuthAPI -import AwsCommonRuntimeKit - -extension SigningAlgorithm { - - /// Convert self to CRT SigningAlgorithmType - /// - Returns: SigningAlgorithmType - public func toCRTType() -> SigningAlgorithmType { - switch self { - case .sigv4: return .signingV4 - case .sigv4a: return .signingV4Asymmetric - } - } -} diff --git a/Sources/SmithyHTTPAuth/AWSSigningConfig.swift b/Sources/SmithyHTTPAuth/AWSSigningConfig.swift new file mode 100644 index 000000000..4a48c6872 --- /dev/null +++ b/Sources/SmithyHTTPAuth/AWSSigningConfig.swift @@ -0,0 +1,61 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import class SmithyIdentity.CRTAWSCredentialIdentity +import enum SmithyHTTPAuthAPI.SigningAlgorithm +import enum SmithyHTTPAuthAPI.AWSSignedBodyHeader +import enum SmithyHTTPAuthAPI.AWSSignedBodyValue +import enum SmithyHTTPAuthAPI.AWSSignatureType +import protocol SmithyIdentity.AWSCredentialIdentityResolver +import struct Foundation.Date +import struct Foundation.Locale +import struct Foundation.TimeInterval +import struct SmithyHTTPAuthAPI.SigningFlags +import struct SmithyIdentity.AWSCredentialIdentity + +public struct AWSSigningConfig { + public let credentials: AWSCredentialIdentity? + public let awsCredentialIdentityResolver: (any AWSCredentialIdentityResolver)? + public let expiration: TimeInterval + public let signedBodyHeader: AWSSignedBodyHeader + public let signedBodyValue: AWSSignedBodyValue + public let flags: SigningFlags + public let date: Date + public let service: String + public let region: String + public let shouldSignHeader: ((String) -> Bool)? + public let signatureType: AWSSignatureType + public let signingAlgorithm: SigningAlgorithm + + public init( + credentials: AWSCredentialIdentity? = nil, + awsCredentialIdentityResolver: (any AWSCredentialIdentityResolver)? = nil, + expiration: TimeInterval = 0, + signedBodyHeader: AWSSignedBodyHeader = .none, + signedBodyValue: AWSSignedBodyValue, + flags: SigningFlags, + date: Date, + service: String, + region: String, + shouldSignHeader: ((String) -> Bool)? = nil, + signatureType: AWSSignatureType, + signingAlgorithm: SigningAlgorithm + ) { + self.credentials = credentials + self.awsCredentialIdentityResolver = awsCredentialIdentityResolver + self.expiration = expiration + self.signedBodyHeader = signedBodyHeader + self.signedBodyValue = signedBodyValue + self.flags = flags + self.date = date + self.service = service + self.region = region + self.shouldSignHeader = shouldSignHeader + self.signatureType = signatureType + self.signingAlgorithm = signingAlgorithm + } +} diff --git a/Sources/SmithyHTTPAuth/CRTAdapters.swift b/Sources/SmithyHTTPAuth/CRTAdapters.swift new file mode 100644 index 000000000..09847c0e5 --- /dev/null +++ b/Sources/SmithyHTTPAuth/CRTAdapters.swift @@ -0,0 +1,103 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import enum AwsCommonRuntimeKit.SigningAlgorithmType +import enum AwsCommonRuntimeKit.SignedBodyHeaderType +import enum AwsCommonRuntimeKit.SignedBodyValue +import enum AwsCommonRuntimeKit.SignatureType +import struct AwsCommonRuntimeKit.SigningConfig + +import enum SmithyHTTPAuthAPI.SigningAlgorithm +import enum SmithyHTTPAuthAPI.AWSSignedBodyHeader +import enum SmithyHTTPAuthAPI.AWSSignedBodyValue +import enum SmithyHTTPAuthAPI.AWSSignatureType + +import struct Foundation.Locale +import class SmithyIdentity.CRTAWSCredentialIdentity + +extension SigningAlgorithm { + /// Convert self to CRT SigningAlgorithmType + /// - Returns: SigningAlgorithmType + public func toCRTType() -> SigningAlgorithmType { + switch self { + case .sigv4: return .signingV4 + case .sigv4a: return .signingV4Asymmetric + } + } +} + +extension AWSSignatureType { + public func toCRTType() -> SignatureType { + switch self { + case .requestChunk: return .requestChunk + case .requestHeaders: return .requestHeaders + case .requestQueryParams: return .requestQueryParams + case .requestTrailingHeaders: return .requestTrailingHeaders + case .requestEvent: return .requestEvent + } + } +} + +extension AWSSignedBodyHeader { + func toCRTType() -> SignedBodyHeaderType { + switch self { + case .none: return .none + case .contentSha256: return .contentSha256 + } + } +} + +extension AWSSignedBodyValue { + func toCRTType() -> SignedBodyValue { + switch self { + case .empty: return .empty + case .emptySha256: return .emptySha256 + case .unsignedPayload: return .unsignedPayload + case .streamingSha256Payload: return .streamingSha256Payload + case .streamingSha256Events: return .streamingSha256Events + case .streamingSha256PayloadTrailer: return .streamingSha256PayloadTrailer + case .streamingUnsignedPayloadTrailer: return .streamingUnSignedPayloadTrailer + } + } +} + +extension AWSSigningConfig { + public func toCRTType() throws -> SigningConfig { + // Never include the Transfer-Encoding header in the signature, + // since older versions of URLSession will modify this header's value + // prior to sending a request. + // + // The Transfer-Encoding header does not affect the AWS operation being + // performed and is just there to coordinate the flow of data to the server. + // + // For all other headers, use the shouldSignHeaders block that was passed to + // determine if the header should be included in the signature. If the + // shouldSignHeaders block was not provided, then include all headers other + // than Transfer-Encoding. + let modifiedShouldSignHeader = { (name: String) in + guard name.lowercased(with: Locale(identifier: "en_US_POSIX")) != "transfer-encoding" else { return false } + return shouldSignHeader?(name) ?? true + } + + return SigningConfig( + algorithm: signingAlgorithm.toCRTType(), + signatureType: signatureType.toCRTType(), + service: service, + region: region, + date: date, + credentials: try credentials.map { try CRTAWSCredentialIdentity(awsCredentialIdentity: $0) }, + credentialsProvider: try awsCredentialIdentityResolver?.getCRTAWSCredentialIdentityResolver(), + expiration: expiration, + signedBodyHeader: signedBodyHeader.toCRTType(), + signedBodyValue: signedBodyValue.toCRTType(), + shouldSignHeader: modifiedShouldSignHeader, + useDoubleURIEncode: flags.useDoubleURIEncode, + shouldNormalizeURIPath: flags.shouldNormalizeURIPath, + omitSessionToken: flags.omitSessionToken + ) + } +} diff --git a/Sources/ClientRuntime/Auth/HTTPAuth/DefaultIdentityResolverConfiguration.swift b/Sources/SmithyHTTPAuth/DefaultIdentityResolverConfiguration.swift similarity index 91% rename from Sources/ClientRuntime/Auth/HTTPAuth/DefaultIdentityResolverConfiguration.swift rename to Sources/SmithyHTTPAuth/DefaultIdentityResolverConfiguration.swift index f72a065fa..1d1350348 100644 --- a/Sources/ClientRuntime/Auth/HTTPAuth/DefaultIdentityResolverConfiguration.swift +++ b/Sources/SmithyHTTPAuth/DefaultIdentityResolverConfiguration.swift @@ -5,10 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 // +import protocol SmithyIdentityAPI.IdentityResolver +import protocol SmithyHTTPAuthAPI.IdentityResolverConfiguration import struct Smithy.Attributes import struct Smithy.AttributeKey -import protocol SmithyIdentityAPI.IdentityResolver -import protocol SmithyIdentityAPI.IdentityResolverConfiguration public struct DefaultIdentityResolverConfiguration: IdentityResolverConfiguration { let identityResolvers: Attributes diff --git a/Sources/SmithyHTTPAuthAPI/AuthScheme.swift b/Sources/SmithyHTTPAuthAPI/AuthScheme.swift index af570b8a1..bf563b1a2 100644 --- a/Sources/SmithyHTTPAuthAPI/AuthScheme.swift +++ b/Sources/SmithyHTTPAuthAPI/AuthScheme.swift @@ -5,10 +5,9 @@ // SPDX-License-Identifier: Apache-2.0 // -import struct Smithy.Attributes import class Smithy.Context import protocol SmithyIdentityAPI.IdentityResolver -import protocol SmithyIdentityAPI.IdentityResolverConfiguration +import struct Smithy.Attributes public protocol AuthScheme { var schemeID: String { get } @@ -19,7 +18,6 @@ public protocol AuthScheme { } public extension AuthScheme { - func identityResolver(config: IdentityResolverConfiguration) throws -> (any IdentityResolver)? { return try config.getIdentityResolver(schemeID: self.schemeID) } diff --git a/Sources/SmithyHTTPAuthAPI/Context+Chunked.swift b/Sources/SmithyHTTPAuthAPI/Context/Context+Chunked.swift similarity index 99% rename from Sources/SmithyHTTPAuthAPI/Context+Chunked.swift rename to Sources/SmithyHTTPAuthAPI/Context/Context+Chunked.swift index b5ce7e8f5..776c8805d 100644 --- a/Sources/SmithyHTTPAuthAPI/Context+Chunked.swift +++ b/Sources/SmithyHTTPAuthAPI/Context/Context+Chunked.swift @@ -5,11 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 // -import struct Smithy.AttributeKey import class Smithy.Context +import struct Smithy.AttributeKey public extension Context { - var isChunkedEligibleStream: Bool? { get { attributes.get(key: isChunkedEligibleStreamKey) } set { attributes.set(key: isChunkedEligibleStreamKey, value: newValue) } diff --git a/Sources/SmithyHTTPAuthAPI/Context+EstimatedSkew.swift b/Sources/SmithyHTTPAuthAPI/Context/Context+EstimatedSkew.swift similarity index 99% rename from Sources/SmithyHTTPAuthAPI/Context+EstimatedSkew.swift rename to Sources/SmithyHTTPAuthAPI/Context/Context+EstimatedSkew.swift index 35650aaec..f0c4d13cf 100644 --- a/Sources/SmithyHTTPAuthAPI/Context+EstimatedSkew.swift +++ b/Sources/SmithyHTTPAuthAPI/Context/Context+EstimatedSkew.swift @@ -5,13 +5,12 @@ // SPDX-License-Identifier: Apache-2.0 // -import struct Smithy.AttributeKey import class Smithy.Context import class Smithy.ContextBuilder import struct Foundation.TimeInterval +import struct Smithy.AttributeKey public extension Context { - var estimatedSkew: TimeInterval? { get { attributes.get(key: estimatedSkewKey) } set { attributes.set(key: estimatedSkewKey, value: newValue) } diff --git a/Sources/SmithyHTTPAuthAPI/Context+HTTPAuth.swift b/Sources/SmithyHTTPAuthAPI/Context/Context+HTTPAuth.swift similarity index 99% rename from Sources/SmithyHTTPAuthAPI/Context+HTTPAuth.swift rename to Sources/SmithyHTTPAuthAPI/Context/Context+HTTPAuth.swift index 3d518c149..77c671b12 100644 --- a/Sources/SmithyHTTPAuthAPI/Context+HTTPAuth.swift +++ b/Sources/SmithyHTTPAuthAPI/Context/Context+HTTPAuth.swift @@ -5,13 +5,12 @@ // SPDX-License-Identifier: Apache-2.0 // -import struct Smithy.Attributes -import struct Smithy.AttributeKey import class Smithy.Context import class Smithy.ContextBuilder +import struct Smithy.Attributes +import struct Smithy.AttributeKey public extension Context { - func getAuthSchemes() -> Attributes? { return attributes.get(key: authSchemesKey) } @@ -36,7 +35,6 @@ public extension Context { } extension ContextBuilder { - @discardableResult public func withAuthSchemeResolver(value: AuthSchemeResolver?) -> ContextBuilder { self.attributes.set(key: authSchemeResolverKey, value: value) diff --git a/Sources/SmithyHTTPAuthAPI/Context+RequestSignature.swift b/Sources/SmithyHTTPAuthAPI/Context/Context+RequestSignature.swift similarity index 86% rename from Sources/SmithyHTTPAuthAPI/Context+RequestSignature.swift rename to Sources/SmithyHTTPAuthAPI/Context/Context+RequestSignature.swift index 5826d9abb..5b9d99179 100644 --- a/Sources/SmithyHTTPAuthAPI/Context+RequestSignature.swift +++ b/Sources/SmithyHTTPAuthAPI/Context/Context+RequestSignature.swift @@ -5,7 +5,9 @@ // SPDX-License-Identifier: Apache-2.0 // -import Smithy +import class Smithy.Context +import class Smithy.ContextBuilder +import struct Smithy.AttributeKey public extension Context { diff --git a/Sources/SmithyHTTPAuthAPI/Context/SigningPropertyKeys.swift b/Sources/SmithyHTTPAuthAPI/Context/SigningPropertyKeys.swift new file mode 100644 index 000000000..ec4b3bba5 --- /dev/null +++ b/Sources/SmithyHTTPAuthAPI/Context/SigningPropertyKeys.swift @@ -0,0 +1,26 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import struct Smithy.AttributeKey +import struct Foundation.TimeInterval + +public enum SigningPropertyKeys { + public static let signingName = AttributeKey(name: "SigningName") + public static let signingRegion = AttributeKey(name: "SigningRegion") + // Keys used to store/retrieve AWSSigningConfig fields in/from signingProperties passed to AWSSigV4Signer + public static let bidirectionalStreaming = AttributeKey(name: "BidirectionalStreaming") + public static let checksum = AttributeKey(name: "checksum") + public static let expiration = AttributeKey(name: "Expiration") + public static let isChunkedEligibleStream = AttributeKey(name: "isChunkedEligibleStream") + public static let omitSessionToken = AttributeKey(name: "OmitSessionToken") + public static let shouldNormalizeURIPath = AttributeKey(name: "ShouldNormalizeURIPath") + public static let signatureType = AttributeKey(name: "SignatureType") + public static let signedBodyHeader = AttributeKey(name: "SignedBodyHeader") + public static let signingAlgorithm = AttributeKey(name: "signingAlgorithm") + public static let unsignedBody = AttributeKey(name: "UnsignedBody") + public static let useDoubleURIEncode = AttributeKey(name: "UseDoubleURIEncode") +} diff --git a/Sources/SmithyIdentityAPI/IdentityResolverConfiguration.swift b/Sources/SmithyHTTPAuthAPI/IdentityResolverConfiguration.swift similarity index 50% rename from Sources/SmithyIdentityAPI/IdentityResolverConfiguration.swift rename to Sources/SmithyHTTPAuthAPI/IdentityResolverConfiguration.swift index eb66288dd..1b320e021 100644 --- a/Sources/SmithyIdentityAPI/IdentityResolverConfiguration.swift +++ b/Sources/SmithyHTTPAuthAPI/IdentityResolverConfiguration.swift @@ -5,6 +5,11 @@ // SPDX-License-Identifier: Apache-2.0 // +import protocol SmithyIdentityAPI.IdentityResolver + +// This protocol exists for HTTP auth scheme resolution process. +// Concrete implementation of this protocol acts as the container for identity resolvers, +// taken from the client config. public protocol IdentityResolverConfiguration { func getIdentityResolver(schemeID: String) throws -> (any IdentityResolver)? } diff --git a/Sources/SmithyHTTPAuthAPI/SelectedAuthScheme.swift b/Sources/SmithyHTTPAuthAPI/SelectedAuthScheme.swift index 59baf4e4f..a2b9f0b58 100644 --- a/Sources/SmithyHTTPAuthAPI/SelectedAuthScheme.swift +++ b/Sources/SmithyHTTPAuthAPI/SelectedAuthScheme.swift @@ -5,9 +5,9 @@ // SPDX-License-Identifier: Apache-2.0 // +import protocol SmithyIdentityAPI.Identity import struct Smithy.Attributes import struct Smithy.AttributeKey -import protocol SmithyIdentityAPI.Identity public struct SelectedAuthScheme { public let schemeID: String diff --git a/Sources/SmithyHTTPAuthAPI/Signer.swift b/Sources/SmithyHTTPAuthAPI/Signer.swift index 6a031be8c..bc2b3792b 100644 --- a/Sources/SmithyHTTPAuthAPI/Signer.swift +++ b/Sources/SmithyHTTPAuthAPI/Signer.swift @@ -5,9 +5,9 @@ // SPDX-License-Identifier: Apache-2.0 // -import struct Smithy.Attributes import class SmithyHTTPAPI.SdkHttpRequestBuilder import protocol SmithyIdentityAPI.Identity +import struct Smithy.Attributes public protocol Signer { diff --git a/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignatureType.swift b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignatureType.swift new file mode 100644 index 000000000..8aabd0d95 --- /dev/null +++ b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignatureType.swift @@ -0,0 +1,14 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +public enum AWSSignatureType { + case requestHeaders + case requestQueryParams + case requestChunk + case requestTrailingHeaders + case requestEvent +} diff --git a/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignedBodyHeader.swift b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignedBodyHeader.swift new file mode 100644 index 000000000..dfb4151b9 --- /dev/null +++ b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignedBodyHeader.swift @@ -0,0 +1,11 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +public enum AWSSignedBodyHeader { + case none + case contentSha256 +} diff --git a/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignedBodyValue.swift b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignedBodyValue.swift new file mode 100644 index 000000000..74c070ba5 --- /dev/null +++ b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/AWSSignedBodyValue.swift @@ -0,0 +1,16 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +public enum AWSSignedBodyValue { + case empty + case emptySha256 + case unsignedPayload + case streamingSha256Payload + case streamingSha256Events + case streamingSha256PayloadTrailer + case streamingUnsignedPayloadTrailer +} diff --git a/Sources/SmithyHTTPAuthAPI/SigningAlgorithm.swift b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/SigningAlgorithm.swift similarity index 100% rename from Sources/SmithyHTTPAuthAPI/SigningAlgorithm.swift rename to Sources/SmithyHTTPAuthAPI/SigningConfigFields/SigningAlgorithm.swift diff --git a/Sources/SmithyHTTPAuthAPI/SigningConfigFields/SigningFlags.swift b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/SigningFlags.swift new file mode 100644 index 000000000..ea1c431d4 --- /dev/null +++ b/Sources/SmithyHTTPAuthAPI/SigningConfigFields/SigningFlags.swift @@ -0,0 +1,18 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +public struct SigningFlags { + public let useDoubleURIEncode: Bool + public let shouldNormalizeURIPath: Bool + public let omitSessionToken: Bool + + public init(useDoubleURIEncode: Bool, shouldNormalizeURIPath: Bool, omitSessionToken: Bool) { + self.useDoubleURIEncode = useDoubleURIEncode + self.shouldNormalizeURIPath = shouldNormalizeURIPath + self.omitSessionToken = omitSessionToken + } +} diff --git a/Sources/SmithyHTTPAuthAPI/SigningPropertyKeys.swift b/Sources/SmithyHTTPAuthAPI/SigningPropertyKeys.swift deleted file mode 100644 index 5c44b6dba..000000000 --- a/Sources/SmithyHTTPAuthAPI/SigningPropertyKeys.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright Amazon.com Inc. or its affiliates. -// All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 -// - -import Smithy - -public enum SigningPropertyKeys { - public static let signingName = AttributeKey(name: "SigningName") - public static let signingRegion = AttributeKey(name: "SigningRegion") -} diff --git a/Sources/SmithyIdentityAPI/AWSCredentialIdentity.swift b/Sources/SmithyIdentity/AWSCredentialIdentity.swift similarity index 96% rename from Sources/SmithyIdentityAPI/AWSCredentialIdentity.swift rename to Sources/SmithyIdentity/AWSCredentialIdentity.swift index 380f158e7..3690d876d 100644 --- a/Sources/SmithyIdentityAPI/AWSCredentialIdentity.swift +++ b/Sources/SmithyIdentity/AWSCredentialIdentity.swift @@ -5,6 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 // +import protocol SmithyIdentityAPI.Identity import struct Foundation.Date /// A type representing AWS credentials for authenticating with an AWS service diff --git a/Sources/SmithyIdentity/AWSCredentialIdentityResolver.swift b/Sources/SmithyIdentity/AWSCredentialIdentityResolver.swift new file mode 100644 index 000000000..f418e3805 --- /dev/null +++ b/Sources/SmithyIdentity/AWSCredentialIdentityResolver.swift @@ -0,0 +1,30 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import class AwsCommonRuntimeKit.CredentialsProvider +import protocol SmithyIdentityAPI.IdentityResolver +import struct Smithy.Attributes + +/// A type that can provide credentials for authenticating with an AWS service +public protocol AWSCredentialIdentityResolver: IdentityResolver where IdentityT == AWSCredentialIdentity {} + +public extension AWSCredentialIdentityResolver { + + /// Returns the underlying `AwsCommonRuntimeKit.CredentialsProvider`. + /// If `self` is not backed by a `AwsCommonRuntimeKit.CredentialsProvider` then this wraps `self` + /// in a `CustomAWSCredentialIdentityResolver` which will create a `AwsCommonRuntimeKit.CredentialsProvider`. + func getCRTAWSCredentialIdentityResolver() throws -> AwsCommonRuntimeKit.CredentialsProvider { + let providerSourcedByCRT = try self as? (any AWSCredentialIdentityResolvedByCRT) + ?? CustomAWSCredentialIdentityResolver(self) + return providerSourcedByCRT.crtAWSCredentialIdentityResolver + } + + func getIdentity(identityProperties: Attributes? = nil) async throws -> AWSCredentialIdentity { + let crtAWSCredentialIdentity = try await self.getCRTAWSCredentialIdentityResolver().getCredentials() + return try .init(crtAWSCredentialIdentity: crtAWSCredentialIdentity) + } +} diff --git a/Sources/SmithyIdentity/AWSCredentialIdentityResolvers/CustomAWSCredentialIdentityResolver.swift b/Sources/SmithyIdentity/AWSCredentialIdentityResolvers/CustomAWSCredentialIdentityResolver.swift new file mode 100644 index 000000000..a931114ad --- /dev/null +++ b/Sources/SmithyIdentity/AWSCredentialIdentityResolvers/CustomAWSCredentialIdentityResolver.swift @@ -0,0 +1,25 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import class AwsCommonRuntimeKit.CredentialsProvider + +/// A credential identity resolver that uses the input identity resolver to resolve the credentials. +/// The provided identity resolver must conform to `AWSCredentialIdentityResolver`. +public struct CustomAWSCredentialIdentityResolver: AWSCredentialIdentityResolvedByCRT { + public let crtAWSCredentialIdentityResolver: AwsCommonRuntimeKit.CredentialsProvider + + /// - Parameter identityResolver: An object conforming to `AWSCredentialIdentityResolver` to resolve the credentials. + /// + /// - Returns: A credential identity resolver that uses the provided resolver to resolve credentials. + public init(_ identityResolver: any AWSCredentialIdentityResolver) throws { + self.crtAWSCredentialIdentityResolver = try AwsCommonRuntimeKit.CredentialsProvider( + provider: AWSCredentialIdentityResolverCRTAdapter( + awsCredentialIdentityResolver: identityResolver + ) + ) + } +} diff --git a/Sources/SmithyIdentity/AWSCredentialIdentityResolvers/StaticAWSCredentialIdentityResolver.swift b/Sources/SmithyIdentity/AWSCredentialIdentityResolvers/StaticAWSCredentialIdentityResolver.swift new file mode 100644 index 000000000..6316b54bb --- /dev/null +++ b/Sources/SmithyIdentity/AWSCredentialIdentityResolvers/StaticAWSCredentialIdentityResolver.swift @@ -0,0 +1,28 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import class AwsCommonRuntimeKit.CredentialsProvider + +/// A credential identity resolver that provides a fixed set of credentials +public struct StaticAWSCredentialIdentityResolver: AWSCredentialIdentityResolvedByCRT { + private let credentials: AWSCredentialIdentity + public let crtAWSCredentialIdentityResolver: AwsCommonRuntimeKit.CredentialsProvider + + /// Creates a credential identity resolver for a fixed set of credentials + /// + /// - Parameter credentials: The credentials that this provider will provide. + /// + /// - Returns: A credential identity resolver for a fixed set of credentials + public init(_ credentials: AWSCredentialIdentity) throws { + self.credentials = credentials + self.crtAWSCredentialIdentityResolver = try AwsCommonRuntimeKit.CredentialsProvider(source: .static( + accessKey: credentials.accessKey, + secret: credentials.secret, + sessionToken: credentials.sessionToken + )) + } +} diff --git a/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityResolvedByCRT.swift b/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityResolvedByCRT.swift new file mode 100644 index 000000000..dab2a7b53 --- /dev/null +++ b/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityResolvedByCRT.swift @@ -0,0 +1,14 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import class AwsCommonRuntimeKit.CredentialsProvider + +/// The protocol that concrete implementations of AWS credential identity resolvers +/// in the SDK must implement in order to use CRT's AWS credentials provider implementation. +public protocol AWSCredentialIdentityResolvedByCRT: AWSCredentialIdentityResolver { + var crtAWSCredentialIdentityResolver: AwsCommonRuntimeKit.CredentialsProvider { get } +} diff --git a/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityResolverCRTAdapter.swift b/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityResolverCRTAdapter.swift new file mode 100644 index 000000000..a9e3af671 --- /dev/null +++ b/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityResolverCRTAdapter.swift @@ -0,0 +1,21 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import protocol AwsCommonRuntimeKit.CredentialsProviding +import struct Smithy.Attributes + +/// The adapter used to return CRTAWSCredentialIdentity from AWSCredentialIdentityResolver. +struct AWSCredentialIdentityResolverCRTAdapter: AwsCommonRuntimeKit.CredentialsProviding { + let awsCredentialIdentityResolver: any AWSCredentialIdentityResolver + + func getCredentials() async throws -> CRTAWSCredentialIdentity { + let credentials = try await awsCredentialIdentityResolver.getIdentity( + identityProperties: Attributes() + ) + return try .init(awsCredentialIdentity: credentials) + } +} diff --git a/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityUtilityInitializers.swift b/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityUtilityInitializers.swift new file mode 100644 index 000000000..48204b082 --- /dev/null +++ b/Sources/SmithyIdentity/CRTAdapters/AWSCredentialIdentityUtilityInitializers.swift @@ -0,0 +1,42 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import enum Smithy.ClientError + +public extension AWSCredentialIdentity { + /// Creates `AWSCredentialIdentity` from the provided `CRTAWSCredentialIdentity`. + /// + /// Throws if it fails to get the access key or secret key from the underlying `CRTAWSCredentialIdentity`. + init(crtAWSCredentialIdentity: CRTAWSCredentialIdentity) throws { + guard let accessKey = crtAWSCredentialIdentity.getAccessKey() else { + throw ClientError.authError("Failed to get access key.") + } + + guard let secret = crtAWSCredentialIdentity.getSecret() else { + throw ClientError.authError("Failed to get secret.") + } + + self.init( + accessKey: accessKey, + secret: secret, + expiration: crtAWSCredentialIdentity.getExpiration(), + sessionToken: crtAWSCredentialIdentity.getSessionToken() + ) + } +} + +public extension CRTAWSCredentialIdentity { + /// Creates `CRTAWSCredentialIdentity` from the provided `AWSCredentialIdentity`. + convenience init(awsCredentialIdentity: AWSCredentialIdentity) throws { + try self.init( + accessKey: awsCredentialIdentity.accessKey, + secret: awsCredentialIdentity.secret, + sessionToken: awsCredentialIdentity.sessionToken, + expiration: awsCredentialIdentity.expiration + ) + } +} diff --git a/Sources/SmithyIdentity/CRTAdapters/CRTAWSCredentialIdentity.swift b/Sources/SmithyIdentity/CRTAdapters/CRTAWSCredentialIdentity.swift new file mode 100644 index 000000000..8fd3c3098 --- /dev/null +++ b/Sources/SmithyIdentity/CRTAdapters/CRTAWSCredentialIdentity.swift @@ -0,0 +1,10 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import class AwsCommonRuntimeKit.Credentials + +public typealias CRTAWSCredentialIdentity = AwsCommonRuntimeKit.Credentials diff --git a/Sources/SmithyIdentityAPI/AWSCredentialIdentityResolver.swift b/Sources/SmithyIdentityAPI/AWSCredentialIdentityResolver.swift deleted file mode 100644 index 061cd8f5f..000000000 --- a/Sources/SmithyIdentityAPI/AWSCredentialIdentityResolver.swift +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright Amazon.com Inc. or its affiliates. -// All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 -// - -/// A type that can provide credentials for authenticating with an AWS service -public protocol AWSCredentialIdentityResolver: IdentityResolver where IdentityT == AWSCredentialIdentity {} diff --git a/Sources/SmithyIdentityAPI/Context/Context+FlowType.swift b/Sources/SmithyIdentityAPI/Context/Context+FlowType.swift new file mode 100644 index 000000000..24c7d1435 --- /dev/null +++ b/Sources/SmithyIdentityAPI/Context/Context+FlowType.swift @@ -0,0 +1,26 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import class Smithy.Context +import class Smithy.ContextBuilder +import struct Smithy.AttributeKey + +public let flowTypeKey = AttributeKey(name: "FlowType") + +extension Context { + public func getFlowType() -> FlowType { + return attributes.get(key: flowTypeKey) ?? .NORMAL + } +} + +extension ContextBuilder { + @discardableResult + public func withFlowType(value: FlowType) -> Self { + self.attributes.set(key: flowTypeKey, value: value) + return self + } +} diff --git a/Sources/SmithyIdentityAPI/OperationContext+Identity.swift b/Sources/SmithyIdentityAPI/Context/Context+IdentityResolver.swift similarity index 99% rename from Sources/SmithyIdentityAPI/OperationContext+Identity.swift rename to Sources/SmithyIdentityAPI/Context/Context+IdentityResolver.swift index db9a6e12f..844dd6cb6 100644 --- a/Sources/SmithyIdentityAPI/OperationContext+Identity.swift +++ b/Sources/SmithyIdentityAPI/Context/Context+IdentityResolver.swift @@ -11,14 +11,12 @@ import class Smithy.Context import class Smithy.ContextBuilder extension Context { - public func getIdentityResolvers() -> Attributes? { return attributes.get(key: identityResolversKey) } } extension ContextBuilder { - @discardableResult public func removeIdentityResolvers() -> Self { attributes.remove(key: identityResolversKey) diff --git a/Sources/SmithyIdentityAPI/FlowType.swift b/Sources/SmithyIdentityAPI/FlowType.swift new file mode 100644 index 000000000..fe5a19448 --- /dev/null +++ b/Sources/SmithyIdentityAPI/FlowType.swift @@ -0,0 +1,11 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +/// The type of flow the middleware context is being constructed for +public enum FlowType { + case NORMAL, PRESIGN_REQUEST, PRESIGN_URL +} diff --git a/Tests/SmithyIdentityTests/CustomAWSCredentialIdentityResolverTests.swift b/Tests/SmithyIdentityTests/CustomAWSCredentialIdentityResolverTests.swift new file mode 100644 index 000000000..62e381629 --- /dev/null +++ b/Tests/SmithyIdentityTests/CustomAWSCredentialIdentityResolverTests.swift @@ -0,0 +1,20 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +import struct SmithyIdentity.CustomAWSCredentialIdentityResolver + +class CustomAWSCredentialIdentityResolverTests: XCTestCase { + func testGetCredentials() async throws { + let mockProvider = MockAWSCredentialIdentityResolver() + let subject = try CustomAWSCredentialIdentityResolver(mockProvider) + let credentials = try await subject.getIdentity() + + XCTAssertEqual(credentials.accessKey, "some_access_key") + XCTAssertEqual(credentials.secret, "some_secret") + } +} diff --git a/Tests/SmithyIdentityTests/MockAWSCredentialIdentityResolver.swift b/Tests/SmithyIdentityTests/MockAWSCredentialIdentityResolver.swift new file mode 100644 index 000000000..f1c05b7fb --- /dev/null +++ b/Tests/SmithyIdentityTests/MockAWSCredentialIdentityResolver.swift @@ -0,0 +1,28 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import protocol SmithyIdentity.AWSCredentialIdentityResolver +import struct Smithy.Attributes +import struct SmithyIdentity.AWSCredentialIdentity + +struct MockAWSCredentialIdentityResolver: AWSCredentialIdentityResolver { + let _getIdentity: () async throws -> AWSCredentialIdentity + init(_ _getIdentity: @escaping () async throws -> AWSCredentialIdentity) { + self._getIdentity = _getIdentity + } + init() { + self._getIdentity = { + AWSCredentialIdentity( + accessKey: "some_access_key", + secret: "some_secret" + ) + } + } + func getIdentity(identityProperties: Attributes?) async throws -> AWSCredentialIdentity { + try await _getIdentity() + } +} diff --git a/Tests/SmithyIdentityTests/StaticAWSCredentialIdentityResolverTests.swift b/Tests/SmithyIdentityTests/StaticAWSCredentialIdentityResolverTests.swift new file mode 100644 index 000000000..46f5801b7 --- /dev/null +++ b/Tests/SmithyIdentityTests/StaticAWSCredentialIdentityResolverTests.swift @@ -0,0 +1,22 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +import struct SmithyIdentity.StaticAWSCredentialIdentityResolver + +class StaticAWSCredentialIdentityResolverTests: XCTestCase { + func testGetCredentials() async throws { + let subject = try StaticAWSCredentialIdentityResolver(.init( + accessKey: "some_access_key", + secret: "some_secret" + )) + let credentials = try await subject.getIdentity() + + XCTAssertEqual(credentials.accessKey, "some_access_key") + XCTAssertEqual(credentials.secret, "some_secret") + } +} diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftDependency.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftDependency.kt index 80aba446a..683b07d30 100644 --- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftDependency.kt +++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftDependency.kt @@ -34,6 +34,14 @@ enum class SwiftDependency( Resources.computeAbsolutePath("smithy-swift", "", "SMITHY_SWIFT_CI_DIR"), "smithy-swift" ), + SMITHY_IDENTITY( + "SmithyIdentity", + "main", + "0.1.0", + "https://github.com/smithy-lang/smithy-swift", + Resources.computeAbsolutePath("smithy-swift", "", "SMITHY_SWIFT_CI_DIR"), + "smithy-swift" + ), SMITHY_IDENTITY_API( "SmithyIdentityAPI", "main", @@ -66,6 +74,14 @@ enum class SwiftDependency( Resources.computeAbsolutePath("smithy-swift", "", "SMITHY_SWIFT_CI_DIR"), "smithy-swift" ), + SMITHY_HTTP_AUTH( + "SmithyHTTPAuth", + "main", + "0.1.0", + "https://github.com/smithy-lang/smithy-swift", + Resources.computeAbsolutePath("smithy-swift", "", "SMITHY_SWIFT_CI_DIR"), + "smithy-swift" + ), SMITHY_HTTP_AUTH_API( "SmithyHTTPAuthAPI", "main", diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/swiftmodules/SmithyIdentityAPITypes.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/swiftmodules/SmithyIdentityTypes.kt similarity index 86% rename from smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/swiftmodules/SmithyIdentityAPITypes.kt rename to smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/swiftmodules/SmithyIdentityTypes.kt index 597ae6f85..7360f20a0 100644 --- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/swiftmodules/SmithyIdentityAPITypes.kt +++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/swiftmodules/SmithyIdentityTypes.kt @@ -4,12 +4,12 @@ import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.swift.codegen.SwiftDeclaration import software.amazon.smithy.swift.codegen.SwiftDependency -object SmithyIdentityAPITypes { +object SmithyIdentityTypes { val AWSCredentialIdentityResolver = runtimeSymbol("AWSCredentialIdentityResolver") } private fun runtimeSymbol(name: String, declaration: SwiftDeclaration? = null): Symbol = SwiftSymbol.make( name, declaration, - SwiftDependency.SMITHY_IDENTITY_API, + SwiftDependency.SMITHY_IDENTITY, )