Skip to content

Commit 37c1cc0

Browse files
author
Zelda Hessler
authored
add codegen test for sigv4a EPR (#3848)
exactly what it says on the tin. Let me know if we should have any other tests verifying the function of sigv4a auth schemes. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
1 parent a64982a commit 37c1cc0

File tree

2 files changed

+118
-9
lines changed

2 files changed

+118
-9
lines changed

aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecoratorTest.kt

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
package software.amazon.smithy.rustsdk
66

77
import org.junit.jupiter.api.Test
8+
import software.amazon.smithy.rust.codegen.core.rustlang.Attribute
9+
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
10+
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
811
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
12+
import software.amazon.smithy.rust.codegen.core.testutil.integrationTest
13+
import software.amazon.smithy.rust.codegen.core.testutil.tokioTest
914

1015
class SigV4AuthDecoratorTest {
1116
private val modelWithSigV4AuthScheme =
@@ -35,6 +40,7 @@ class SigV4AuthDecoratorTest {
3540
3641
structure SomeInput {
3742
@httpPayload
43+
@required
3844
something: Bytestream
3945
}
4046
@@ -56,10 +62,115 @@ class SigV4AuthDecoratorTest {
5662
@unsignedPayload
5763
@http(uri: "/", method: "POST")
5864
operation SomeOperation { input: SomeInput, output: SomeOutput }
59-
""".asSmithyModel()
65+
""".asSmithyModel(smithyVersion = "2.0")
6066

6167
@Test
6268
fun unsignedPayloadSetsCorrectHeader() {
6369
awsSdkIntegrationTest(modelWithSigV4AuthScheme) { _, _ -> }
6470
}
71+
72+
private val modelWithSigV4aAuthScheme =
73+
"""
74+
namespace test
75+
76+
use aws.auth#sigv4
77+
use aws.auth#sigv4a
78+
use aws.api#service
79+
use aws.protocols#restJson1
80+
use smithy.rules#endpointRuleSet
81+
use aws.auth#unsignedPayload
82+
use smithy.test#httpRequestTests
83+
84+
@auth([sigv4a,sigv4])
85+
@sigv4(name: "dontcare")
86+
@sigv4a(name: "dontcare")
87+
@restJson1
88+
@endpointRuleSet({
89+
"version": "1.0",
90+
"rules": [
91+
{
92+
"type": "endpoint",
93+
"conditions": [],
94+
"endpoint": {
95+
"url": "https://example.com",
96+
"properties": {
97+
"authSchemes": [
98+
{
99+
"name": "sigv4a",
100+
"signingRegionSet": ["*"],
101+
"signingName": "dontcare"
102+
}
103+
]
104+
}
105+
}
106+
}
107+
],
108+
"parameters": {
109+
"endpoint": { "required": true, "type": "string", "builtIn": "SDK::Endpoint" },
110+
}
111+
})
112+
@service(sdkId: "dontcare")
113+
service TestService { version: "2023-01-01", operations: [SomeOperation] }
114+
115+
@streaming
116+
blob Bytestream
117+
118+
structure SomeInput {
119+
@httpPayload
120+
@required
121+
something: Bytestream
122+
}
123+
124+
structure SomeOutput { something: String }
125+
126+
@http(uri: "/", method: "POST")
127+
operation SomeOperation { input: SomeInput, output: SomeOutput }
128+
""".asSmithyModel(smithyVersion = "2.0")
129+
130+
@Test
131+
fun unsignedPayloadSetsCorrectHeaderForSigV4a() {
132+
awsSdkIntegrationTest(modelWithSigV4aAuthScheme) { clientCodegenContext, rustCrate ->
133+
val moduleUseName = clientCodegenContext.moduleUseName()
134+
val rc = clientCodegenContext.runtimeConfig
135+
136+
rustCrate.integrationTest("sigv4a") {
137+
Attribute.featureGate("test-util").render(this)
138+
tokioTest("test_sigv4a_signing") {
139+
rustTemplate(
140+
"""
141+
let http_client = #{StaticReplayClient}::new(vec![#{ReplayEvent}::new(
142+
#{Request}::builder()
143+
.header("authorization", "AWS4-ECDSA-P256-SHA256 Credential=ANOTREAL/20090213/dontcare/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date;x-amz-region-set;x-amz-user-agent, Signature=3045022100b95d1c054ff04b676d12f0c893348606844d67ccf595981f0ca4968fae2eddfd022073e66edc0ad1da05b08392fccefa3ad69f8ec9393461033412fa05c55b749e9d")
144+
.uri("https://example.com")
145+
.body(#{SdkBody}::from("Hello, world!"))
146+
.unwrap(),
147+
#{Response}::builder().status(200).body(#{SdkBody}::empty()).unwrap(),
148+
)]);
149+
let config = $moduleUseName::Config::builder()
150+
.http_client(http_client.clone())
151+
.endpoint_url("https://example.com")
152+
.behavior_version_latest()
153+
.with_test_defaults()
154+
.build();
155+
let client = $moduleUseName::Client::from_conf(config);
156+
let _ = client.some_operation().something(#{ByteStream}::from_static(b"Hello, world!")).send().await;
157+
158+
http_client.assert_requests_match(&["authorization"]);
159+
let auth_header = http_client.actual_requests().next().unwrap().headers().get(http::header::AUTHORIZATION).unwrap();
160+
assert!(auth_header.contains("AWS4-ECDSA-P256-SHA256"));
161+
""",
162+
"ByteStream" to RuntimeType.byteStream(rc),
163+
"Credentials" to AwsRuntimeType.awsCredentialTypesTestUtil(rc).resolve("Credentials"),
164+
"Region" to AwsRuntimeType.awsTypes(rc).resolve("region::Region"),
165+
"ReplayEvent" to RuntimeType.smithyRuntimeTestUtil(rc).resolve("ReplayEvent"),
166+
"Request" to RuntimeType.HttpRequest,
167+
"Response" to RuntimeType.HttpResponse,
168+
"SdkBody" to RuntimeType.sdkBody(rc),
169+
"StaticReplayClient" to RuntimeType.smithyRuntimeTestUtil(rc).resolve("StaticReplayClient"),
170+
"tracing_subscriber" to RuntimeType.TracingSubscriber,
171+
)
172+
}
173+
}
174+
}
175+
}
65176
}

codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -279,27 +279,25 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null)
279279
val Bytes = CargoDependency.Bytes.toType().resolve("Bytes")
280280
val Http = CargoDependency.Http.toType()
281281
val HttpBody = CargoDependency.HttpBody.toType()
282-
val HttpHeaderMap = Http.resolve("HeaderMap")
283282
val HttpRequest = Http.resolve("Request")
284283
val HttpRequestBuilder = Http.resolve("request::Builder")
285284
val HttpResponse = Http.resolve("Response")
286285
val HttpResponseBuilder = Http.resolve("response::Builder")
287286
val Hyper = CargoDependency.Hyper.toType()
288287
val LazyStatic = CargoDependency.LazyStatic.toType()
289-
val Md5 = CargoDependency.Md5.toType()
290288
val OnceCell = CargoDependency.OnceCell.toType()
291289
val PercentEncoding = CargoDependency.PercentEncoding.toType()
292290
val PrettyAssertions = CargoDependency.PrettyAssertions.toType()
293291
val Regex = CargoDependency.Regex.toType()
294292
val Serde = CargoDependency.Serde.toType()
295293
val SerdeDeserialize = Serde.resolve("Deserialize")
296294
val SerdeSerialize = Serde.resolve("Serialize")
297-
val RegexLite = CargoDependency.RegexLite.toType()
298295
val Tokio = CargoDependency.Tokio.toType()
299296
val TokioStream = CargoDependency.TokioStream.toType()
300297
val Tower = CargoDependency.Tower.toType()
301298
val Tracing = CargoDependency.Tracing.toType()
302299
val TracingTest = CargoDependency.TracingTest.toType()
300+
val TracingSubscriber = CargoDependency.TracingSubscriber.toType()
303301

304302
// codegen types
305303
val ConstrainedTrait = RuntimeType("crate::constrained::Constrained", InlineDependency.constrained())
@@ -312,8 +310,6 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null)
312310

313311
fun smithyChecksums(runtimeConfig: RuntimeConfig) = CargoDependency.smithyChecksums(runtimeConfig).toType()
314312

315-
fun smithyCompression(runtimeConfig: RuntimeConfig) = CargoDependency.smithyCompression(runtimeConfig).toType()
316-
317313
fun smithyEventStream(runtimeConfig: RuntimeConfig) = CargoDependency.smithyEventStream(runtimeConfig).toType()
318314

319315
fun smithyHttp(runtimeConfig: RuntimeConfig) = CargoDependency.smithyHttp(runtimeConfig).toType()
@@ -444,7 +440,7 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null)
444440
forInlineDependency(InlineDependency.awsQueryCompatibleErrors(runtimeConfig))
445441

446442
fun defaultAuthPlugin(runtimeConfig: RuntimeConfig) =
447-
RuntimeType.forInlineDependency(InlineDependency.defaultAuthPlugin(runtimeConfig))
443+
forInlineDependency(InlineDependency.defaultAuthPlugin(runtimeConfig))
448444
.resolve("DefaultAuthOptionsPlugin")
449445

450446
fun labelFormat(
@@ -502,9 +498,11 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null)
502498
return smithyTypes(runtimeConfig).resolve("date_time::Format::$timestampFormat")
503499
}
504500

501+
fun smithyRuntimeTestUtil(runtimeConfig: RuntimeConfig) =
502+
CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType().resolve("client::http::test_util")
503+
505504
fun captureRequest(runtimeConfig: RuntimeConfig) =
506-
CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType()
507-
.resolve("client::http::test_util::capture_request")
505+
smithyRuntimeTestUtil(runtimeConfig).resolve("capture_request")
508506

509507
fun forInlineDependency(inlineDependency: InlineDependency) =
510508
RuntimeType("crate::${inlineDependency.name}", inlineDependency)

0 commit comments

Comments
 (0)