-
Notifications
You must be signed in to change notification settings - Fork 190
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
Add operation customization for disabling payload signing #3915
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
--- | ||
applies_to: ["client"] | ||
authors: ["Velfi"] | ||
references: ["smithy-rs#3583"] | ||
breaking: false | ||
new_feature: true | ||
bug_fix: false | ||
--- | ||
|
||
It is now possible to disable payload signing through an operation customization. | ||
|
||
```rust | ||
async fn put_example_object(client: &aws_sdk_s3::Client) { | ||
let res = client | ||
.put_object() | ||
.bucket("test-bucket") | ||
.key("test-key") | ||
.body(ByteStream::from_static(b"Hello, world!")) | ||
.customize() | ||
// Setting this will disable payload signing. | ||
.disable_payload_signing() | ||
.send() | ||
.await; | ||
} | ||
``` | ||
|
||
Disabling payload signing will result in a small speedup at the cost of removing a data integrity check. | ||
However, this is an advanced feature and **may not be supported by all services/operations**. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "aws-runtime" | ||
version = "1.4.3" | ||
version = "1.5.0" | ||
authors = ["AWS Rust SDK Team <[email protected]>"] | ||
description = "Runtime support code for the AWS SDK. This crate isn't intended to be used directly." | ||
edition = "2021" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,7 @@ val DECORATORS: List<ClientCodegenDecorator> = | |
TokenProvidersDecorator(), | ||
ServiceEnvConfigDecorator(), | ||
HttpRequestCompressionDecorator(), | ||
DisablePayloadSigningDecorator(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correctness: Should we only be applying this to S3 (and possibly only specific S3 operations)? I'm guessing most operations are going to require signing and won't work if the payload is unsigned but you'd have to test it. I also can't imagine it matters much for most operations to need unsigned so I'd rather not support this for more than we need to. |
||
// TODO(https://github.com/smithy-lang/smithy-rs/issues/3863): Comment in once the issue has been resolved | ||
// SmokeTestsDecorator(), | ||
), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.rustsdk | ||
|
||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext | ||
import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator | ||
import software.amazon.smithy.rust.codegen.client.smithy.generators.client.CustomizableOperationSection | ||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate | ||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope | ||
import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization | ||
import software.amazon.smithy.rust.codegen.core.smithy.customize.adhocCustomization | ||
|
||
class DisablePayloadSigningDecorator : ClientCodegenDecorator { | ||
override val name: String = "DisablePayloadSigning" | ||
override val order: Byte = 0 | ||
|
||
override fun extraSections(codegenContext: ClientCodegenContext): List<AdHocCustomization> = | ||
listOf( | ||
adhocCustomization<CustomizableOperationSection.CustomizableOperationImpl> { | ||
rustTemplate( | ||
""" | ||
/// Disable payload signing for this request. | ||
/// | ||
/// **WARNING:** This is an advanced feature that removes | ||
/// the cost of signing a request payload by removing a data | ||
/// integrity check. Not all services/operations support | ||
/// this feature. | ||
pub fn disable_payload_signing(self) -> Self { | ||
self.runtime_plugin(#{PayloadSigningOverrideRuntimePlugin}::unsigned()) | ||
} | ||
""", | ||
*preludeScope, | ||
"PayloadSigningOverrideRuntimePlugin" to | ||
AwsRuntimeType.awsRuntime(codegenContext.runtimeConfig) | ||
.resolve("auth::PayloadSigningOverrideRuntimePlugin"), | ||
) | ||
}, | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,9 @@ | |
|
||
use aws_credential_types::provider::SharedCredentialsProvider; | ||
use aws_sdk_s3::config::{Credentials, Region}; | ||
use aws_sdk_s3::primitives::ByteStream; | ||
use aws_sdk_s3::{Client, Config}; | ||
use aws_smithy_runtime::client::http::test_util::capture_request; | ||
use aws_smithy_runtime::client::http::test_util::{ReplayEvent, StaticReplayClient}; | ||
use aws_smithy_types::body::SdkBody; | ||
use http::header::AUTHORIZATION; | ||
|
@@ -40,3 +42,78 @@ async fn test_signer() { | |
|
||
http_client.assert_requests_match(&[AUTHORIZATION.as_str()]); | ||
} | ||
|
||
#[tokio::test] | ||
async fn disable_payload_signing_works() { | ||
let (http_client, request) = capture_request(None); | ||
let conf = aws_sdk_s3::Config::builder() | ||
.with_test_defaults() | ||
.behavior_version_latest() | ||
.region(Region::new("us-east-1")) | ||
.http_client(http_client) | ||
.build(); | ||
let client = aws_sdk_s3::Client::from_conf(conf); | ||
let _ = client | ||
.put_object() | ||
.bucket("XXXXXXXXXXX") | ||
.key("test-key") | ||
.body(ByteStream::from_static(b"Hello, world!")) | ||
.customize() | ||
.disable_payload_signing() | ||
.send() | ||
.await; | ||
|
||
let request = request.expect_request(); | ||
let x_amz_content_sha256 = request | ||
.headers() | ||
.get("x-amz-content-sha256") | ||
.expect("x-amz-content-sha256 is set") | ||
.to_owned(); | ||
assert_eq!("UNSIGNED-PAYLOAD", x_amz_content_sha256); | ||
} | ||
|
||
// This test ensures that the interceptor's payload signing setting | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which interceptor? Also maybe add context on why this is important. |
||
// takes priority over the runtime plugin for disabling signing. | ||
#[tokio::test] | ||
async fn disable_payload_signing_works_with_checksums() { | ||
let (http_client, request) = capture_request(None); | ||
let conf = aws_sdk_s3::Config::builder() | ||
.with_test_defaults() | ||
.behavior_version_latest() | ||
.region(Region::new("us-east-1")) | ||
.http_client(http_client) | ||
.build(); | ||
let client = aws_sdk_s3::Client::from_conf(conf); | ||
|
||
// ByteStreams created from a file are streaming and have a known size | ||
let mut file = tempfile::NamedTempFile::new().unwrap(); | ||
use std::io::Write; | ||
file.write_all(b"Hello, world!").unwrap(); | ||
|
||
let body = aws_sdk_s3::primitives::ByteStream::read_from() | ||
.path(file.path()) | ||
.buffer_size(1024) | ||
.build() | ||
.await | ||
.unwrap(); | ||
|
||
let _ = client | ||
.put_object() | ||
.bucket("XXXXXXXXXXX") | ||
.key("test-key") | ||
.body(body) | ||
.checksum_algorithm(aws_sdk_s3::types::ChecksumAlgorithm::Crc32) | ||
.customize() | ||
.disable_payload_signing() | ||
.send() | ||
.await; | ||
|
||
let request = request.expect_request(); | ||
let x_amz_content_sha256 = request | ||
.headers() | ||
.get("x-amz-content-sha256") | ||
.expect("x-amz-content-sha256 is set") | ||
.to_owned(); | ||
// The checksum interceptor sets this. | ||
assert_eq!("STREAMING-UNSIGNED-PAYLOAD-TRAILER", x_amz_content_sha256); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this not need gated anymore?