Repository navigation
test(auth): check SigV4 decisions against the AWS SDK signer - #792
LeeroyHannigan wants to merge 3 commits into
Conversation
Sign requests with aws-sigv4, the SigV4 signer in the AWS SDK for Rust, and pass them to BuiltinAuthProvider::authenticate. A request as signed must verify, and the server's canonical request must equal the signer's. A change to any part the signature covers must be refused with the message of the check that covers it. The fixed corpus covers the header sets DynamoDB clients sign and send, 39 region codes and three local endpoint names, a long-term key and a session key. 256 more requests come from proptest with a fixed seed. aws-sigv4, aws-credential-types and proptest are already in Cargo.lock and are dev-dependencies only.
navareamol
left a comment
There was a problem hiding this comment.
Two things:
- The skew window cases expect
UnrecognizedClientExceptionand our own message. Has anyone checked what real DynamoDB returns? Details inline on mutate.rs. - The description says "39 region codes and three local endpoint names".
local,localhostandLOCALare inREGIONS, so they're region names.ENDPOINTShas five entries.
I'll approve once 1 is checked (or the assertion is loosened) and the description is fixed.
| wire: changed(&signed.wire, |wire| { | ||
| wire.replace("x-amz-date", date.clone()) | ||
| }), | ||
| expected: Refusal::Client, |
There was a problem hiding this comment.
This test expects UnrecognizedClientException and our own message when the request's time is outside the 15 minute window. That copies what our server does today. Has anyone checked what real DynamoDB returns for this? If it's the same, great. If not, I'd check only that the request is refused here, and file the error type as a separate issue, so this test doesn't lock in an answer that might be wrong.
There was a problem hiding this comment.
Checked, and it differs. DynamoDB answers InvalidSignatureException for a date outside the window. The message starts "Signature expired:" for a past date and "Signature not yet current:" for a future one (us-east-1, 2026-11-03, each case twice). Our server answers UnrecognizedClientException with its own text, so the old assertion locked in the wrong answer.
062f439 changes the four cases per shape. The time check must refuse each one, with either error and any message except the scope date and signature mismatch messages. A request with X-Amz-Date moved after signing also breaks the signature, so these cases still check that the time check runs first, as it does on DynamoDB. The error type and message are now #805.
The skew window cases expected UnrecognizedClientException and the server's own message. DynamoDB answers InvalidSignatureException (#805). Its message starts "Signature expired:" for a past date and "Signature not yet current:" for a future one. Each of the four requests per shape must now be refused by the time check. Either error passes, with any message except those of the scope date check and the signature comparison. A request with X-Amz-Date moved after signing also breaks the signature, so it still checks that the time check runs first, as it does on DynamoDB. Its credential scope date moves with X-Amz-Date. The scope date check then passes when the move crosses midnight UTC.
|
Thanks. Both points are in 062f439 and the updated description.
|
Cargo.lock conflicted. Main moved extenddb-auth from hmac to aws-lc-rs. The lock file is main's, with extenddb-auth's dependency list extended by the three test dependencies this branch adds: aws-credential-types, aws-sigv4 and proptest.
What
This PR adds the test suite
crates/auth/tests/sigv4_differential. The suite signs requests withaws-sigv4, the SigV4 signer in the AWS SDK for Rust. It passes each request toBuiltinAuthProvider::authenticate, the call that the HTTP layer makes for a DynamoDB request. The credential store is in memory and holds a long-term key and a session key with its token.aws-sigv4signed. The requests use the header sets that DynamoDB clients sign and send. They also cover 42 region names (39 AWS region codes pluslocal,localhostandLOCAL), five endpoints and both keys. Others use header values with extra spaces, mixed-case header names, large bodies and clock offsets inside the skew window. Some change, add or remove unsigned headers after signing.SignedHeaders. Some carry different body bytes, with and withoutx-amz-content-sha256, or a timestamp moved by one second. Others use the wrong secret, a different credential scope or signature, or another session token or none. A request signed fors3has a valid signature, so only the service check can refuse it.InvalidSignatureExceptionorUnrecognizedClientException, with any message. The server's error and message differ from DynamoDB's, and A request outside the 15 minute SigV4 window gets UnrecognizedClientException; DynamoDB answers InvalidSignatureException #805 tracks that difference.aws-sigv4,aws-credential-typesandproptestare already inCargo.lock. They are dev-dependencies of extenddb-auth, and no package version changes.Scope: the requests are the ones that DynamoDB clients send. That is
POST /with no query string, header values in visible ASCII, and each signed header sent once. The harness builds the header map and body thatauthenticatereceives. It does not run the HTTP layer.Merge order: #355 and #512 change
BuiltinAuthProvider::newand some of the checks that this suite asserts. The PR that merges after this one updates the harness to match.Why
The server checks SigV4 signatures with its own implementation. The unit tests check it against the two AWS test vectors and against hand-written cases. This suite checks it against the SDK signer, across the header, body, scope and token combinations that clients produce.
The first version of the skew window cases expected
UnrecognizedClientExceptionand the server's own message. DynamoDB answersInvalidSignatureException. Its message starts "Signature expired:" for a past date and "Signature not yet current:" for a future date. DynamoDB also checks the time before it compares the signature. We measured these answers in us-east-1 on 2026-11-03, two times for each case.Testing done
cargo test -p extenddb-auth: 274 unit tests, the 13 suite tests and 3 doctests pass. The unit tests include the AWS SigV4 test vectors. The suite takes about 2.5 seconds in a debug build.x-amz-content-sha256IncompleteSignatureInvalidSignatureExceptionwith DynamoDB's message prefixes passes the suite.cargo +1.97.0 clippy --all-targets -- -D warnings,cargo fmt --checkandcargo +1.88.0 test -p extenddb-authare clean. The four license-notice checks pass.Checklist
cargo test --workspace)cargo fmt --check)cargo clippy -- -W clippy::pedantic)Storagetrait, auth model, on-diskformat, or public CLI surface, an RFC has been accepted or is linked
below. Otherwise, an ADR captures the decision (link below).
ADR / RFC: n/a. The PR adds tests and changes no server code.
By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.