Skip to content

feat: S3 Express support #916

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
29 changes: 29 additions & 0 deletions Sources/ClientRuntime/Config/Context+Config.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// 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 extension Context {

var clientConfig: DefaultClientConfiguration? {
get { get(key: clientConfigKey) }
set { set(key: clientConfigKey, value: newValue) }
}
}

public extension ContextBuilder {

func withClientConfig(value: DefaultClientConfiguration?) -> Self {
attributes.set(key: clientConfigKey, value: value)
return self
}
}

private let clientConfigKey: AttributeKey<DefaultClientConfiguration> =
AttributeKey<DefaultClientConfiguration>(name: "SmithySwiftClientConfig")
17 changes: 17 additions & 0 deletions Sources/ClientRuntime/Config/IdentityPropertyKeys.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import struct Smithy.AttributeKey

public enum IdentityPropertyKeys {

/// The service client config to be used in credential resolution.
///
/// Used only in conjunction with the `awsv4-s3express` auth scheme, which generates bucket-specific credentials
/// for use with the S3 Express service.
public static let clientConfig = AttributeKey<any DefaultClientConfiguration>(name: "ClientRuntimeClientConfig")
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ extension EndpointResolverMiddleware: ApplyEndpoint {
signingName = param.signingName
case .sigV4A(let param):
signingName = param.signingName
case .sigV4S3Express(let param):
signingName = param.signingName
case .none:
break
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import enum SmithyHTTPAPI.EndpointPropertyValue
public enum EndpointsAuthScheme: Equatable {
case sigV4(SigV4Parameters)
case sigV4A(SigV4AParameters)
case sigV4S3Express(SigV4Parameters)
case none

/// The name of the auth scheme
public var name: String {
switch self {
case .sigV4: return "sigv4"
case .sigV4A: return "sigv4a"
case .sigV4S3Express: return "sigv4-s3express"
case .none: return "none"
}
}
Expand All @@ -36,6 +38,8 @@ extension EndpointsAuthScheme {
self = .sigV4(try SigV4Parameters(from: dictionary))
case "sigv4a":
self = .sigV4A(try SigV4AParameters(from: dictionary))
case "sigv4-s3express":
self = .sigV4S3Express(try SigV4Parameters(from: dictionary))
case "none":
self = .none
default:
Expand Down Expand Up @@ -156,7 +160,7 @@ public struct DefaultEndpointsAuthSchemeResolver: EndpointsAuthSchemeResolver {
/// Supported auth schemes by the SDK
let supportedAuthSchemes: Set<String>

public init(supportedAuthSchemes: Set<String> = ["sigv4", "sigv4a", "none"]) {
public init(supportedAuthSchemes: Set<String> = ["sigv4", "sigv4a", "sigv4-s3express", "none"]) {
self.supportedAuthSchemes = supportedAuthSchemes
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,14 @@ extension AuthSchemeMiddleware: SelectAuthScheme {
context: attributes
)
// Resolve identity using the resolver from auth scheme
let identity = try await identityResolver.getIdentity(identityProperties: option.identityProperties)
var modifiedIdentityProperties = option.identityProperties
modifiedIdentityProperties.set(
key: IdentityPropertyKeys.clientConfig,
value: attributes.clientConfig
)
let identity = try await identityResolver.getIdentity(
identityProperties: modifiedIdentityProperties
)
// Save selected auth scheme
selectedAuthScheme = SelectedAuthScheme(
schemeID: option.schemeID,
Expand Down
1 change: 1 addition & 0 deletions Sources/SmithyHTTPAuth/CRTAdapters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ extension SigningAlgorithm {
switch self {
case .sigv4: return .signingV4
case .sigv4a: return .signingV4Asymmetric
case .sigv4s3express: return .signingV4S3Express
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ public enum SigningAlgorithm: String, Sendable {
case sigv4
/// Signature Version 4 Asymmetric
case sigv4a
/// Signature Version 4 for S3 Express
case sigv4s3express = "sigv4-s3express"
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ open class OperationEndpointResolverMiddleware(
// Write code that saves endpoint params to middleware context for use in auth scheme middleware when using rules-based auth scheme resolvers
if (AuthSchemeResolverGenerator.usesRulesBasedAuthResolver(ctx)) {
writer.write(
"context.set(key: \$N<EndpointParams>(name: \"EndpointParams\"), value: endpointParamsBlock(context))",
"context.set(key: \$N<EndpointParams>(name: \$S), value: endpointParamsBlock(context))",
SmithyTypes.AttributeKey,
"EndpointParams",
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class MiddlewareExecutionGenerator(

// FIXME it over indents if i add another indent, come up with better way to properly indent or format for swift

writer.write(" .withClientConfig(value: config)")
writer.write(" .withMethod(value: .\$L)", httpMethod)
writer.write(" .withServiceName(value: serviceName)")
writer.write(" .withOperation(value: \$S)", op.toLowerCamelCase())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ extension RestJsonProtocolClient {
contents.shouldSyntacticSanityCheck()
val expectedFragment = """
let context = Smithy.ContextBuilder()
.withClientConfig(value: config)
.withMethod(value: .post)
.withServiceName(value: serviceName)
.withOperation(value: "getStatus")
Expand Down Expand Up @@ -190,6 +191,7 @@ extension RestJsonProtocolClient {
val expected = """
public func allocateWidget(input: AllocateWidgetInput) async throws -> AllocateWidgetOutput {
let context = Smithy.ContextBuilder()
.withClientConfig(value: config)
.withMethod(value: .post)
.withServiceName(value: serviceName)
.withOperation(value: "allocateWidget")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,10 @@ extension EventStreamTestClientTypes.TestStream {
val context = setupTests("eventstream.smithy", "aws.protocoltests.restjson#TestService")
println(context.manifest.files)
val contents = getFileContents(context.manifest, "Sources/Example/EventStreamTestClient.swift")
var expected = """
val expected = """
public func testStreamOp(input: TestStreamOpInput) async throws -> TestStreamOpOutput {
let context = Smithy.ContextBuilder()
.withClientConfig(value: config)
.withMethod(value: .post)
.withServiceName(value: serviceName)
.withOperation(value: "testStreamOp")
Expand Down
Loading