Unverified Commit 4b16e27c authored by Shing Lyu's avatar Shing Lyu Committed by GitHub
Browse files

Integration test for qldbsession request signing (#350)



* fix: typo in qldbsession example

* feat: test harness for QLDB signv4 service name

* fix: typo in qldbsession example

* feat: test harness for QLDB signv4 service name

* feat: integration test for qldbsession signing

* fix: request protocol version

* fix: test request protocol version

* fix: overwrite the user agent for test

Co-authored-by: default avatarShing Lyu <shinglyu@amazon.nl>
parent 7955da2e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ import software.amazon.smithy.rust.codegen.smithy.generators.LibRsSection
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig
import software.amazon.smithy.rust.codegen.smithy.letIf

val TestedServices = setOf("aws-sdk-kms", "aws-sdk-dynamodb")
val TestedServices = setOf("aws-sdk-kms", "aws-sdk-dynamodb", "aws-sdk-qldbsession")

class IntegrationTestDecorator : RustCodegenDecorator {
    override val name: String = "IntegrationTest"
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ edition = "2018"
[dependencies]
qldbsession = { package = "aws-sdk-qldbsession", path = "../../build/aws-sdk/qldbsession" }
### To use native TLS:
# dynamodb = { package = "aws-sdk-qldbsession", path = "../../build/aws-sdk/qldbsession", default-features = false, features = ["native-tls"] }
# qldbsession = { package = "aws-sdk-qldbsession", path = "../../build/aws-sdk/qldbsession", default-features = false, features = ["native-tls"] }

tokio = { version = "1", features = ["full"] }

+19 −0
Original line number Diff line number Diff line
# This Cargo.toml is unused in generated code. It exists solely to enable these tests to compile in-situ
[package]
name = "qldb-tests"
version = "0.1.0"
authors = ["Russell Cohen <rcoh@amazon.com>", "Shing Lyu <shinglyu@amazon.com"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
aws-sdk-qldbsession = { path = "../../build/aws-sdk/qldbsession" }
smithy-http = { path = "../../build/aws-sdk/smithy-http" }
smithy-types = { path = "../../build/aws-sdk/smithy-types" }
http = "0.2.3"
aws-hyper = { path = "../../build/aws-sdk/aws-hyper", features = ["test-util"] }
aws-auth = { path = "../../build/aws-sdk/aws-auth" }
aws-http = { path = "../../build/aws-sdk/aws-http" }
tokio = { version = "1", features = ["full"]}
tracing-subscriber = "0.2.16"
+4 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_auth::Credentials;
use aws_http::user_agent::AwsUserAgent;
use aws_hyper::test_connection::TestConnection;
use aws_hyper::Client;
use aws_sdk_qldbsession as qldbsession;
use http::Uri;
use qldbsession::model::StartSessionRequest;
use qldbsession::operation::SendCommand;
use qldbsession::{Config, Region};
use smithy_http::body::SdkBody;
use std::time::{Duration, UNIX_EPOCH};

// TODO: having the full HTTP requests right in the code is a bit gross, consider something
// like https://github.com/davidbarsky/sigv4/blob/master/aws-sigv4/src/lib.rs#L283-L315 to store
// the requests/responses externally

#[tokio::test]
async fn signv4_use_correct_service_name() {
    let creds = Credentials::from_keys(
        "ANOTREAL",
        "notrealrnrELgWzOk3IfjzDKtFBhDby",
        Some("notarealsessiontoken".to_string()),
    );
    let conn = TestConnection::new(vec![(
        http::Request::builder()
            .header("content-type", "application/x-amz-json-1.0")
            .header("x-amz-target", "QLDBSession.SendCommand")
            .header("content-length", "49")
            .header("host", "session.qldb.us-east-1.amazonaws.com")
            .header("authorization", "AWS4-HMAC-SHA256 Credential=ANOTREAL/20210305/us-east-1/qldb/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-target, Signature=38be4a432384f4ee7fb9683a9d093cc636a86a4fa6e7e8a198f4437c8c7f596a")
            // qldbsession uses the service name 'qldb' in signature _________________________^^^^
            .header("x-amz-date", "20210305T134922Z")
            .header("x-amz-security-token", "notarealsessiontoken")
            .header("user-agent", "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0")
            .uri(Uri::from_static("https://session.qldb.us-east-1.amazonaws.com/"))
            .body(SdkBody::from(r#"{"StartSession":{"LedgerName":"not-real-ledger"}}"#)).unwrap(),
        http::Response::builder()
            .status(http::StatusCode::from_u16(200).unwrap())
            .body(r#"{}"#).unwrap()),
    ]);

    let client = Client::new(conn.clone());
    let conf = Config::builder()
        .region(Region::new("us-east-1"))
        .credentials_provider(creds)
        .build();

    let mut op = SendCommand::builder()
        .start_session(
            StartSessionRequest::builder()
                .ledger_name("not-real-ledger")
                .build(),
        )
        .build()
        .unwrap()
        .make_operation(&conf)
        .expect("valid operation");
    // Fix the request time and user agent so the headers are stable
    op.config_mut()
        .insert(UNIX_EPOCH + Duration::from_secs(1614952162));
    op.config_mut().insert(AwsUserAgent::for_tests());

    let _ = client.call(op).await.expect("request should succeed");

    assert_eq!(conn.requests().len(), 1);
    for validate_request in conn.requests().iter() {
        validate_request.assert_matches(vec![]);
    }
}