Skip to content

Commit 1e555c3

Browse files
authored
fix: x-amz-content-sha256 header is expected for unsigned payload and event stream operations (#934)
1 parent ffb5a87 commit 1e555c3

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "4cc18c3e-31f4-4f70-987d-36e1ddee4a57",
3+
"type": "bugfix",
4+
"description": "Set X-Amz-Content-Sha256 header for unsigned payload and event stream operations by default",
5+
"issues": [
6+
"awslabs/aws-sdk-kotlin#1029"
7+
]
8+
}

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/auth/Sigv4AuthSchemeIntegration.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import software.amazon.smithy.kotlin.codegen.model.buildSymbol
1818
import software.amazon.smithy.kotlin.codegen.model.hasTrait
1919
import software.amazon.smithy.kotlin.codegen.model.knowledge.AwsSignatureVersion4
2020
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator
21+
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolMiddleware
2122
import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigProperty
2223
import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigPropertyType
2324
import software.amazon.smithy.model.Model
25+
import software.amazon.smithy.model.knowledge.EventStreamIndex
2426
import software.amazon.smithy.model.shapes.OperationShape
2527
import software.amazon.smithy.model.shapes.ShapeId
2628

@@ -36,6 +38,11 @@ class Sigv4AuthSchemeIntegration : KotlinIntegration {
3638

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

41+
override fun customizeMiddleware(
42+
ctx: ProtocolGenerator.GenerationContext,
43+
resolved: List<ProtocolMiddleware>,
44+
): List<ProtocolMiddleware> = resolved + Sigv4SignedBodyHeaderMiddleware()
45+
3946
override fun additionalServiceConfigProps(ctx: CodegenContext): List<ConfigProperty> {
4047
val credentialsProviderProp = ConfigProperty {
4148
symbol = RuntimeTypes.Auth.Credentials.AwsCredentials.CredentialsProvider
@@ -87,3 +94,23 @@ open class SigV4AuthSchemeHandler : AuthSchemeHandler {
8794
writer.write("#T(#T, #S)", RuntimeTypes.Auth.HttpAuthAws.SigV4AuthScheme, RuntimeTypes.Auth.Signing.AwsSigningStandard.DefaultAwsSigner, signingService)
8895
}
8996
}
97+
98+
/**
99+
* Conditionally updates the operation context to set the signed body header attribute
100+
* e.g. to set `X-Amz-Content-Sha256` header.
101+
*/
102+
class Sigv4SignedBodyHeaderMiddleware : ProtocolMiddleware {
103+
override val name: String = "Sigv4SignedBodyHeaderMiddleware"
104+
105+
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean {
106+
val hasEventStream = EventStreamIndex.of(ctx.model).getInputInfo(op).isPresent
107+
return hasEventStream || op.hasTrait<UnsignedPayloadTrait>()
108+
}
109+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
110+
writer.write(
111+
"op.context.set(#T.SignedBodyHeader, #T.X_AMZ_CONTENT_SHA256)",
112+
RuntimeTypes.Auth.Signing.AwsSigningCommon.AwsSigningAttributes,
113+
RuntimeTypes.Auth.Signing.AwsSigningCommon.AwsSignedBodyHeader,
114+
)
115+
}
116+
}

runtime/auth/http-auth-aws/common/src/aws/smithy/kotlin/runtime/http/auth/AwsHttpSigner.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ public class AwsHttpSigner(private val config: Config) : HttpSigner {
9393
* this parameter has no effect.
9494
*/
9595
public var expiresAfter: Duration? = null
96+
97+
/**
98+
* A predicate to control which headers are a part of the canonical request. Note that skipping auth-required
99+
* headers will result in an unusable signature. Headers injected by the signing process cannot be skipped.
100+
*
101+
* This function does not override the internal check function (e.g., for `x-amzn-trace-id`, `user-agent`, etc.) but
102+
* rather supplements it. In particular, a header will get signed if and only if it returns true to both the
103+
* internal check and this function (if defined).
104+
*
105+
* The default predicate is to not reject signing any headers (i.e., `_ -> true`).
106+
*/
107+
public var shouldSignHeader: ShouldSignHeaderPredicate = { _ -> true }
96108
}
97109

98110
override suspend fun sign(signingRequest: SignHttpRequest) {
@@ -118,6 +130,7 @@ public class AwsHttpSigner(private val config: Config) : HttpSigner {
118130
normalizeUriPath = config.normalizeUriPath
119131
useDoubleUriEncode = config.useDoubleUriEncode
120132
expiresAfter = config.expiresAfter
133+
shouldSignHeader = config.shouldSignHeader
121134

122135
signedBodyHeader = contextSignedBodyHeader ?: config.signedBodyHeader
123136

0 commit comments

Comments
 (0)