Skip to content
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

feat: support S3 Express One Zone #1206

Merged
merged 159 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
159 commits
Select commit Hold shift + click to select a range
7cfe73b
Add DisableExpressSessionAuth config
lauzadis Jan 4, 2024
4c3fc22
Add DisableExpressSessionAuth config
lauzadis Jan 4, 2024
551acaf
.api
lauzadis Jan 4, 2024
6e9032f
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin
lauzadis Jan 9, 2024
d63fa12
Latest commit
lauzadis Jan 11, 2024
14e3479
ktlint
lauzadis Jan 11, 2024
73d73d5
latest commit
lauzadis Jan 11, 2024
aaa342e
checksums
lauzadis Jan 12, 2024
222ea54
ktlintFormat
lauzadis Jan 12, 2024
f06d8aa
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Jan 16, 2024
d030ffa
Upgrade smithy-kotlin
lauzadis Jan 16, 2024
840f62e
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Jan 25, 2024
441cf26
Asynchronous credentials refresh
lauzadis Jan 25, 2024
8fc02cd
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 5, 2024
d247414
Bump to latest SNAPSHOT version
lauzadis Feb 5, 2024
e679bcd
lint
lauzadis Feb 5, 2024
0c85adf
api
lauzadis Feb 5, 2024
1067774
fix checksums
lauzadis Feb 7, 2024
f6b67d2
fix checksums
lauzadis Feb 7, 2024
78fb58c
Fixed session token header
lauzadis Feb 7, 2024
4e4cdf0
KDocs
lauzadis Feb 7, 2024
a204997
E2E tests
lauzadis Feb 7, 2024
5f91b5d
Simplify MD5 checksums interceptor
lauzadis Feb 7, 2024
7870548
create S3ExpressCredentialsProvider interface
lauzadis Feb 7, 2024
012b4be
Simplify and add a test
lauzadis Feb 7, 2024
9e43b1b
Add new dependency in order to use `AwsHttpSigner`
lauzadis Feb 7, 2024
80dfb81
cleanup
lauzadis Feb 7, 2024
7f25eed
CRT signer working
lauzadis Feb 7, 2024
f00ca0a
docs
lauzadis Feb 7, 2024
e6fb9f5
Relocate S3 Express AuthScheme ID to aws-sdk-kotlin
lauzadis Feb 8, 2024
1cb4caa
Remove log
lauzadis Feb 8, 2024
bbe3e35
Cleanup
lauzadis Feb 8, 2024
e6ff901
Revert visibility of credentials() function
lauzadis Feb 8, 2024
228333f
ktlintFormat
lauzadis Feb 8, 2024
8748f53
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 8, 2024
50ee25d
cleanup
lauzadis Feb 8, 2024
777a52d
split S3ExpressCredentialsProvider interface from implementation
lauzadis Feb 8, 2024
8440be1
correct expiration logic
lauzadis Feb 9, 2024
fd1ad4a
Add S3 Express benchmark (temporarily commented-out other benchmarks …
lauzadis Feb 9, 2024
b1ea753
Re-enable benchmarks
lauzadis Feb 9, 2024
d504c55
revert capturedMetrics
lauzadis Feb 9, 2024
8aedf25
ktlintFormat
lauzadis Feb 9, 2024
02aaa92
remove println
lauzadis Feb 9, 2024
a7f3b57
update endpoint attribute check
lauzadis Feb 9, 2024
25b1387
Kdocs
lauzadis Feb 9, 2024
f48b3d9
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 9, 2024
35bfe70
CI
lauzadis Feb 9, 2024
5475c10
Fix header name
lauzadis Feb 12, 2024
18d594f
Remove explicit type
lauzadis Feb 13, 2024
8d86e72
Simplify `S3ExpressCrc32ChecksumInterceptor` installation
lauzadis Feb 13, 2024
c5da754
Remove redundant `.invoke`
lauzadis Feb 13, 2024
39dbeb6
Don't deconfigure credentials
lauzadis Feb 13, 2024
700eade
Refactor S3ExpressAttributes
lauzadis Feb 13, 2024
204d13e
Relocate SigV4S3ExpressAuthScheme
lauzadis Feb 13, 2024
6605462
Fix symbols usage
lauzadis Feb 13, 2024
d4f07ef
Simplify attributes
lauzadis Feb 13, 2024
22e5433
const vals
lauzadis Feb 13, 2024
629f937
Bump log level and add operation name
lauzadis Feb 13, 2024
eea0bab
Make cache and key internal, key data class
lauzadis Feb 13, 2024
4d64f90
Rename to DefaultS3ExpressCredentialsProvider, make internal and expo…
lauzadis Feb 13, 2024
8cf9716
Change AwsHttpSigner -> HttpSigner
lauzadis Feb 14, 2024
1f16360
Remove unnecessary import
lauzadis Feb 14, 2024
f8d0de5
Relocate signer and interceptors to `s3` source set
lauzadis Feb 14, 2024
0df8638
Don't inherit `SigV4AuthSchemeIntegration`
lauzadis Feb 14, 2024
2c0d44a
ktlint
lauzadis Feb 14, 2024
73a39db
Revert move
lauzadis Feb 14, 2024
b308381
Fix API breakage of FlexibleChecksumsRequestInterceptor
lauzadis Feb 14, 2024
5e49bde
revert visibility changes
lauzadis Feb 14, 2024
01f0ca8
remove unused imports
lauzadis Feb 14, 2024
e7157c8
update providerName
lauzadis Feb 14, 2024
e9b8d4c
remove `client` from `S3ExpressCredentialsCacheKey`
lauzadis Feb 14, 2024
0fd4f66
Make `S3ExpressHttpSigner` internal
lauzadis Feb 14, 2024
6b15f3c
Simplify refresh logic
lauzadis Feb 15, 2024
993690d
Simplify refresh logic
lauzadis Feb 15, 2024
b38ecfc
ktlint
lauzadis Feb 15, 2024
16d8dfd
changelog
lauzadis Feb 15, 2024
8921174
Update KDocs
lauzadis Feb 15, 2024
7aa8d74
Use `writer` implicitly
lauzadis Feb 15, 2024
e150519
Correct unit
lauzadis Feb 15, 2024
e504792
Add a FIXME to use IMDS
lauzadis Feb 16, 2024
7dd646b
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 16, 2024
88eab9c
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 17, 2024
52b8acc
Add KDocs
lauzadis Feb 17, 2024
8bb9605
Clarify error message
lauzadis Feb 17, 2024
723dfad
Don't overrride functions and add KDocs for `default` companion objec…
lauzadis Feb 17, 2024
4bb7777
Clean up config property
lauzadis Feb 17, 2024
56ba192
Relax to `httpSigner`
lauzadis Feb 17, 2024
829c48b
Rename file to match class
lauzadis Feb 17, 2024
c540190
Fix config symbol
lauzadis Feb 17, 2024
24bcb74
Grab a local copy of `entries` instead of recomputing it
lauzadis Feb 17, 2024
88bcc03
DirectoryBucket -> Bucket
lauzadis Feb 17, 2024
1227f90
logger.trace
lauzadis Feb 17, 2024
ca038d6
Relocate things to `express` package
lauzadis Feb 17, 2024
2cbf22b
Remove FIXME comment
lauzadis Feb 17, 2024
8ec0916
Fix logging during async refresh
lauzadis Feb 17, 2024
99f63c0
Refactor to use `TimeSource`
lauzadis Feb 17, 2024
de2ea56
`supervisorJob`
lauzadis Feb 17, 2024
416fa6c
Apply synthetic trait
lauzadis Feb 19, 2024
c07135a
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 19, 2024
7e2cffc
Refactor async refresh logic to DefaultS3ExpressCredentialsProvider
lauzadis Feb 19, 2024
ec1dabb
simplify cache, perform refresh in provider
lauzadis Feb 20, 2024
fdfc475
ktlint
lauzadis Feb 20, 2024
ff98ba2
Fix isExpired logic
lauzadis Feb 20, 2024
898430d
Fix application of SigV4 S3 Express auth scheme
lauzadis Feb 20, 2024
89eeae8
Add tests
lauzadis Feb 20, 2024
7db188d
Update KDocs
lauzadis Feb 20, 2024
344a3ee
Update KDocs
lauzadis Feb 20, 2024
19f3e7e
Relocate SigV4S3ExpressAuthScheme to express package
lauzadis Feb 20, 2024
14ef411
ktlint
lauzadis Feb 20, 2024
0e1d816
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 20, 2024
e6c65b9
remove extra space
lauzadis Feb 21, 2024
758e92e
update `CredentialsProvider` -> `CloseableCredentialsProvider`
lauzadis Feb 21, 2024
60bef73
Replace class with typealias to `LruCache`
lauzadis Feb 21, 2024
e544637
Implement CloseableCredentialsProvider
lauzadis Feb 21, 2024
1531e73
Use `ComparableTimeMark`
lauzadis Feb 21, 2024
1f566f1
remove `open`
lauzadis Feb 21, 2024
70f7de5
Add a comment about running after `SigV4AuthSchemeIntegration`
lauzadis Feb 21, 2024
0cae045
Relocate S3 Express client config properties
lauzadis Feb 21, 2024
674c521
ktlint
lauzadis Feb 21, 2024
0e3177b
Add SFG
lauzadis Feb 21, 2024
ef4035a
Refactor to usage-based async refresh
lauzadis Feb 21, 2024
71d20a5
ktlintFormat
lauzadis Feb 21, 2024
b78afec
Remove `S3ExpressCredentialsProvider` interface
lauzadis Feb 21, 2024
b5557b4
Update single flight group use
lauzadis Feb 21, 2024
8f747d7
ktlint
lauzadis Feb 21, 2024
2d15cc9
update docs
lauzadis Feb 21, 2024
60e9f6d
add runBlocking to delay calls
lauzadis Feb 22, 2024
036f7ee
CI
lauzadis Feb 22, 2024
d7b176d
ktlint
lauzadis Feb 22, 2024
a261640
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 22, 2024
585a85f
Set name on client instead of operation benchmark
lauzadis Feb 22, 2024
a434153
Remove unnecessary function
lauzadis Feb 22, 2024
7454ca5
`createSessionCredentials` also insert the credentials into the cache
lauzadis Feb 22, 2024
ef38825
ktlint
lauzadis Feb 22, 2024
000bb4d
also remove prefix on PutObject
lauzadis Feb 22, 2024
fbcbf7b
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 22, 2024
f5cdfca
ktlint
lauzadis Feb 22, 2024
0bdd2e4
only print new statuses
lauzadis Feb 22, 2024
b989db6
@InternalSdkApi
lauzadis Feb 26, 2024
890b12e
Add expiration to log
lauzadis Feb 26, 2024
4258ab7
rename to baseCredentials
lauzadis Feb 26, 2024
f5b99f4
Handle input changing through interceptors
lauzadis Feb 26, 2024
4b505c4
ktlint
lauzadis Feb 26, 2024
cefbf91
Delegate all enablement logic to `isEnabledFor`
lauzadis Feb 27, 2024
f92950c
Prevent generating empty `SigningContextAttributeKey` list
lauzadis Feb 27, 2024
d04cad9
Add S3 Express to the end of the list
lauzadis Feb 27, 2024
e302fc7
Update tests to handle async refresh initiation
lauzadis Feb 27, 2024
26ed81e
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 28, 2024
52577d4
Make interceptors `internal`
lauzadis Feb 28, 2024
83a3942
Fix KDocs
lauzadis Feb 28, 2024
6be45a7
remove unnecessary `client` class variable
lauzadis Feb 28, 2024
f6c4fb2
Validate S3 Express was used for PutObject and add presigner test
lauzadis Feb 28, 2024
e07509d
Downgrade log level
lauzadis Feb 28, 2024
7237813
ktlint
lauzadis Feb 28, 2024
624ac0e
make const header val `internal`
lauzadis Feb 28, 2024
5c2dfe4
Add S3 Express benchmarks
lauzadis Feb 28, 2024
fca9d7a
Use `smithy.client.call.attempt_duration` metric
lauzadis Feb 28, 2024
84e1665
Bump to latest version of smithy-kotlin
lauzadis Feb 28, 2024
540cf74
Merge branch 'main' of github.com:awslabs/aws-sdk-kotlin into feat-s3…
lauzadis Feb 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/6aef179b-d710-40a5-bd6e-37078f07dfa4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "6aef179b-d710-40a5-bd6e-37078f07dfa4",
"type": "feature",
"description": "Add support for S3 Express One Zone"
}
1 change: 1 addition & 0 deletions aws-runtime/aws-http/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ kotlin {
api(project(":aws-runtime:aws-endpoint"))
api(libs.smithy.kotlin.aws.signing.common)
api(libs.smithy.kotlin.http.client)
api(libs.smithy.kotlin.http.auth.aws)
lauzadis marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import software.amazon.smithy.aws.traits.HttpChecksumTrait
import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.core.KotlinWriter
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes
import software.amazon.smithy.kotlin.codegen.core.defaultName
import software.amazon.smithy.kotlin.codegen.core.withBlock
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.model.*
Expand Down Expand Up @@ -43,22 +42,22 @@ class FlexibleChecksumsRequest : KotlinIntegration {
}

override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
val inputSymbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(op.inputShape))
val interceptorSymbol = RuntimeTypes.HttpClient.Interceptors.FlexibleChecksumsRequestInterceptor
val inputSymbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(op.inputShape))

val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()!!

val requestAlgorithmMember = ctx.model.expectShape<StructureShape>(op.input.get())
.members()
.first { it.memberName == httpChecksumTrait.requestAlgorithmMember.get() }

writer.withBlock(
"op.interceptors.add(#T<#T> {",
"})",
interceptorSymbol,
inputSymbol,
) {
writer.write("it.#L?.value", requestAlgorithmMember.defaultName())
val requestAlgorithmMemberName = ctx.symbolProvider.toMemberName(requestAlgorithmMember)

writer.withBlock("op.interceptors.add(#T<#T>() {", "})", interceptorSymbol, inputSymbol) {
writer.write("input.#L?.value", requestAlgorithmMemberName)
}
writer.withBlock("input.#L?.let {", "}", requestAlgorithmMemberName) {
writer.write("op.context[#T.ChecksumAlgorithm] = it.value", RuntimeTypes.HttpClient.Operation.HttpOperationContext)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package aws.sdk.kotlin.codegen.customization.s3.express

import SigV4S3ExpressAuthTrait
import aws.sdk.kotlin.codegen.customization.s3.isS3
import software.amazon.smithy.aws.traits.HttpChecksumTrait
import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.core.*
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes
import software.amazon.smithy.kotlin.codegen.model.*
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolMiddleware
import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigProperty
import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigPropertyType
import software.amazon.smithy.kotlin.codegen.utils.dq
import software.amazon.smithy.kotlin.codegen.utils.getOrNull
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.*
import software.amazon.smithy.model.traits.*
import software.amazon.smithy.model.transform.ModelTransformer

/**
* An integration which handles codegen for S3 Express, such as:
* 1. Configure auth scheme by applying a synthetic shape and trait
* 2. Add ExpressClient and Bucket to execution context
* 3. Override checksums to use CRC32 instead of MD5
* 4. Disable all checksums for s3:UploadPart
*/
class S3ExpressIntegration : KotlinIntegration {
companion object {
val DisableExpressSessionAuth: ConfigProperty = ConfigProperty {
name = "disableS3ExpressSessionAuth"
useSymbolWithNullableBuilder(KotlinTypes.Boolean, "false")
documentation = """
Flag to disable S3 Express One Zone's bucket-level session authentication method.
""".trimIndent()
}

val ExpressCredentialsProvider: ConfigProperty = ConfigProperty {
name = "expressCredentialsProvider"
symbol = RuntimeTypes.Auth.Credentials.AwsCredentials.CredentialsProvider
documentation = """
Credentials provider to be used for making requests to S3 Express.
""".trimIndent()

propertyType = ConfigPropertyType.Custom(
render = { _, writer ->
writer.write(
"public val #1L: #2T = builder.#1L ?: #3T()",
name,
symbol,
buildSymbol {
name = "DefaultS3ExpressCredentialsProvider"
namespace = "aws.sdk.kotlin.services.s3.express"
},
)
},
renderBuilder = { prop, writer ->
prop.documentation?.let(writer::dokka)
writer.write("public var #L: #T? = null", name, symbol)
},
)
}
}

override fun enabledForService(model: Model, settings: KotlinSettings) =
model.expectShape<ServiceShape>(settings.service).isS3

/**
* Add a synthetic SigV4 S3 Express auth trait and shape
*/
override fun preprocessModel(model: Model, settings: KotlinSettings): Model {
val transformer = ModelTransformer.create()

// AuthIndex.getAuthSchemes looks for shapes with an AuthDefinitionTrait, so need to make one for SigV4 S3Express
val authDefinitionTrait = AuthDefinitionTrait.builder().addTrait(SigV4S3ExpressAuthTrait.ID).build()
val sigV4S3ExpressAuthShape = StructureShape.builder()
.addTrait(authDefinitionTrait)
.id(SigV4S3ExpressAuthTrait.ID)
.build()

val serviceShape = settings.getService(model)
val serviceShapeBuilder = serviceShape.toBuilder()

serviceShapeBuilder.addTrait(SigV4S3ExpressAuthTrait())

val authTrait = AuthTrait(serviceShape.expectTrait(AuthTrait::class.java).valueSet + mutableSetOf(SigV4S3ExpressAuthTrait.ID))
serviceShapeBuilder.addTrait(authTrait)

// Add the new shape and update the service shape's AuthTrait
return transformer.replaceShapes(model, listOf(sigV4S3ExpressAuthShape, serviceShapeBuilder.build()))
}

override fun customizeMiddleware(ctx: ProtocolGenerator.GenerationContext, resolved: List<ProtocolMiddleware>) =
resolved + listOf(
AddClientToExecutionContext,
AddBucketToExecutionContext,
UseCrc32Checksum,
UploadPartDisableChecksum,
)

private val S3AttributesSymbol = buildSymbol {
name = "S3Attributes"
namespace = "aws.sdk.kotlin.services.s3"
}

private val AddClientToExecutionContext = object : ProtocolMiddleware {
override val name: String = "AddClientToExecutionContext"

override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
ctx.model.expectShape<ServiceShape>(ctx.settings.service).isS3

override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
writer.write("op.context[#T.ExpressClient] = this", S3AttributesSymbol)
}
}

private val AddBucketToExecutionContext = object : ProtocolMiddleware {
lauzadis marked this conversation as resolved.
Show resolved Hide resolved
override val name: String = "AddBucketToExecutionContext"

override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
ctx.model.expectShape<StructureShape>(op.input.get())
.members()
.any { it.memberName == "Bucket" }

override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
writer.write("input.bucket?.let { op.context[#T.Bucket] = it }", S3AttributesSymbol)
}
}

/**
* For any operations that require a checksum, set CRC32 if the user has not already configured a checksum.
*/
private val UseCrc32Checksum = object : ProtocolMiddleware {
override val name: String = "UseCrc32Checksum"

override val order: Byte = -1 // Render before flexible checksums

override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean = !op.isS3UploadPart &&
(op.hasTrait<HttpChecksumRequiredTrait>() || (op.hasTrait<HttpChecksumTrait>() && op.expectTrait<HttpChecksumTrait>().isRequestChecksumRequired))

override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
val interceptorSymbol = buildSymbol {
namespace = "aws.sdk.kotlin.services.s3.express"
name = "S3ExpressCrc32ChecksumInterceptor"
}

val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()

val checksumAlgorithmMember = ctx.model.expectShape<StructureShape>(op.input.get())
.members()
.firstOrNull { it.memberName == httpChecksumTrait?.requestAlgorithmMember?.getOrNull() }

// S3 models a header name x-amz-sdk-checksum-algorithm representing the name of the checksum algorithm used
val checksumHeaderName = checksumAlgorithmMember?.getTrait<HttpHeaderTrait>()?.value

writer.write("op.interceptors.add(#T(${checksumHeaderName?.dq() ?: ""}))", interceptorSymbol)
}
}

/**
* Disable all checksums for s3:UploadPart
*/
private val UploadPartDisableChecksum = object : ProtocolMiddleware {
override val name: String = "UploadPartDisableChecksum"

override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
op.isS3UploadPart

override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
val interceptorSymbol = buildSymbol {
namespace = "aws.sdk.kotlin.services.s3.express"
name = "S3ExpressDisableChecksumInterceptor"
}
writer.addImport(interceptorSymbol)
writer.write("op.interceptors.add(#T())", interceptorSymbol)
}
}

private val OperationShape.isS3UploadPart: Boolean get() = id.name == "UploadPart"

override fun additionalServiceConfigProps(ctx: CodegenContext): List<ConfigProperty> = listOf(
DisableExpressSessionAuth,
ExpressCredentialsProvider,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package aws.sdk.kotlin.codegen.customization.s3.express

import aws.sdk.kotlin.codegen.customization.s3.isS3
import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait
import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.codegen.core.SymbolReference
import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.core.*
import software.amazon.smithy.kotlin.codegen.integration.AppendingSectionWriter
import software.amazon.smithy.kotlin.codegen.integration.AuthSchemeHandler
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding
import software.amazon.smithy.kotlin.codegen.model.buildSymbol
import software.amazon.smithy.kotlin.codegen.model.expectShape
import software.amazon.smithy.kotlin.codegen.model.hasTrait
import software.amazon.smithy.kotlin.codegen.model.knowledge.AwsSignatureVersion4
import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointCustomization
import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointPropertyRenderer
import software.amazon.smithy.kotlin.codegen.rendering.endpoints.ExpressionRenderer
import software.amazon.smithy.kotlin.codegen.rendering.protocol.*
import software.amazon.smithy.kotlin.codegen.utils.getOrNull
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.node.Node
import software.amazon.smithy.model.shapes.OperationShape
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.model.shapes.ShapeId
import software.amazon.smithy.rulesengine.language.syntax.expressions.Expression
import java.util.*

/**
* Register support for the `sigv4-s3express` auth scheme.
*/
class SigV4S3ExpressAuthSchemeIntegration : KotlinIntegration {
// Needs to run after `SigV4AuthSchemeIntegration`
override val order: Byte = -51

override fun enabledForService(model: Model, settings: KotlinSettings): Boolean = model.expectShape<ServiceShape>(settings.service).isS3

override fun authSchemes(ctx: ProtocolGenerator.GenerationContext): List<AuthSchemeHandler> = listOf(SigV4S3ExpressAuthSchemeHandler())

override fun customizeEndpointResolution(ctx: ProtocolGenerator.GenerationContext): EndpointCustomization = SigV4S3ExpressEndpointCustomization

override val sectionWriters: List<SectionWriterBinding>
get() = listOf(SectionWriterBinding(HttpProtocolClientGenerator.ClientInitializer, renderClientInitializer))

// add S3 Express credentials provider to managed resources in the service client initializer
private val renderClientInitializer = AppendingSectionWriter { writer ->
writer.write("managedResources.#T(config.expressCredentialsProvider)", RuntimeTypes.Core.IO.addIfManaged)
}
}

internal val sigV4S3ExpressSymbol = buildSymbol {
name = "sigV4S3Express"
namespace = "aws.sdk.kotlin.services.s3.express"
}

internal val SigV4S3ExpressAuthSchemeSymbol = buildSymbol {
name = "SigV4S3ExpressAuthScheme"
namespace = "aws.sdk.kotlin.services.s3.express"
}

private object SigV4S3ExpressEndpointCustomization : EndpointCustomization {
override val propertyRenderers: Map<String, EndpointPropertyRenderer> = mapOf(
"authSchemes" to ::renderAuthScheme,
)
}

class SigV4S3ExpressAuthSchemeHandler : AuthSchemeHandler {
override val authSchemeId: ShapeId = ShapeId.from("aws.auth#sigv4s3express")

override val authSchemeIdSymbol: Symbol = buildSymbol {
name = "AuthSchemeId(\"aws.auth#sigv4s3express\")"
aajtodd marked this conversation as resolved.
Show resolved Hide resolved
val ref = RuntimeTypes.Auth.Identity.AuthSchemeId
objectRef = ref
namespace = ref.namespace
reference(ref, SymbolReference.ContextOption.USE)
}

override fun identityProviderAdapterExpression(writer: KotlinWriter) {
writer.write("config.#L", S3ExpressIntegration.ExpressCredentialsProvider.propertyName)
}

override fun authSchemeProviderInstantiateAuthOptionExpr(
ctx: ProtocolGenerator.GenerationContext,
op: OperationShape?,
writer: KotlinWriter,
) {
val expr = if (op?.hasTrait<UnsignedPayloadTrait>() == true) {
"#T(unsignedPayload = true)"
} else {
"#T()"
}
writer.write(expr, sigV4S3ExpressSymbol)
}

override fun instantiateAuthSchemeExpr(ctx: ProtocolGenerator.GenerationContext, writer: KotlinWriter) {
val signingService = AwsSignatureVersion4.signingServiceName(ctx.service)
writer.write("#T(#T, #S)", SigV4S3ExpressAuthSchemeSymbol, RuntimeTypes.Auth.Signing.AwsSigningStandard.DefaultAwsSigner, signingService)
}
}

private fun renderAuthScheme(writer: KotlinWriter, authSchemes: Expression, expressionRenderer: ExpressionRenderer) {
val expressScheme = authSchemes.toNode().expectArrayNode().find {
it.expectObjectNode().expectStringMember("name").value == "sigv4-s3express"
}?.expectObjectNode()

expressScheme?.let {
writer.writeInline("#T to ", RuntimeTypes.SmithyClient.Endpoints.SigningContextAttributeKey)
writer.withBlock("listOf(", ")") {
withBlock("#T(", "),", sigV4S3ExpressSymbol) {
// we delegate back to the expression visitor for each of these fields because it's possible to
// encounter template strings throughout

writeInline("serviceName = ")
renderOrElse(expressionRenderer, expressScheme.getStringMember("signingName"), "null")

writeInline("disableDoubleUriEncode = ")
renderOrElse(expressionRenderer, expressScheme.getBooleanMember("disableDoubleEncoding"), "false")

writeInline("signingRegion = ")
renderOrElse(expressionRenderer, expressScheme.getStringMember("signingRegion"), "null")
}
}
}
}

private fun KotlinWriter.renderOrElse(
expressionRenderer: ExpressionRenderer,
optionalNode: Optional<out Node>,
whenNullValue: String,
) {
val nullableNode = optionalNode.getOrNull()
when (nullableNode) {
null -> writeInline(whenNullValue)
else -> expressionRenderer.renderExpression(Expression.fromNode(nullableNode))
}
write(",")
}
Loading
Loading