Skip to content

Commit 5bd6de2

Browse files
committed
add support for md5 checksum validation
1 parent 939d273 commit 5bd6de2

File tree

12 files changed

+1104
-0
lines changed

12 files changed

+1104
-0
lines changed

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/profile/AwsProfile.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,30 @@ public inline fun <reified T : Enum<T>> AwsProfile.getEnumOrNull(key: String, su
221221
)
222222
}
223223

224+
/**
225+
* Parse a config value as an enum set.
226+
*/
227+
@InternalSdkApi
228+
public inline fun <reified T : Enum<T>> AwsProfile.getEnumSetOrNull(key: String, subKey: String? = null): Set<T>? =
229+
getOrNull(key, subKey)?.let { rawValue ->
230+
rawValue.split(",")
231+
.map { it.trim() }
232+
.map { value ->
233+
enumValues<T>().firstOrNull {
234+
it.name.equals(value, ignoreCase = true)
235+
} ?: throw ConfigurationException(
236+
buildString {
237+
append(key)
238+
append(" '")
239+
append(value)
240+
append("' is not supported, should be one of: ")
241+
enumValues<T>().joinTo(this) { it.name.lowercase() }
242+
}
243+
)
244+
}.toSet()
245+
.takeIf { it.isNotEmpty() }
246+
}
247+
224248
internal fun AwsProfile.getUrlOrNull(key: String, subKey: String? = null): Url? =
225249
getOrNull(key, subKey)?.let {
226250
try {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package aws.sdk.kotlin.codegen.customization.sqs
6+
7+
import aws.sdk.kotlin.codegen.ServiceClientCompanionObjectWriter
8+
import software.amazon.smithy.kotlin.codegen.KotlinSettings
9+
import software.amazon.smithy.kotlin.codegen.core.CodegenContext
10+
import software.amazon.smithy.kotlin.codegen.integration.AppendingSectionWriter
11+
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
12+
import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding
13+
import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes
14+
import software.amazon.smithy.kotlin.codegen.model.buildSymbol
15+
import software.amazon.smithy.kotlin.codegen.model.expectShape
16+
import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigProperty
17+
import software.amazon.smithy.model.Model
18+
import software.amazon.smithy.model.shapes.ServiceShape
19+
20+
class ClientConfigIntegration : KotlinIntegration {
21+
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
22+
model.expectShape<ServiceShape>(settings.service).isSqs
23+
24+
companion object {
25+
val ValidationEnabledProp: ConfigProperty = ConfigProperty {
26+
name = "checksumValidationEnabled"
27+
symbol = buildSymbol {
28+
name = "ValidationEnabled"
29+
namespace = "aws.sdk.kotlin.services.sqs.internal"
30+
documentation = """
31+
Specifies when MD5 checksum validation should be performed for SQS messages. This controls the automatic
32+
calculation and validation of checksums during message operations.
33+
34+
Valid values:
35+
- ALWAYS (default) - Checksums are calculated and validated for both sending and receiving operations
36+
(SendMessage, SendMessageBatch, and ReceiveMessage)
37+
- WHEN_SENDING - Checksums are only calculated and validated during send operations
38+
(SendMessage and SendMessageBatch)
39+
- WHEN_RECEIVING - Checksums are only calculated and validated during receive operations
40+
(ReceiveMessage)
41+
- NEVER - No checksum calculation or validation is performed
42+
""".trimIndent()
43+
}
44+
}
45+
46+
private val validationScope = buildSymbol {
47+
name = "ValidationScope"
48+
namespace = "aws.sdk.kotlin.services.sqs.internal"
49+
}
50+
51+
val ValidationScopeProp: ConfigProperty = ConfigProperty {
52+
name = "checksumValidationScopes"
53+
symbol = KotlinTypes.Collections.set(validationScope, default = "emptySet()")
54+
documentation = """
55+
Specifies which parts of an SQS message should undergo MD5 checksum validation. This configuration
56+
accepts a set of validation scopes that determine which message components to validate.
57+
58+
Valid values:
59+
- MESSAGE_ATTRIBUTES - Validates checksums for message attributes
60+
- MESSAGE_SYSTEM_ATTRIBUTES - Validates checksums for message system attributes
61+
(Note: Not available for ReceiveMessage operations as SQS does not calculate checksums for
62+
system attributes during message receipt)
63+
- MESSAGE_BODY - Validates checksums for the message body
64+
65+
Default: All three scopes (MESSAGE_ATTRIBUTES, MESSAGE_SYSTEM_ATTRIBUTES, MESSAGE_BODY)
66+
""".trimIndent()
67+
}
68+
}
69+
70+
override fun additionalServiceConfigProps(ctx: CodegenContext): List<ConfigProperty> =
71+
listOf(
72+
ValidationEnabledProp,
73+
ValidationScopeProp,
74+
)
75+
76+
override val sectionWriters: List<SectionWriterBinding>
77+
get() = listOf(
78+
SectionWriterBinding(
79+
ServiceClientCompanionObjectWriter.FinalizeEnvironmentalConfig,
80+
finalizeSqsConfigWriter,
81+
),
82+
)
83+
84+
// add Sqs-specific config finalization
85+
private val finalizeSqsConfigWriter = AppendingSectionWriter { writer ->
86+
val finalizeSqsConfig = buildSymbol {
87+
name = "finalizeSqsConfig"
88+
namespace = "aws.sdk.kotlin.services.sqs.internal"
89+
}
90+
writer.write("#T(builder, sharedConfig)", finalizeSqsConfig)
91+
}
92+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package aws.sdk.kotlin.codegen.customization.sqs
6+
7+
import software.amazon.smithy.kotlin.codegen.KotlinSettings
8+
import software.amazon.smithy.kotlin.codegen.core.KotlinWriter
9+
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
10+
import software.amazon.smithy.kotlin.codegen.model.buildSymbol
11+
import software.amazon.smithy.kotlin.codegen.model.expectShape
12+
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator
13+
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolMiddleware
14+
import software.amazon.smithy.model.Model
15+
import software.amazon.smithy.model.shapes.OperationShape
16+
import software.amazon.smithy.model.shapes.ServiceShape
17+
18+
/**
19+
* Register interceptor to handle SQS message MD5 checksum validation.
20+
*/
21+
class SqsMd5ChecksumValidationIntegration : KotlinIntegration {
22+
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
23+
model.expectShape<ServiceShape>(settings.service).isSqs
24+
25+
override fun customizeMiddleware(
26+
ctx: ProtocolGenerator.GenerationContext,
27+
resolved: List<ProtocolMiddleware>,
28+
): List<ProtocolMiddleware> = resolved + listOf(SqsMd5ChecksumValidationMiddleware)
29+
}
30+
31+
internal object SqsMd5ChecksumValidationMiddleware : ProtocolMiddleware {
32+
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean {
33+
return when (op.id.name) {
34+
"ReceiveMessage",
35+
"SendMessage",
36+
"SendMessageBatch" -> true
37+
else -> false
38+
}
39+
}
40+
41+
override val name: String = "SqsMd5ChecksumValidationInterceptor"
42+
43+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
44+
val symbol = buildSymbol {
45+
name = this@SqsMd5ChecksumValidationMiddleware.name
46+
namespace = "aws.sdk.kotlin.services.sqs"
47+
}
48+
49+
writer.write("op.interceptors.add(#T(config.checksumValidationEnabled, config.checksumValidationScopes,))", symbol)
50+
}
51+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package aws.sdk.kotlin.codegen.customization.sqs
6+
7+
import aws.sdk.kotlin.codegen.sdkId
8+
import software.amazon.smithy.model.shapes.ServiceShape
9+
10+
/**
11+
* Returns true if the service is Sqs
12+
*/
13+
val ServiceShape.isSqs: Boolean
14+
get() = sdkId.lowercase() == "sqs"

codegen/aws-sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,5 @@ aws.sdk.kotlin.codegen.smoketests.SmokeTestsDenyListIntegration
4949
aws.sdk.kotlin.codegen.smoketests.testing.SmokeTestSuccessHttpEngineIntegration
5050
aws.sdk.kotlin.codegen.smoketests.testing.SmokeTestFailHttpEngineIntegration
5151
aws.sdk.kotlin.codegen.customization.AwsQueryModeCustomization
52+
aws.sdk.kotlin.codegen.customization.sqs.ClientConfigIntegration
53+
aws.sdk.kotlin.codegen.customization.sqs.SqsMd5ChecksumValidationIntegration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package aws.sdk.kotlin.codegen.customization.sqs
6+
7+
import aws.sdk.kotlin.codegen.testutil.model
8+
import org.junit.jupiter.api.Test
9+
import software.amazon.smithy.kotlin.codegen.core.KotlinWriter
10+
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator
11+
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolMiddleware
12+
import software.amazon.smithy.kotlin.codegen.test.defaultSettings
13+
import software.amazon.smithy.kotlin.codegen.test.newTestContext
14+
import software.amazon.smithy.model.shapes.OperationShape
15+
import kotlin.test.assertEquals
16+
import kotlin.test.assertFalse
17+
import kotlin.test.assertTrue
18+
import kotlin.test.fail
19+
20+
class SqsMd5ChecksumValidationIntegrationTest {
21+
@Test
22+
fun testNotExpectedForNonSqsModel() {
23+
val model = model("NotSqs")
24+
val actual = SqsMd5ChecksumValidationIntegration().enabledForService(model, model.defaultSettings())
25+
26+
assertFalse(actual)
27+
}
28+
29+
@Test
30+
fun testExpectedForSqsModel() {
31+
val model = model("Sqs")
32+
val actual = SqsMd5ChecksumValidationIntegration().enabledForService(model, model.defaultSettings())
33+
34+
assertTrue(actual)
35+
}
36+
37+
@Test
38+
fun testMiddlewareAddition() {
39+
val model = model("Sqs")
40+
val preexistingMiddleware = listOf(FooMiddleware)
41+
val ctx = model.newTestContext("Sqs")
42+
val actual = SqsMd5ChecksumValidationIntegration().customizeMiddleware(ctx.generationCtx, preexistingMiddleware)
43+
44+
assertEquals(listOf(FooMiddleware, SqsMd5ChecksumValidationMiddleware), actual)
45+
}
46+
}
47+
48+
object FooMiddleware : ProtocolMiddleware {
49+
override val name: String = "FooMiddleware"
50+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) =
51+
fail("Unexpected call to `FooMiddleware.render")
52+
}

0 commit comments

Comments
 (0)