mirror of https://github.com/smithy-lang/smithy-rs
Use `Identity` instead of `Credentials` in signing code (#2913)
This PR replaces the access_key, secret_key, and session token fields of signing params with the Orchestrator's `Identity` type. ## Checklist <!--- If a checkbox below is not applicable, then please DELETE it rather than leaving it unchecked --> - [x] I have updated `CHANGELOG.next.toml` if I made changes to the smithy-rs codegen or runtime crates - [x] I have updated `CHANGELOG.next.toml` if I made changes to the AWS SDK, generated SDK code, or SDK runtime crates ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
This commit is contained in:
parent
87d601b456
commit
39c6476f31
|
@ -51,3 +51,12 @@ message = "In sigV4-related code, rename 'signing service' to 'signing name'. Th
|
|||
references = ["smithy-rs#2911"]
|
||||
meta = { "breaking" = true, "tada" = false, "bug" = false }
|
||||
author = "Velfi"
|
||||
|
||||
[[aws-sdk-rust]]
|
||||
message = """
|
||||
All versions of SigningParams have been updated to contain an [`Identity`](https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/identity/struct.Identity.html)
|
||||
as opposed to AWS credentials in `&str` form. [Read more](https://github.com/awslabs/aws-sdk-rust/discussions/868).
|
||||
"""
|
||||
references = ["smithy-rs#2913"]
|
||||
meta = { "breaking" = true, "tada" = false, "bug" = false }
|
||||
author = "Velfi"
|
||||
|
|
|
@ -14,6 +14,7 @@ test-util = []
|
|||
[dependencies]
|
||||
aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" }
|
||||
aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" }
|
||||
aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["client"] }
|
||||
fastrand = "2.0.0"
|
||||
tokio = { version = "1.23.1", features = ["sync"] }
|
||||
tracing = "0.1"
|
||||
|
@ -28,9 +29,6 @@ env_logger = "0.9.0"
|
|||
|
||||
tokio = { version = "1.23.1", features = ["full", "test-util", "rt"] }
|
||||
tracing-test = "0.2.4"
|
||||
# TODO(https://github.com/awslabs/smithy-rs/issues/2619): Remove this
|
||||
# workaround once the fixed is upstreamed.
|
||||
regex = { version = "1.0", features = ["unicode-case", "unicode-perl"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
|
|
@ -10,6 +10,8 @@ use std::sync::Arc;
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use aws_smithy_runtime_api::client::identity::Identity;
|
||||
|
||||
/// AWS SDK Credentials
|
||||
///
|
||||
/// An opaque struct representing credentials that may be used in an AWS SDK, modeled on
|
||||
|
@ -140,18 +142,6 @@ impl Credentials {
|
|||
)
|
||||
}
|
||||
|
||||
/// Creates a test `Credentials`.
|
||||
#[cfg(feature = "test-util")]
|
||||
pub fn for_tests() -> Self {
|
||||
Self::new(
|
||||
"ANOTREAL",
|
||||
"notrealrnrELgWzOk3IfjzDKtFBhDby",
|
||||
Some("notarealsessiontoken".to_string()),
|
||||
None,
|
||||
"test",
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the access key ID.
|
||||
pub fn access_key_id(&self) -> &str {
|
||||
&self.0.access_key_id
|
||||
|
@ -178,6 +168,38 @@ impl Credentials {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-util")]
|
||||
impl Credentials {
|
||||
/// Creates a test `Credentials` with no session token.
|
||||
pub fn for_tests() -> Self {
|
||||
Self::new(
|
||||
"ANOTREAL",
|
||||
"notrealrnrELgWzOk3IfjzDKtFBhDby",
|
||||
None,
|
||||
None,
|
||||
"test",
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a test `Credentials` that include a session token.
|
||||
pub fn for_tests_with_session_token() -> Self {
|
||||
Self::new(
|
||||
"ANOTREAL",
|
||||
"notrealrnrELgWzOk3IfjzDKtFBhDby",
|
||||
Some("notarealsessiontoken".to_string()),
|
||||
None,
|
||||
"test",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Credentials> for Identity {
|
||||
fn from(val: Credentials) -> Self {
|
||||
let expiry = val.expiry();
|
||||
Identity::new(val, expiry)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Credentials;
|
||||
|
|
|
@ -89,8 +89,9 @@ fn test_operation() -> Operation<TestOperationParser, AwsResponseRetryClassifier
|
|||
));
|
||||
aws_http::auth::set_credentials_cache(
|
||||
conf,
|
||||
CredentialsCache::lazy()
|
||||
.create_cache(SharedCredentialsProvider::new(Credentials::for_tests())),
|
||||
CredentialsCache::lazy().create_cache(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
)),
|
||||
);
|
||||
conf.insert(SigningRegion::from_static("test-region"));
|
||||
conf.insert(OperationSigningConfig::default_config());
|
||||
|
|
|
@ -217,12 +217,16 @@ impl SigV4Signer {
|
|||
|
||||
fn signing_params<'a>(
|
||||
settings: SigningSettings,
|
||||
credentials: &'a Credentials,
|
||||
identity: &'a Identity,
|
||||
operation_config: &'a SigV4OperationSigningConfig,
|
||||
request_timestamp: SystemTime,
|
||||
) -> Result<SigningParams<'a>, SigV4SigningError> {
|
||||
let creds = identity
|
||||
.data::<Credentials>()
|
||||
.ok_or_else(|| SigV4SigningError::WrongIdentityType(identity.clone()))?;
|
||||
|
||||
if let Some(expires_in) = settings.expires_in {
|
||||
if let Some(creds_expires_time) = credentials.expiry() {
|
||||
if let Some(creds_expires_time) = creds.expiry() {
|
||||
let presigned_expires_time = request_timestamp + expires_in;
|
||||
if presigned_expires_time > creds_expires_time {
|
||||
tracing::warn!(EXPIRATION_WARNING);
|
||||
|
@ -230,9 +234,8 @@ impl SigV4Signer {
|
|||
}
|
||||
}
|
||||
|
||||
let mut builder = SigningParams::builder()
|
||||
.access_key(credentials.access_key_id())
|
||||
.secret_key(credentials.secret_access_key())
|
||||
let builder = SigningParams::builder()
|
||||
.identity(identity)
|
||||
.region(
|
||||
operation_config
|
||||
.region
|
||||
|
@ -249,7 +252,6 @@ impl SigV4Signer {
|
|||
)
|
||||
.time(request_timestamp)
|
||||
.settings(settings);
|
||||
builder.set_security_token(credentials.session_token());
|
||||
Ok(builder.build().expect("all required fields set"))
|
||||
}
|
||||
|
||||
|
@ -324,18 +326,18 @@ impl Signer for SigV4Signer {
|
|||
Self::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
|
||||
let request_time = runtime_components.time_source().unwrap_or_default().now();
|
||||
|
||||
let credentials = if let Some(creds) = identity.data::<Credentials>() {
|
||||
creds
|
||||
} else if operation_config.signing_options.signing_optional {
|
||||
tracing::debug!("skipped SigV4 signing since signing is optional for this operation and there are no credentials");
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(SigV4SigningError::WrongIdentityType(identity.clone()).into());
|
||||
if identity.data::<Credentials>().is_none() {
|
||||
if operation_config.signing_options.signing_optional {
|
||||
tracing::debug!("skipped SigV4 signing since signing is optional for this operation and there are no credentials");
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(SigV4SigningError::WrongIdentityType(identity.clone()).into());
|
||||
}
|
||||
};
|
||||
|
||||
let settings = Self::settings(&operation_config);
|
||||
let signing_params =
|
||||
Self::signing_params(settings, credentials, &operation_config, request_time)?;
|
||||
Self::signing_params(settings, identity, &operation_config, request_time)?;
|
||||
|
||||
let (signing_instructions, _signature) = {
|
||||
// A body that is already in memory can be signed directly. A body that is not in memory
|
||||
|
@ -382,7 +384,7 @@ impl Signer for SigV4Signer {
|
|||
signer_sender
|
||||
.send(Box::new(SigV4MessageSigner::new(
|
||||
_signature,
|
||||
credentials.clone(),
|
||||
identity.clone(),
|
||||
Region::new(signing_params.region().to_string()).into(),
|
||||
signing_params.name().to_string().into(),
|
||||
time_source,
|
||||
|
@ -397,11 +399,11 @@ impl Signer for SigV4Signer {
|
|||
|
||||
#[cfg(feature = "event-stream")]
|
||||
mod event_stream {
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_sigv4::event_stream::{sign_empty_message, sign_message};
|
||||
use aws_sigv4::SigningParams;
|
||||
use aws_smithy_async::time::SharedTimeSource;
|
||||
use aws_smithy_eventstream::frame::{Message, SignMessage, SignMessageError};
|
||||
use aws_smithy_runtime_api::client::identity::Identity;
|
||||
use aws_types::region::SigningRegion;
|
||||
use aws_types::SigningName;
|
||||
|
||||
|
@ -409,7 +411,7 @@ mod event_stream {
|
|||
#[derive(Debug)]
|
||||
pub(super) struct SigV4MessageSigner {
|
||||
last_signature: String,
|
||||
credentials: Credentials,
|
||||
identity: Identity,
|
||||
signing_region: SigningRegion,
|
||||
signing_name: SigningName,
|
||||
time: SharedTimeSource,
|
||||
|
@ -418,14 +420,14 @@ mod event_stream {
|
|||
impl SigV4MessageSigner {
|
||||
pub(super) fn new(
|
||||
last_signature: String,
|
||||
credentials: Credentials,
|
||||
identity: Identity,
|
||||
signing_region: SigningRegion,
|
||||
signing_name: SigningName,
|
||||
time: SharedTimeSource,
|
||||
) -> Self {
|
||||
Self {
|
||||
last_signature,
|
||||
credentials,
|
||||
identity,
|
||||
signing_region,
|
||||
signing_name,
|
||||
time,
|
||||
|
@ -433,14 +435,12 @@ mod event_stream {
|
|||
}
|
||||
|
||||
fn signing_params(&self) -> SigningParams<'_, ()> {
|
||||
let mut builder = SigningParams::builder()
|
||||
.access_key(self.credentials.access_key_id())
|
||||
.secret_key(self.credentials.secret_access_key())
|
||||
let builder = SigningParams::builder()
|
||||
.identity(&self.identity)
|
||||
.region(self.signing_region.as_ref())
|
||||
.name(self.signing_name.as_ref())
|
||||
.time(self.time.now())
|
||||
.settings(());
|
||||
builder.set_security_token(self.credentials.session_token());
|
||||
builder.build().unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -467,9 +467,11 @@ mod event_stream {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::auth::sigv4::event_stream::SigV4MessageSigner;
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_smithy_async::time::SharedTimeSource;
|
||||
use aws_smithy_eventstream::frame::{HeaderValue, Message, SignMessage};
|
||||
|
||||
use aws_types::region::Region;
|
||||
use aws_types::region::SigningRegion;
|
||||
use aws_types::SigningName;
|
||||
|
@ -484,7 +486,7 @@ mod event_stream {
|
|||
let region = Region::new("us-east-1");
|
||||
let mut signer = check_send_sync(SigV4MessageSigner::new(
|
||||
"initial-signature".into(),
|
||||
Credentials::for_tests(),
|
||||
Credentials::for_tests_with_session_token().into(),
|
||||
SigningRegion::from(region),
|
||||
SigningName::from_static("transcribe"),
|
||||
SharedTimeSource::new(UNIX_EPOCH + Duration::new(1611160427, 0)),
|
||||
|
@ -534,13 +536,14 @@ mod tests {
|
|||
let mut settings = SigningSettings::default();
|
||||
settings.expires_in = Some(creds_expire_in - Duration::from_secs(10));
|
||||
|
||||
let credentials = Credentials::new(
|
||||
let identity = Credentials::new(
|
||||
"test-access-key",
|
||||
"test-secret-key",
|
||||
Some("test-session-token".into()),
|
||||
Some(now + creds_expire_in),
|
||||
"test",
|
||||
);
|
||||
)
|
||||
.into();
|
||||
let operation_config = SigV4OperationSigningConfig {
|
||||
region: Some(SigningRegion::from_static("test")),
|
||||
service: Some(SigningName::from_static("test")),
|
||||
|
@ -555,13 +558,13 @@ mod tests {
|
|||
payload_override: None,
|
||||
},
|
||||
};
|
||||
SigV4Signer::signing_params(settings, &credentials, &operation_config, now).unwrap();
|
||||
SigV4Signer::signing_params(settings, &identity, &operation_config, now).unwrap();
|
||||
assert!(!logs_contain(EXPIRATION_WARNING));
|
||||
|
||||
let mut settings = SigningSettings::default();
|
||||
settings.expires_in = Some(creds_expire_in + Duration::from_secs(10));
|
||||
|
||||
SigV4Signer::signing_params(settings, &credentials, &operation_config, now).unwrap();
|
||||
SigV4Signer::signing_params(settings, &identity, &operation_config, now).unwrap();
|
||||
assert!(logs_contain(EXPIRATION_WARNING));
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ aws-sigv4 = { path = "../aws-sigv4", features = ["http0-compat"] }
|
|||
aws-smithy-eventstream = { path = "../../../rust-runtime/aws-smithy-eventstream", optional = true }
|
||||
aws-smithy-http = { path = "../../../rust-runtime/aws-smithy-http" }
|
||||
aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" }
|
||||
aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api" }
|
||||
aws-types = { path = "../aws-types" }
|
||||
http = "0.2.2"
|
||||
tracing = "0.1"
|
||||
|
|
|
@ -5,6 +5,7 @@ allowed_external_types = [
|
|||
"aws_smithy_http::*",
|
||||
"aws_types::*",
|
||||
"http::request::Request",
|
||||
"aws_smithy_runtime_api::client::identity::Identity",
|
||||
|
||||
# TODO(https://github.com/awslabs/smithy-rs/issues/1193): Once tooling permits it, only allow the following types in the `event-stream` feature
|
||||
"aws_smithy_eventstream::frame::SignMessage",
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
#![allow(clippy::disallowed_methods)]
|
||||
|
||||
use crate::middleware::Signature;
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_sigv4::event_stream::{sign_empty_message, sign_message};
|
||||
use aws_sigv4::SigningParams;
|
||||
use aws_smithy_eventstream::frame::{Message, SignMessage, SignMessageError};
|
||||
use aws_smithy_http::property_bag::{PropertyBag, SharedPropertyBag};
|
||||
use aws_smithy_runtime_api::client::identity::Identity;
|
||||
use aws_types::region::SigningRegion;
|
||||
use aws_types::SigningName;
|
||||
use std::time::SystemTime;
|
||||
|
@ -21,7 +21,7 @@ use std::time::SystemTime;
|
|||
#[derive(Debug)]
|
||||
pub struct SigV4MessageSigner {
|
||||
last_signature: String,
|
||||
credentials: Credentials,
|
||||
identity: Identity,
|
||||
signing_region: SigningRegion,
|
||||
signing_name: SigningName,
|
||||
time: Option<SystemTime>,
|
||||
|
@ -30,14 +30,14 @@ pub struct SigV4MessageSigner {
|
|||
impl SigV4MessageSigner {
|
||||
pub fn new(
|
||||
last_signature: String,
|
||||
credentials: Credentials,
|
||||
identity: Identity,
|
||||
signing_region: SigningRegion,
|
||||
signing_name: SigningName,
|
||||
time: Option<SystemTime>,
|
||||
) -> Self {
|
||||
Self {
|
||||
last_signature,
|
||||
credentials,
|
||||
identity,
|
||||
signing_region,
|
||||
signing_name,
|
||||
time,
|
||||
|
@ -45,14 +45,12 @@ impl SigV4MessageSigner {
|
|||
}
|
||||
|
||||
fn signing_params(&self) -> SigningParams<()> {
|
||||
let mut builder = SigningParams::builder()
|
||||
.access_key(self.credentials.access_key_id())
|
||||
.secret_key(self.credentials.secret_access_key())
|
||||
let builder = SigningParams::builder()
|
||||
.identity(&self.identity)
|
||||
.region(self.signing_region.as_ref())
|
||||
.name(self.signing_name.as_ref())
|
||||
.time(self.time.unwrap_or_else(SystemTime::now))
|
||||
.settings(());
|
||||
builder.set_security_token(self.credentials.session_token());
|
||||
builder.build().unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +80,7 @@ mod tests {
|
|||
use crate::event_stream::SigV4MessageSigner;
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_smithy_eventstream::frame::{HeaderValue, Message, SignMessage};
|
||||
|
||||
use aws_types::region::Region;
|
||||
use aws_types::region::SigningRegion;
|
||||
use aws_types::SigningName;
|
||||
|
@ -96,7 +95,7 @@ mod tests {
|
|||
let region = Region::new("us-east-1");
|
||||
let mut signer = check_send_sync(SigV4MessageSigner::new(
|
||||
"initial-signature".into(),
|
||||
Credentials::for_tests(),
|
||||
Credentials::for_tests_with_session_token().into(),
|
||||
SigningRegion::from(region),
|
||||
SigningName::from_static("transcribe"),
|
||||
Some(UNIX_EPOCH + Duration::new(1611160427, 0)),
|
||||
|
@ -144,21 +143,19 @@ impl SigV4Signer {
|
|||
fn signing_params(properties: &PropertyBag) -> SigningParams<()> {
|
||||
// Every single one of these values would have been retrieved during the initial request,
|
||||
// so we can safely assume they all exist in the property bag at this point.
|
||||
let credentials = properties.get::<Credentials>().unwrap();
|
||||
let identity = properties.get::<Identity>().unwrap();
|
||||
let region = properties.get::<SigningRegion>().unwrap();
|
||||
let name = properties.get::<SigningName>().unwrap();
|
||||
let time = properties
|
||||
.get::<SystemTime>()
|
||||
.copied()
|
||||
.unwrap_or_else(SystemTime::now);
|
||||
let mut builder = SigningParams::builder()
|
||||
.access_key(credentials.access_key_id())
|
||||
.secret_key(credentials.secret_access_key())
|
||||
let builder = SigningParams::builder()
|
||||
.identity(identity)
|
||||
.region(region.as_ref())
|
||||
.name(name.as_ref())
|
||||
.time(time)
|
||||
.settings(());
|
||||
builder.set_security_token(credentials.session_token());
|
||||
builder.build().unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -208,6 +205,7 @@ mod old_tests {
|
|||
use aws_credential_types::Credentials;
|
||||
use aws_smithy_eventstream::frame::{HeaderValue, Message, SignMessage};
|
||||
use aws_smithy_http::property_bag::PropertyBag;
|
||||
use aws_smithy_runtime_api::client::identity::Identity;
|
||||
use aws_types::region::Region;
|
||||
use aws_types::region::SigningRegion;
|
||||
use aws_types::SigningName;
|
||||
|
@ -219,8 +217,8 @@ mod old_tests {
|
|||
let mut properties = PropertyBag::new();
|
||||
properties.insert(region.clone());
|
||||
properties.insert(UNIX_EPOCH + Duration::new(1611160427, 0));
|
||||
properties.insert::<Identity>(Credentials::for_tests_with_session_token().into());
|
||||
properties.insert(SigningName::from_static("transcribe"));
|
||||
properties.insert(Credentials::for_tests());
|
||||
properties.insert(SigningRegion::from(region));
|
||||
properties.insert(Signature::new("initial-signature".into()));
|
||||
|
||||
|
|
|
@ -22,13 +22,14 @@
|
|||
//! use aws_types::region::{Region, SigningRegion};
|
||||
//! use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
//! use aws_sig_auth::signer::{self, SigningError, OperationSigningConfig, HttpSignatureType, RequestConfig};
|
||||
//! use aws_smithy_runtime_api::client::identity::Identity;
|
||||
//!
|
||||
//! fn generate_rds_iam_token(
|
||||
//! db_hostname: &str,
|
||||
//! region: Region,
|
||||
//! port: u16,
|
||||
//! db_username: &str,
|
||||
//! credentials: &Credentials,
|
||||
//! identity: &Identity,
|
||||
//! timestamp: SystemTime,
|
||||
//! ) -> Result<String, SigningError> {
|
||||
//! let signer = signer::SigV4Signer::new();
|
||||
|
@ -53,7 +54,7 @@
|
|||
//! let _signature = signer.sign(
|
||||
//! &operation_config,
|
||||
//! &request_config,
|
||||
//! &credentials,
|
||||
//! identity,
|
||||
//! &mut request,
|
||||
//! )?;
|
||||
//! let mut uri = request.uri().to_string();
|
||||
|
@ -62,14 +63,14 @@
|
|||
//! Ok(uri)
|
||||
//! }
|
||||
//!
|
||||
//! // You will need to get `credentials` from a credentials provider ahead of time
|
||||
//! # let credentials = Credentials::new("AKIDEXAMPLE", "secret", None, None, "example");
|
||||
//! // You will need to get an `identity` from a credentials provider ahead of time
|
||||
//! # let identity = Credentials::new("AKIDEXAMPLE", "secret", None, None, "example").into();
|
||||
//! let token = generate_rds_iam_token(
|
||||
//! "prod-instance.us-east-1.rds.amazonaws.com",
|
||||
//! Region::from_static("us-east-1"),
|
||||
//! 3306,
|
||||
//! "dbuser",
|
||||
//! &credentials,
|
||||
//! &identity,
|
||||
//! // this value is hard coded to create deterministic signature for tests. Generally,
|
||||
//! // `SystemTime::now()` should be used
|
||||
//! UNIX_EPOCH + Duration::from_secs(1635257380)
|
||||
|
@ -88,6 +89,7 @@
|
|||
//! use aws_types::SigningName;
|
||||
//! use std::error::Error;
|
||||
//! use std::time::SystemTime;
|
||||
//! use aws_smithy_runtime_api::client::identity::Identity;
|
||||
//! async fn sign_request(
|
||||
//! mut request: &mut http::Request<SdkBody>,
|
||||
//! region: Region,
|
||||
|
@ -101,10 +103,11 @@
|
|||
//! name: &SigningName::from_static("execute-api"),
|
||||
//! payload_override: None,
|
||||
//! };
|
||||
//! let identity = credentials_provider.provide_credentials().await?.into();
|
||||
//! signer.sign(
|
||||
//! &OperationSigningConfig::default_config(),
|
||||
//! &request_config,
|
||||
//! &credentials_provider.provide_credentials().await?,
|
||||
//! &identity,
|
||||
//! &mut request,
|
||||
//! )?;
|
||||
//! Ok((()))
|
||||
|
|
|
@ -49,10 +49,10 @@ impl AsRef<str> for Signature {
|
|||
/// a signature.
|
||||
///
|
||||
/// Prior to signing, the following fields MUST be present in the property bag:
|
||||
/// - [`SigningRegion`](SigningRegion): The region used when signing the request, e.g. `us-east-1`
|
||||
/// - [`SigningName`](SigningName): The name of the service to use when signing the request, e.g. `dynamodb`
|
||||
/// - [`Credentials`](Credentials): Credentials to sign with
|
||||
/// - [`OperationSigningConfig`](OperationSigningConfig): Operation specific signing configuration, e.g.
|
||||
/// - [`SigningRegion`]: The region used when signing the request, e.g. `us-east-1`
|
||||
/// - [`SigningName`]: The name of the service to use when signing the request, e.g. `dynamodb`
|
||||
/// - [`Credentials`]: Credentials to sign with
|
||||
/// - [`OperationSigningConfig`]: Operation specific signing configuration, e.g.
|
||||
/// changes to URL encoding behavior, or headers that must be omitted.
|
||||
/// - [`SharedTimeSource`]: The time source to use when signing the request.
|
||||
/// If any of these fields are missing, the middleware will return an error.
|
||||
|
@ -180,10 +180,11 @@ impl MapRequest for SigV4SigningStage {
|
|||
},
|
||||
SigningRequirements::Required => signing_config(config)?,
|
||||
};
|
||||
let identity = creds.into();
|
||||
|
||||
let signature = self
|
||||
.signer
|
||||
.sign(operation_config, &request_config, &creds, &mut req)
|
||||
.sign(operation_config, &request_config, &identity, &mut req)
|
||||
.map_err(SigningStageErrorKind::SigningFailure)?;
|
||||
|
||||
// If this is an event stream operation, set up the event stream signer
|
||||
|
@ -193,7 +194,7 @@ impl MapRequest for SigV4SigningStage {
|
|||
signer_sender
|
||||
.send(Box::new(EventStreamSigV4Signer::new(
|
||||
signature.as_ref().into(),
|
||||
creds,
|
||||
identity,
|
||||
request_config.region.clone(),
|
||||
request_config.name.clone(),
|
||||
time_override,
|
||||
|
@ -220,6 +221,7 @@ mod test {
|
|||
use aws_credential_types::Credentials;
|
||||
use aws_endpoint::AwsAuthStage;
|
||||
use aws_smithy_async::time::SharedTimeSource;
|
||||
|
||||
use aws_types::region::{Region, SigningRegion};
|
||||
use aws_types::SigningName;
|
||||
|
||||
|
@ -241,7 +243,7 @@ mod test {
|
|||
properties.insert(UNIX_EPOCH + Duration::new(1611160427, 0));
|
||||
properties.insert(SigningName::from_static("kinesis"));
|
||||
properties.insert(OperationSigningConfig::default_config());
|
||||
properties.insert(Credentials::for_tests());
|
||||
properties.insert(Credentials::for_tests_with_session_token());
|
||||
properties.insert(SigningRegion::from(region));
|
||||
Result::<_, Infallible>::Ok(req)
|
||||
})
|
||||
|
@ -275,7 +277,7 @@ mod test {
|
|||
));
|
||||
properties.insert(SigningName::from_static("kinesis"));
|
||||
properties.insert(OperationSigningConfig::default_config());
|
||||
properties.insert(Credentials::for_tests());
|
||||
properties.insert(Credentials::for_tests_with_session_token());
|
||||
properties.insert(SigningRegion::from(region.clone()));
|
||||
properties.insert(deferred_signer_sender);
|
||||
Result::<_, Infallible>::Ok(req)
|
||||
|
@ -288,7 +290,7 @@ mod test {
|
|||
let mut signer_for_comparison = EventStreamSigV4Signer::new(
|
||||
// This is the expected SigV4 signature for the HTTP request above
|
||||
"abac477b4afabf5651079e7b9a0aa6a1a3e356a7418a81d974cdae9d4c8e5441".into(),
|
||||
Credentials::for_tests(),
|
||||
Credentials::for_tests_with_session_token().into(),
|
||||
SigningRegion::from(region),
|
||||
SigningName::from_static("kinesis"),
|
||||
Some(UNIX_EPOCH + Duration::new(1611160427, 0)),
|
||||
|
@ -337,7 +339,8 @@ mod test {
|
|||
.apply(req.try_clone().expect("can clone"))
|
||||
.expect_err("no cred provider"),
|
||||
);
|
||||
req.properties_mut().insert(Credentials::for_tests());
|
||||
req.properties_mut()
|
||||
.insert(Credentials::for_tests_with_session_token());
|
||||
let req = signer.apply(req).expect("signing succeeded");
|
||||
// make sure we got the correct error types in any order
|
||||
assert!(errs.iter().all(|el| matches!(
|
||||
|
|
|
@ -3,20 +3,19 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use aws_credential_types::Credentials;
|
||||
use crate::middleware::Signature;
|
||||
use aws_sigv4::http_request::{
|
||||
sign, PayloadChecksumKind, PercentEncodingMode, SessionTokenMode, SignableRequest,
|
||||
SignatureLocation, SigningParams, SigningSettings, UriPathNormalizationMode,
|
||||
};
|
||||
use aws_smithy_http::body::SdkBody;
|
||||
use aws_smithy_runtime_api::client::identity::Identity;
|
||||
use aws_types::region::SigningRegion;
|
||||
use aws_types::SigningName;
|
||||
use std::fmt;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use crate::middleware::Signature;
|
||||
pub use aws_sigv4::http_request::SignableBody;
|
||||
|
||||
pub type SigningError = aws_sigv4::http_request::SigningError;
|
||||
|
||||
const EXPIRATION_WARNING: &str = "Presigned request will expire before the given \
|
||||
|
@ -159,11 +158,11 @@ impl SigV4Signer {
|
|||
|
||||
fn signing_params<'a>(
|
||||
settings: SigningSettings,
|
||||
credentials: &'a Credentials,
|
||||
identity: &'a Identity,
|
||||
request_config: &'a RequestConfig<'a>,
|
||||
) -> SigningParams<'a> {
|
||||
if let Some(expires_in) = settings.expires_in {
|
||||
if let Some(creds_expires_time) = credentials.expiry() {
|
||||
if let Some(creds_expires_time) = identity.expiration().cloned() {
|
||||
let presigned_expires_time = request_config.request_ts + expires_in;
|
||||
if presigned_expires_time > creds_expires_time {
|
||||
tracing::warn!(EXPIRATION_WARNING);
|
||||
|
@ -171,14 +170,12 @@ impl SigV4Signer {
|
|||
}
|
||||
}
|
||||
|
||||
let mut builder = SigningParams::builder()
|
||||
.access_key(credentials.access_key_id())
|
||||
.secret_key(credentials.secret_access_key())
|
||||
let builder = SigningParams::builder()
|
||||
.identity(identity)
|
||||
.region(request_config.region.as_ref())
|
||||
.name(request_config.name.as_ref())
|
||||
.time(request_config.request_ts)
|
||||
.settings(settings);
|
||||
builder.set_security_token(credentials.session_token());
|
||||
builder.build().expect("all required fields set")
|
||||
}
|
||||
|
||||
|
@ -190,11 +187,11 @@ impl SigV4Signer {
|
|||
&self,
|
||||
operation_config: &OperationSigningConfig,
|
||||
request_config: &RequestConfig<'_>,
|
||||
credentials: &Credentials,
|
||||
identity: &Identity,
|
||||
request: &mut http::Request<SdkBody>,
|
||||
) -> Result<Signature, SigningError> {
|
||||
let settings = Self::settings(operation_config);
|
||||
let signing_params = Self::signing_params(settings, credentials, request_config);
|
||||
let signing_params = Self::signing_params(settings, identity, request_config);
|
||||
|
||||
let (signing_instructions, signature) = {
|
||||
// A body that is already in memory can be signed directly. A body that is not in memory
|
||||
|
@ -239,6 +236,7 @@ mod tests {
|
|||
use super::{RequestConfig, SigV4Signer, EXPIRATION_WARNING};
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_sigv4::http_request::SigningSettings;
|
||||
|
||||
use aws_types::region::SigningRegion;
|
||||
use aws_types::SigningName;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
@ -253,26 +251,27 @@ mod tests {
|
|||
let mut settings = SigningSettings::default();
|
||||
settings.expires_in = Some(creds_expire_in - Duration::from_secs(10));
|
||||
|
||||
let credentials = Credentials::new(
|
||||
let identity = Credentials::new(
|
||||
"test-access-key",
|
||||
"test-secret-key",
|
||||
Some("test-session-token".into()),
|
||||
Some(now + creds_expire_in),
|
||||
"test",
|
||||
);
|
||||
)
|
||||
.into();
|
||||
let request_config = RequestConfig {
|
||||
request_ts: now,
|
||||
region: &SigningRegion::from_static("test"),
|
||||
name: &SigningName::from_static("test"),
|
||||
payload_override: None,
|
||||
};
|
||||
SigV4Signer::signing_params(settings, &credentials, &request_config);
|
||||
SigV4Signer::signing_params(settings, &identity, &request_config);
|
||||
assert!(!logs_contain(EXPIRATION_WARNING));
|
||||
|
||||
let mut settings = SigningSettings::default();
|
||||
settings.expires_in = Some(creds_expire_in + Duration::from_secs(10));
|
||||
|
||||
SigV4Signer::signing_params(settings, &credentials, &request_config);
|
||||
SigV4Signer::signing_params(settings, &identity, &request_config);
|
||||
assert!(logs_contain(EXPIRATION_WARNING));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ default = ["sign-http"]
|
|||
[dependencies]
|
||||
aws-smithy-eventstream = { path = "../../../rust-runtime/aws-smithy-eventstream", optional = true }
|
||||
aws-smithy-http = { path = "../../../rust-runtime/aws-smithy-http" }
|
||||
aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["client"] }
|
||||
aws-credential-types = { path = "../aws-credential-types" }
|
||||
bytes = { version = "1", optional = true }
|
||||
form_urlencoded = { version = "1.0", optional = true }
|
||||
hex = "0.4"
|
||||
|
@ -30,6 +32,8 @@ hmac = "0.12"
|
|||
sha2 = "0.10"
|
||||
|
||||
[dev-dependencies]
|
||||
aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["client", "test-util"] }
|
||||
aws-credential-types = { path = "../aws-credential-types", features = ["test-util"] }
|
||||
criterion = "0.4"
|
||||
bytes = "1"
|
||||
httparse = "1.5"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
POST /test/@connections/JBDvjfGEIAMCERw%3D HTTP/1.1
|
||||
X-amz-date:20150830T123600Z
|
||||
Authorization:AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=6f871eb157f326fa5f7439eb88ca200048635950ce7d6037deda56f0c95d4364
|
||||
Authorization:AWS4-HMAC-SHA256 Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=57d157672191bac40bae387e48bbe14b15303c001fdbb01f4abf295dccb09705
|
||||
Host:tj9n5r0m12.execute-api.us-east-1.amazonaws.com
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
GET /?Param2=value2&Param1=value1&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=35&X-Amz-SignedHeaders=host&X-Amz-Signature=f25aea20f8c722ece3b363fc5d60cc91add973f9b64c42ba36fa28d57afe9019 HTTP/1.1
|
||||
GET /?Param2=value2&Param1=value1&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ANOTREAL%2F20150830%2Fus-east-1%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=35&X-Amz-SignedHeaders=host&X-Amz-Signature=ecce208e4b4f7d7e3a4cc22ced6acc2ad1d170ee8ba87d7165f6fa4b9aff09ab HTTP/1.1
|
||||
Host:example.amazonaws.com
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
GET /?Param2=value2&Param1=value1 HTTP/1.1
|
||||
Host:example.amazonaws.com
|
||||
X-Amz-Date:20150830T123600Z
|
||||
Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=b97d918cfa904a5beff61c982a1b6f458b799221646efd99d3219ec94cdf2500
|
||||
Authorization: AWS4-HMAC-SHA256 Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5557820e7380d585310524bd93d51a08d7757fb5efd7344ee12088f2b0860947
|
||||
|
|
|
@ -3,4 +3,5 @@ allowed_external_types = [
|
|||
"http::request::Request",
|
||||
# TODO(https://github.com/awslabs/smithy-rs/issues/1193): Once tooling permits it, only allow the following types in the `event-stream` feature
|
||||
"aws_smithy_eventstream::frame::Message",
|
||||
"aws_smithy_runtime_api::client::identity::Identity"
|
||||
]
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
//! use aws_sigv4::event_stream::{sign_message, SigningParams};
|
||||
//! use aws_smithy_eventstream::frame::{Header, HeaderValue, Message};
|
||||
//! use std::time::SystemTime;
|
||||
//! use aws_credential_types::Credentials;
|
||||
//! use aws_smithy_runtime_api::client::identity::Identity;
|
||||
//!
|
||||
//! // The `last_signature` argument is the previous message's signature, or
|
||||
//! // the signature of the initial HTTP request if a message hasn't been signed yet.
|
||||
|
@ -21,9 +23,15 @@
|
|||
//! HeaderValue::String("value".into()),
|
||||
//! ));
|
||||
//!
|
||||
//! let identity = Credentials::new(
|
||||
//! "AKIDEXAMPLE",
|
||||
//! "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
//! None,
|
||||
//! None,
|
||||
//! "hardcoded-credentials"
|
||||
//! ).into();
|
||||
//! let params = SigningParams::builder()
|
||||
//! .access_key("example access key")
|
||||
//! .secret_key("example secret key")
|
||||
//! .identity(&identity)
|
||||
//! .region("us-east-1")
|
||||
//! .name("exampleservice")
|
||||
//! .time(SystemTime::now())
|
||||
|
@ -113,11 +121,13 @@ fn sign_payload<'a>(
|
|||
last_signature: &'a str,
|
||||
params: &'a SigningParams<'a>,
|
||||
) -> SigningOutput<Message> {
|
||||
let creds = params.credentials().expect("AWS credentials are required");
|
||||
// Truncate the sub-seconds up front since the timestamp written to the signed message header
|
||||
// needs to exactly match the string formatted timestamp, which doesn't include sub-seconds.
|
||||
let time = truncate_subsecs(params.time);
|
||||
|
||||
let signing_key = generate_signing_key(params.secret_key, time, params.region, params.name);
|
||||
let signing_key =
|
||||
generate_signing_key(creds.secret_access_key(), time, params.region, params.name);
|
||||
let string_to_sign = calculate_string_to_sign(
|
||||
message_payload.as_ref().map(|v| &v[..]).unwrap_or(&[]),
|
||||
last_signature,
|
||||
|
@ -141,7 +151,11 @@ fn sign_payload<'a>(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::event_stream::{calculate_string_to_sign, sign_message};
|
||||
use crate::sign::sha256_hex_string;
|
||||
use crate::SigningParams;
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_smithy_eventstream::frame::{Header, HeaderValue, Message};
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
#[test]
|
||||
|
@ -154,9 +168,7 @@ mod tests {
|
|||
message_to_sign.write_to(&mut message_payload).unwrap();
|
||||
|
||||
let params = SigningParams {
|
||||
access_key: "fake access key",
|
||||
secret_key: "fake secret key",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "testservice",
|
||||
time: (UNIX_EPOCH + Duration::new(123_456_789_u64, 1234u32)),
|
||||
|
@ -192,9 +204,7 @@ mod tests {
|
|||
HeaderValue::String("value".into()),
|
||||
));
|
||||
let params = SigningParams {
|
||||
access_key: "fake access key",
|
||||
secret_key: "fake secret key",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "testservice",
|
||||
time: (UNIX_EPOCH + Duration::new(123_456_789_u64, 1234u32)),
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
//! **Note**: This requires `http0-compat` to be enabled.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use aws_credential_types::Credentials;
|
||||
//! use aws_smithy_runtime_api::client::identity::Identity;
|
||||
//! # use aws_sigv4::http_request::SignableBody;
|
||||
//! #[cfg(feature = "http0-compat")]
|
||||
//! fn test() -> Result<(), aws_sigv4::http_request::SigningError> {
|
||||
|
@ -18,10 +20,16 @@
|
|||
//! use std::time::SystemTime;
|
||||
//!
|
||||
//! // Set up information and settings for the signing
|
||||
//! let identity = Credentials::new(
|
||||
//! "AKIDEXAMPLE",
|
||||
//! "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
//! None,
|
||||
//! None,
|
||||
//! "hardcoded-credentials"
|
||||
//! ).into();
|
||||
//! let signing_settings = SigningSettings::default();
|
||||
//! let signing_params = SigningParams::builder()
|
||||
//! .access_key("example access key")
|
||||
//! .secret_key("example secret key")
|
||||
//! .identity(&identity)
|
||||
//! .region("us-east-1")
|
||||
//! .name("exampleservice")
|
||||
//! .time(SystemTime::now())
|
|
@ -20,7 +20,6 @@ use std::borrow::Cow;
|
|||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
use std::str::FromStr;
|
||||
use std::time::SystemTime;
|
||||
|
||||
|
@ -131,6 +130,9 @@ impl<'a> CanonicalRequest<'a> {
|
|||
req: &'b SignableRequest<'b>,
|
||||
params: &'b SigningParams<'b>,
|
||||
) -> Result<CanonicalRequest<'b>, CanonicalRequestError> {
|
||||
let creds = params
|
||||
.credentials()
|
||||
.ok_or_else(CanonicalRequestError::unsupported_credential_type)?;
|
||||
// Path encoding: if specified, re-encode % as %25
|
||||
// Set method and path into CanonicalRequest
|
||||
let path = req.uri().path();
|
||||
|
@ -151,7 +153,7 @@ impl<'a> CanonicalRequest<'a> {
|
|||
let signed_headers = SignedHeaders::new(signed_headers);
|
||||
|
||||
let security_token = match params.settings.session_token_mode {
|
||||
SessionTokenMode::Include => params.security_token,
|
||||
SessionTokenMode::Include => creds.session_token(),
|
||||
SessionTokenMode::Exclude => None,
|
||||
};
|
||||
|
||||
|
@ -167,7 +169,7 @@ impl<'a> CanonicalRequest<'a> {
|
|||
content_sha256: payload_hash,
|
||||
credential: format!(
|
||||
"{}/{}/{}/{}/aws4_request",
|
||||
params.access_key,
|
||||
creds.access_key_id(),
|
||||
format_date(params.time),
|
||||
params.region,
|
||||
params.name,
|
||||
|
@ -200,6 +202,9 @@ impl<'a> CanonicalRequest<'a> {
|
|||
payload_hash: &str,
|
||||
date_time: &str,
|
||||
) -> Result<(Vec<CanonicalHeaderName>, HeaderMap), CanonicalRequestError> {
|
||||
let creds = params
|
||||
.credentials()
|
||||
.ok_or_else(CanonicalRequestError::unsupported_credential_type)?;
|
||||
// Header computation:
|
||||
// The canonical request will include headers not present in the input. We need to clone and
|
||||
// normalize the headers from the original request and add:
|
||||
|
@ -222,7 +227,7 @@ impl<'a> CanonicalRequest<'a> {
|
|||
if params.settings.signature_location == SignatureLocation::Headers {
|
||||
Self::insert_date_header(&mut canonical_headers, date_time);
|
||||
|
||||
if let Some(security_token) = params.security_token {
|
||||
if let Some(security_token) = creds.session_token() {
|
||||
let mut sec_header = HeaderValue::from_str(security_token)?;
|
||||
sec_header.set_sensitive(true);
|
||||
canonical_headers.insert(header::X_AMZ_SECURITY_TOKEN, sec_header);
|
||||
|
@ -517,7 +522,7 @@ impl<'a> StringToSign<'a> {
|
|||
}
|
||||
|
||||
impl<'a> fmt::Display for StringToSign<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}\n{}\n{}\n{}",
|
||||
|
@ -537,22 +542,21 @@ mod tests {
|
|||
};
|
||||
use crate::http_request::test::{test_canonical_request, test_request, test_sts};
|
||||
use crate::http_request::{
|
||||
PayloadChecksumKind, SessionTokenMode, SignableBody, SignableRequest, SigningSettings,
|
||||
PayloadChecksumKind, SessionTokenMode, SignableBody, SignableRequest, SignatureLocation,
|
||||
SigningParams, SigningSettings,
|
||||
};
|
||||
use crate::http_request::{SignatureLocation, SigningParams};
|
||||
use crate::sign::sha256_hex_string;
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_smithy_http::query_writer::QueryWriter;
|
||||
use aws_smithy_runtime_api::client::identity::Identity;
|
||||
use http::{HeaderValue, Uri};
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use proptest::{prelude::*, proptest};
|
||||
use std::time::Duration;
|
||||
|
||||
fn signing_params(settings: SigningSettings) -> SigningParams<'static> {
|
||||
fn signing_params(identity: &Identity, settings: SigningSettings) -> SigningParams<'_> {
|
||||
SigningParams {
|
||||
access_key: "test-access-key",
|
||||
secret_key: "test-secret-key",
|
||||
security_token: None,
|
||||
identity,
|
||||
region: "test-region",
|
||||
name: "testservicename",
|
||||
time: parse_date_time("20210511T154045Z").unwrap(),
|
||||
|
@ -576,7 +580,8 @@ mod tests {
|
|||
payload_checksum_kind: PayloadChecksumKind::XAmzSha256,
|
||||
..Default::default()
|
||||
};
|
||||
let signing_params = signing_params(settings);
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, settings);
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
|
@ -597,7 +602,8 @@ mod tests {
|
|||
payload_checksum_kind: PayloadChecksumKind::XAmzSha256,
|
||||
..Default::default()
|
||||
};
|
||||
let mut signing_params = signing_params(settings);
|
||||
let identity = Credentials::for_tests().into();
|
||||
let mut signing_params = signing_params(&identity, settings);
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
assert_eq!(
|
||||
creq.values.content_sha256(),
|
||||
|
@ -624,7 +630,8 @@ mod tests {
|
|||
payload_checksum_kind: PayloadChecksumKind::XAmzSha256,
|
||||
..Default::default()
|
||||
};
|
||||
let signing_params = signing_params(settings);
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, settings);
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
assert_eq!(creq.values.content_sha256(), "UNSIGNED-PAYLOAD");
|
||||
assert!(creq.to_string().ends_with("UNSIGNED-PAYLOAD"));
|
||||
|
@ -640,7 +647,8 @@ mod tests {
|
|||
payload_checksum_kind: PayloadChecksumKind::XAmzSha256,
|
||||
..Default::default()
|
||||
};
|
||||
let signing_params = signing_params(settings);
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, settings);
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
assert_eq!(creq.values.content_sha256(), payload_hash);
|
||||
assert!(creq.to_string().ends_with(payload_hash));
|
||||
|
@ -680,7 +688,8 @@ mod tests {
|
|||
fn test_double_url_encode_path() {
|
||||
let req = test_request("double-encode-path");
|
||||
let req = SignableRequest::from(&req);
|
||||
let signing_params = signing_params(SigningSettings::default());
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, SigningSettings::default());
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
|
||||
let expected = test_canonical_request("double-encode-path");
|
||||
|
@ -692,7 +701,8 @@ mod tests {
|
|||
fn test_double_url_encode() {
|
||||
let req = test_request("double-url-encode");
|
||||
let req = SignableRequest::from(&req);
|
||||
let signing_params = signing_params(SigningSettings::default());
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, SigningSettings::default());
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
|
||||
let expected = test_canonical_request("double-url-encode");
|
||||
|
@ -705,7 +715,8 @@ mod tests {
|
|||
let req = http::Request::builder()
|
||||
.uri("https://s3.us-east-1.amazonaws.com/my-bucket?list-type=2&prefix=~objprefix&single&k=&unreserved=-_.~").body("").unwrap().into();
|
||||
let req = SignableRequest::from(&req);
|
||||
let signing_params = signing_params(SigningSettings::default());
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, SigningSettings::default());
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
assert_eq!(
|
||||
Some("k=&list-type=2&prefix=~objprefix&single=&unreserved=-_.~"),
|
||||
|
@ -728,7 +739,8 @@ mod tests {
|
|||
.unwrap()
|
||||
.into();
|
||||
let req = SignableRequest::from(&req);
|
||||
let signing_params = signing_params(SigningSettings::default());
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, SigningSettings::default());
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
|
||||
let expected = "list-type=2&prefix=%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~";
|
||||
|
@ -744,8 +756,8 @@ mod tests {
|
|||
session_token_mode: SessionTokenMode::Include,
|
||||
..Default::default()
|
||||
};
|
||||
let mut signing_params = signing_params(settings);
|
||||
signing_params.security_token = Some("notarealsessiontoken");
|
||||
let identity = Credentials::for_tests_with_session_token().into();
|
||||
let mut signing_params = signing_params(&identity, settings);
|
||||
|
||||
let creq = CanonicalRequest::from(&req, &signing_params).unwrap();
|
||||
assert_eq!(
|
||||
|
@ -787,7 +799,8 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let signing_params = signing_params(settings);
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, settings);
|
||||
let canonical = CanonicalRequest::from(&request, &signing_params).unwrap();
|
||||
|
||||
let values = canonical.values.as_headers().unwrap();
|
||||
|
@ -819,7 +832,8 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let signing_params = signing_params(settings);
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, settings);
|
||||
let canonical = CanonicalRequest::from(&request, &signing_params).unwrap();
|
||||
|
||||
let values = canonical.values.into_query_params().unwrap();
|
||||
|
@ -857,7 +871,8 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let signing_params = signing_params(settings);
|
||||
let identity = Credentials::for_tests().into();
|
||||
let signing_params = signing_params(&identity, settings);
|
||||
let canonical = CanonicalRequest::from(&request, &signing_params).unwrap();
|
||||
|
||||
let values = canonical.values.into_query_params().unwrap();
|
||||
|
|
|
@ -12,6 +12,7 @@ use std::str::Utf8Error;
|
|||
#[derive(Debug)]
|
||||
enum SigningErrorKind {
|
||||
FailedToCreateCanonicalRequest { source: CanonicalRequestError },
|
||||
UnsupportedIdentityType,
|
||||
}
|
||||
|
||||
/// Error signing request
|
||||
|
@ -20,12 +21,23 @@ pub struct SigningError {
|
|||
kind: SigningErrorKind,
|
||||
}
|
||||
|
||||
impl SigningError {
|
||||
pub(crate) fn unsupported_identity_type() -> Self {
|
||||
Self {
|
||||
kind: SigningErrorKind::UnsupportedIdentityType,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SigningError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind {
|
||||
SigningErrorKind::FailedToCreateCanonicalRequest { .. } => {
|
||||
write!(f, "failed to create canonical request")
|
||||
}
|
||||
SigningErrorKind::UnsupportedIdentityType => {
|
||||
write!(f, "only 'AWS credentials' are supported for signing")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +46,7 @@ impl Error for SigningError {
|
|||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match &self.kind {
|
||||
SigningErrorKind::FailedToCreateCanonicalRequest { source } => Some(source),
|
||||
SigningErrorKind::UnsupportedIdentityType => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +65,7 @@ enum CanonicalRequestErrorKind {
|
|||
InvalidHeaderValue { source: InvalidHeaderValue },
|
||||
InvalidUtf8InHeaderValue { source: Utf8Error },
|
||||
InvalidUri { source: InvalidUri },
|
||||
UnsupportedIdentityType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -67,6 +81,9 @@ impl fmt::Display for CanonicalRequestError {
|
|||
InvalidHeaderValue { .. } => write!(f, "invalid header value"),
|
||||
InvalidUtf8InHeaderValue { .. } => write!(f, "invalid UTF-8 in header value"),
|
||||
InvalidUri { .. } => write!(f, "the uri was invalid"),
|
||||
UnsupportedIdentityType => {
|
||||
write!(f, "only AWS credentials are supported for signing")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +96,7 @@ impl Error for CanonicalRequestError {
|
|||
InvalidHeaderValue { source } => Some(source),
|
||||
InvalidUtf8InHeaderValue { source } => Some(source),
|
||||
InvalidUri { source } => Some(source),
|
||||
UnsupportedIdentityType => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +107,12 @@ impl CanonicalRequestError {
|
|||
kind: CanonicalRequestErrorKind::InvalidUtf8InHeaderValue { source },
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unsupported_credential_type() -> Self {
|
||||
Self {
|
||||
kind: CanonicalRequestErrorKind::UnsupportedIdentityType,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidHeaderName> for CanonicalRequestError {
|
||||
|
|
|
@ -212,13 +212,20 @@ fn calculate_signing_params<'a>(
|
|||
request: &'a SignableRequest<'a>,
|
||||
params: &'a SigningParams<'a>,
|
||||
) -> Result<(CalculatedParams, String), SigningError> {
|
||||
let creds = params
|
||||
.credentials()
|
||||
.ok_or_else(SigningError::unsupported_identity_type)?;
|
||||
let creq = CanonicalRequest::from(request, params)?;
|
||||
|
||||
let encoded_creq = &sha256_hex_string(creq.to_string().as_bytes());
|
||||
let string_to_sign =
|
||||
StringToSign::new(params.time, params.region, params.name, encoded_creq).to_string();
|
||||
let signing_key =
|
||||
generate_signing_key(params.secret_key, params.time, params.region, params.name);
|
||||
let signing_key = generate_signing_key(
|
||||
creds.secret_access_key(),
|
||||
params.time,
|
||||
params.region,
|
||||
params.name,
|
||||
);
|
||||
let signature = calculate_signature(signing_key, string_to_sign.as_bytes());
|
||||
tracing::trace!(canonical_request = %creq, string_to_sign = %string_to_sign, "calculated signing parameters");
|
||||
|
||||
|
@ -235,7 +242,7 @@ fn calculate_signing_params<'a>(
|
|||
(param::X_AMZ_SIGNATURE, Cow::Owned(signature.clone())),
|
||||
];
|
||||
|
||||
if let Some(security_token) = params.security_token {
|
||||
if let Some(security_token) = creds.session_token() {
|
||||
signing_params.push((
|
||||
param::X_AMZ_SECURITY_TOKEN,
|
||||
Cow::Owned(security_token.to_string()),
|
||||
|
@ -255,6 +262,9 @@ fn calculate_signing_headers<'a>(
|
|||
request: &'a SignableRequest<'a>,
|
||||
params: &'a SigningParams<'a>,
|
||||
) -> Result<SigningOutput<Vec<Header>>, SigningError> {
|
||||
let creds = params
|
||||
.credentials()
|
||||
.ok_or_else(SigningError::unsupported_identity_type)?;
|
||||
// Step 1: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-create-canonical-request.html.
|
||||
let creq = CanonicalRequest::from(request, params)?;
|
||||
tracing::trace!(canonical_request = %creq);
|
||||
|
@ -264,8 +274,12 @@ fn calculate_signing_headers<'a>(
|
|||
let sts = StringToSign::new(params.time, params.region, params.name, encoded_creq);
|
||||
|
||||
// Step 3: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-calculate-signature.html
|
||||
let signing_key =
|
||||
generate_signing_key(params.secret_key, params.time, params.region, params.name);
|
||||
let signing_key = generate_signing_key(
|
||||
creds.secret_access_key(),
|
||||
params.time,
|
||||
params.region,
|
||||
params.name,
|
||||
);
|
||||
let signature = calculate_signature(signing_key, sts.to_string().as_bytes());
|
||||
|
||||
// Step 4: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-add-signature-to-request.html
|
||||
|
@ -274,8 +288,7 @@ fn calculate_signing_headers<'a>(
|
|||
add_header(&mut headers, header::X_AMZ_DATE, &values.date_time, false);
|
||||
headers.push(Header {
|
||||
key: "authorization",
|
||||
value: build_authorization_header(params.access_key, &creq, sts, &signature),
|
||||
|
||||
value: build_authorization_header(creds.access_key_id(), &creq, sts, &signature),
|
||||
sensitive: false,
|
||||
});
|
||||
if params.settings.payload_checksum_kind == PayloadChecksumKind::XAmzSha256 {
|
||||
|
@ -287,7 +300,7 @@ fn calculate_signing_headers<'a>(
|
|||
);
|
||||
}
|
||||
|
||||
if let Some(security_token) = params.security_token {
|
||||
if let Some(security_token) = creds.session_token() {
|
||||
add_header(
|
||||
&mut headers,
|
||||
header::X_AMZ_SECURITY_TOKEN,
|
||||
|
@ -327,7 +340,6 @@ fn build_authorization_header(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::sign;
|
||||
use crate::date_time::test_parsers::parse_date_time;
|
||||
use crate::http_request::sign::SignableRequest;
|
||||
use crate::http_request::test::{
|
||||
|
@ -336,6 +348,7 @@ mod tests {
|
|||
use crate::http_request::{
|
||||
SessionTokenMode, SignableBody, SignatureLocation, SigningParams, SigningSettings,
|
||||
};
|
||||
use aws_credential_types::Credentials;
|
||||
use http::{HeaderValue, Request};
|
||||
use pretty_assertions::assert_eq;
|
||||
use proptest::proptest;
|
||||
|
@ -366,9 +379,7 @@ mod tests {
|
|||
fn test_sign_vanilla_with_headers() {
|
||||
let settings = SigningSettings::default();
|
||||
let params = SigningParams {
|
||||
access_key: "AKIDEXAMPLE",
|
||||
secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "service",
|
||||
time: parse_date_time("20150830T123600Z").unwrap(),
|
||||
|
@ -377,9 +388,9 @@ mod tests {
|
|||
|
||||
let original = test_request("get-vanilla-query-order-key-case");
|
||||
let signable = SignableRequest::from(&original);
|
||||
let out = sign(signable, ¶ms).unwrap();
|
||||
let out = crate::http_request::sign(signable, ¶ms).unwrap();
|
||||
assert_eq!(
|
||||
"b97d918cfa904a5beff61c982a1b6f458b799221646efd99d3219ec94cdf2500",
|
||||
"5557820e7380d585310524bd93d51a08d7757fb5efd7344ee12088f2b0860947",
|
||||
out.signature
|
||||
);
|
||||
|
||||
|
@ -395,9 +406,7 @@ mod tests {
|
|||
let test = "double-encode-path";
|
||||
let settings = SigningSettings::default();
|
||||
let params = SigningParams {
|
||||
access_key: "AKIDEXAMPLE",
|
||||
secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "service",
|
||||
time: parse_date_time("20150830T123600Z").unwrap(),
|
||||
|
@ -406,9 +415,9 @@ mod tests {
|
|||
|
||||
let original = test_request(test);
|
||||
let signable = SignableRequest::from(&original);
|
||||
let out = sign(signable, ¶ms).unwrap();
|
||||
let out = crate::http_request::sign(signable, ¶ms).unwrap();
|
||||
assert_eq!(
|
||||
"6f871eb157f326fa5f7439eb88ca200048635950ce7d6037deda56f0c95d4364",
|
||||
"57d157672191bac40bae387e48bbe14b15303c001fdbb01f4abf295dccb09705",
|
||||
out.signature
|
||||
);
|
||||
|
||||
|
@ -427,9 +436,7 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
let params = SigningParams {
|
||||
access_key: "AKIDEXAMPLE",
|
||||
secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "service",
|
||||
time: parse_date_time("20150830T123600Z").unwrap(),
|
||||
|
@ -438,9 +445,9 @@ mod tests {
|
|||
|
||||
let original = test_request("get-vanilla-query-order-key-case");
|
||||
let signable = SignableRequest::from(&original);
|
||||
let out = sign(signable, ¶ms).unwrap();
|
||||
let out = crate::http_request::sign(signable, ¶ms).unwrap();
|
||||
assert_eq!(
|
||||
"f25aea20f8c722ece3b363fc5d60cc91add973f9b64c42ba36fa28d57afe9019",
|
||||
"ecce208e4b4f7d7e3a4cc22ced6acc2ad1d170ee8ba87d7165f6fa4b9aff09ab",
|
||||
out.signature
|
||||
);
|
||||
|
||||
|
@ -455,9 +462,7 @@ mod tests {
|
|||
fn test_sign_headers_utf8() {
|
||||
let settings = SigningSettings::default();
|
||||
let params = SigningParams {
|
||||
access_key: "AKIDEXAMPLE",
|
||||
secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "service",
|
||||
time: parse_date_time("20150830T123600Z").unwrap(),
|
||||
|
@ -471,9 +476,9 @@ mod tests {
|
|||
.unwrap()
|
||||
.into();
|
||||
let signable = SignableRequest::from(&original);
|
||||
let out = sign(signable, ¶ms).unwrap();
|
||||
let out = crate::http_request::sign(signable, ¶ms).unwrap();
|
||||
assert_eq!(
|
||||
"4596b207a7fc6bdf18725369bc0cd7022cf20efbd2c19730549f42d1a403648e",
|
||||
"55e16b31f9bde5fd04f9d3b780dd2b5e5f11a5219001f91a8ca9ec83eaf1618f",
|
||||
out.signature
|
||||
);
|
||||
|
||||
|
@ -491,9 +496,9 @@ mod tests {
|
|||
"authorization",
|
||||
HeaderValue::from_str(
|
||||
"AWS4-HMAC-SHA256 \
|
||||
Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, \
|
||||
Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, \
|
||||
SignedHeaders=host;some-header;x-amz-date, \
|
||||
Signature=4596b207a7fc6bdf18725369bc0cd7022cf20efbd2c19730549f42d1a403648e",
|
||||
Signature=55e16b31f9bde5fd04f9d3b780dd2b5e5f11a5219001f91a8ca9ec83eaf1618f",
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
|
@ -509,9 +514,7 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
let mut params = SigningParams {
|
||||
access_key: "AKIDEXAMPLE",
|
||||
secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "service",
|
||||
time: parse_date_time("20150830T123600Z").unwrap(),
|
||||
|
@ -523,13 +526,15 @@ mod tests {
|
|||
.body("")
|
||||
.unwrap()
|
||||
.into();
|
||||
let out_without_session_token = sign(SignableRequest::from(&original), ¶ms).unwrap();
|
||||
params.security_token = Some("notarealsessiontoken");
|
||||
let out_without_session_token =
|
||||
crate::http_request::sign(SignableRequest::from(&original), ¶ms).unwrap();
|
||||
let identity = Credentials::for_tests_with_session_token().into();
|
||||
params.identity = &identity;
|
||||
|
||||
let out_with_session_token_but_excluded =
|
||||
sign(SignableRequest::from(&original), ¶ms).unwrap();
|
||||
crate::http_request::sign(SignableRequest::from(&original), ¶ms).unwrap();
|
||||
assert_eq!(
|
||||
"d2445d2d58e01146627c1e498dc0b4749d0cecd2cab05c5349ed132c083914e8",
|
||||
"ab32de057edf094958d178b3c91f3c8d5c296d526b11da991cd5773d09cea560",
|
||||
out_with_session_token_but_excluded.signature
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -552,9 +557,9 @@ mod tests {
|
|||
"authorization",
|
||||
HeaderValue::from_str(
|
||||
"AWS4-HMAC-SHA256 \
|
||||
Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, \
|
||||
Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, \
|
||||
SignedHeaders=host;x-amz-date, \
|
||||
Signature=d2445d2d58e01146627c1e498dc0b4749d0cecd2cab05c5349ed132c083914e8",
|
||||
Signature=ab32de057edf094958d178b3c91f3c8d5c296d526b11da991cd5773d09cea560",
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
|
@ -571,9 +576,7 @@ mod tests {
|
|||
fn test_sign_headers_space_trimming() {
|
||||
let settings = SigningSettings::default();
|
||||
let params = SigningParams {
|
||||
access_key: "AKIDEXAMPLE",
|
||||
secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "service",
|
||||
time: parse_date_time("20150830T123600Z").unwrap(),
|
||||
|
@ -590,9 +593,9 @@ mod tests {
|
|||
.unwrap()
|
||||
.into();
|
||||
let signable = SignableRequest::from(&original);
|
||||
let out = sign(signable, ¶ms).unwrap();
|
||||
let out = crate::http_request::sign(signable, ¶ms).unwrap();
|
||||
assert_eq!(
|
||||
"0bd74dbf6f21161f61a1a3a1c313b6a4bc67ec57bf5ea9ae956a63753ca1d7f7",
|
||||
"244f2a0db34c97a528f22715fe01b2417b7750c8a95c7fc104a3c48d81d84c08",
|
||||
out.signature
|
||||
);
|
||||
|
||||
|
@ -613,9 +616,9 @@ mod tests {
|
|||
"authorization",
|
||||
HeaderValue::from_str(
|
||||
"AWS4-HMAC-SHA256 \
|
||||
Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, \
|
||||
Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, \
|
||||
SignedHeaders=host;some-header;x-amz-date, \
|
||||
Signature=0bd74dbf6f21161f61a1a3a1c313b6a4bc67ec57bf5ea9ae956a63753ca1d7f7",
|
||||
Signature=244f2a0db34c97a528f22715fe01b2417b7750c8a95c7fc104a3c48d81d84c08",
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
|
@ -633,9 +636,7 @@ mod tests {
|
|||
) {
|
||||
let settings = SigningSettings::default();
|
||||
let params = SigningParams {
|
||||
access_key: "123",
|
||||
secret_key: "asdf",
|
||||
security_token: None,
|
||||
identity: &Credentials::for_tests().into(),
|
||||
region: "us-east-1",
|
||||
name: "foo",
|
||||
time: std::time::SystemTime::UNIX_EPOCH,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
unreachable_pub
|
||||
)]
|
||||
|
||||
use std::fmt;
|
||||
use aws_credential_types::Credentials;
|
||||
use aws_smithy_runtime_api::client::identity::Identity;
|
||||
use std::time::SystemTime;
|
||||
|
||||
pub mod sign;
|
||||
|
@ -29,14 +30,11 @@ pub mod event_stream;
|
|||
pub mod http_request;
|
||||
|
||||
/// Parameters to use when signing.
|
||||
// #[derive(Debug)] assumes that any data `Identity` holds is responsible for handling its own redaction.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct SigningParams<'a, S> {
|
||||
/// Access Key ID to use.
|
||||
pub(crate) access_key: &'a str,
|
||||
/// Secret access key to use.
|
||||
pub(crate) secret_key: &'a str,
|
||||
/// (Optional) Security token to use.
|
||||
pub(crate) security_token: Option<&'a str>,
|
||||
pub(crate) identity: &'a Identity,
|
||||
|
||||
/// Region to sign for.
|
||||
pub(crate) region: &'a str,
|
||||
|
@ -61,19 +59,10 @@ impl<'a, S> SigningParams<'a, S> {
|
|||
pub fn name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: fmt::Debug> fmt::Debug for SigningParams<'a, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SigningParams")
|
||||
.field("access_key", &"** redacted **")
|
||||
.field("secret_key", &"** redacted **")
|
||||
.field("security_token", &"** redacted **")
|
||||
.field("region", &self.region)
|
||||
.field("name", &self.name)
|
||||
.field("time", &self.time)
|
||||
.field("settings", &self.settings)
|
||||
.finish()
|
||||
/// If the identity in params contains AWS credentials, return them. Otherwise, return `None`.
|
||||
pub(crate) fn credentials(&self) -> Option<&Credentials> {
|
||||
self.identity.data::<Credentials>()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +75,7 @@ impl<'a, S: Default> SigningParams<'a, S> {
|
|||
|
||||
/// Builder and error for creating [`SigningParams`]
|
||||
pub mod signing_params {
|
||||
use super::SigningParams;
|
||||
use super::{Identity, SigningParams};
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::time::SystemTime;
|
||||
|
@ -113,9 +102,7 @@ pub mod signing_params {
|
|||
/// Builder that can create new [`SigningParams`]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Builder<'a, S> {
|
||||
access_key: Option<&'a str>,
|
||||
secret_key: Option<&'a str>,
|
||||
security_token: Option<&'a str>,
|
||||
identity: Option<&'a Identity>,
|
||||
region: Option<&'a str>,
|
||||
name: Option<&'a str>,
|
||||
time: Option<SystemTime>,
|
||||
|
@ -123,34 +110,14 @@ pub mod signing_params {
|
|||
}
|
||||
|
||||
impl<'a, S> Builder<'a, S> {
|
||||
/// Sets the access key (required).
|
||||
pub fn access_key(mut self, access_key: &'a str) -> Self {
|
||||
self.access_key = Some(access_key);
|
||||
/// Sets the identity (required).
|
||||
pub fn identity(mut self, identity: &'a Identity) -> Self {
|
||||
self.identity = Some(identity);
|
||||
self
|
||||
}
|
||||
/// Sets the access key (required)
|
||||
pub fn set_access_key(&mut self, access_key: Option<&'a str>) {
|
||||
self.access_key = access_key;
|
||||
}
|
||||
|
||||
/// Sets the secret key (required)
|
||||
pub fn secret_key(mut self, secret_key: &'a str) -> Self {
|
||||
self.secret_key = Some(secret_key);
|
||||
self
|
||||
}
|
||||
/// Sets the secret key (required)
|
||||
pub fn set_secret_key(&mut self, secret_key: Option<&'a str>) {
|
||||
self.secret_key = secret_key;
|
||||
}
|
||||
|
||||
/// Sets the security token (optional)
|
||||
pub fn security_token(mut self, security_token: &'a str) -> Self {
|
||||
self.security_token = Some(security_token);
|
||||
self
|
||||
}
|
||||
/// Sets the security token (optional)
|
||||
pub fn set_security_token(&mut self, security_token: Option<&'a str>) {
|
||||
self.security_token = security_token;
|
||||
/// Sets the identity (required)
|
||||
pub fn set_identity(&mut self, identity: Option<&'a Identity>) {
|
||||
self.identity = identity;
|
||||
}
|
||||
|
||||
/// Sets the region (required)
|
||||
|
@ -197,13 +164,9 @@ pub mod signing_params {
|
|||
/// a required argument was not given.
|
||||
pub fn build(self) -> Result<SigningParams<'a, S>, BuildError> {
|
||||
Ok(SigningParams {
|
||||
access_key: self
|
||||
.access_key
|
||||
.ok_or_else(|| BuildError::new("access key is required"))?,
|
||||
secret_key: self
|
||||
.secret_key
|
||||
.ok_or_else(|| BuildError::new("secret key is required"))?,
|
||||
security_token: self.security_token,
|
||||
identity: self
|
||||
.identity
|
||||
.ok_or_else(|| BuildError::new("an identity is required"))?,
|
||||
region: self
|
||||
.region
|
||||
.ok_or_else(|| BuildError::new("region is required"))?,
|
||||
|
|
|
@ -66,7 +66,7 @@ async fn generate_random() {
|
|||
let conf = Config::builder()
|
||||
.http_connector(conn.clone())
|
||||
.region(Region::new("us-east-1"))
|
||||
.credentials_provider(Credentials::for_tests())
|
||||
.credentials_provider(Credentials::for_tests_with_session_token())
|
||||
.build();
|
||||
let client = kms::Client::from_conf(conf);
|
||||
let resp = client
|
||||
|
@ -148,7 +148,7 @@ async fn generate_random_keystore_not_found() {
|
|||
let conf = Config::builder()
|
||||
.http_connector(conn.clone())
|
||||
.region(Region::new("us-east-1"))
|
||||
.credentials_provider(Credentials::for_tests())
|
||||
.credentials_provider(Credentials::for_tests_with_session_token())
|
||||
.build();
|
||||
let client = kms::Client::from_conf(conf);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use std::time::{Duration, SystemTime};
|
|||
#[tokio::test]
|
||||
async fn test_presigning() {
|
||||
let config = Config::builder()
|
||||
.credentials_provider(Credentials::for_tests())
|
||||
.credentials_provider(Credentials::for_tests_with_session_token())
|
||||
.region(Region::new("us-east-1"))
|
||||
.build();
|
||||
let client = polly::Client::from_conf(config);
|
||||
|
|
|
@ -37,7 +37,7 @@ async fn signv4_use_correct_service_name() {
|
|||
let conf = Config::builder()
|
||||
.http_connector(conn.clone())
|
||||
.region(Region::new("us-east-1"))
|
||||
.credentials_provider(Credentials::for_tests())
|
||||
.credentials_provider(Credentials::for_tests_with_session_token())
|
||||
.build();
|
||||
let client = Client::from_conf(conf);
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@ use std::time::{Duration, UNIX_EPOCH};
|
|||
async fn test_s3_ops_are_customizable() {
|
||||
let (conn, rcvr) = capture_request(None);
|
||||
let sdk_config = SdkConfig::builder()
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.region(Region::new("us-east-1"))
|
||||
.http_connector(conn.clone())
|
||||
.build();
|
||||
|
|
|
@ -42,7 +42,9 @@ async fn ignore_invalid_xml_body_root() {
|
|||
]);
|
||||
|
||||
let sdk_config = SdkConfig::builder()
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.region(Region::new("us-east-1"))
|
||||
.http_connector(conn.clone())
|
||||
.build();
|
||||
|
|
|
@ -50,7 +50,9 @@ const NAUGHTY_STRINGS: &str = include_str!("blns/blns.txt");
|
|||
async fn test_s3_signer_with_naughty_string_metadata() {
|
||||
let (conn, rcvr) = capture_request(None);
|
||||
let sdk_config = SdkConfig::builder()
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.region(Region::new("us-east-1"))
|
||||
.http_connector(conn.clone())
|
||||
.build();
|
||||
|
|
|
@ -14,7 +14,9 @@ use std::time::{Duration, UNIX_EPOCH};
|
|||
async fn test_operation_should_not_normalize_uri_path() {
|
||||
let (conn, rx) = capture_request(None);
|
||||
let sdk_config = SdkConfig::builder()
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.region(Region::new("us-east-1"))
|
||||
.http_connector(conn.clone())
|
||||
.build();
|
||||
|
|
|
@ -49,7 +49,7 @@ where
|
|||
O: FnOnce(s3::Client) -> F,
|
||||
F: TestOperation,
|
||||
{
|
||||
let creds = Credentials::for_tests();
|
||||
let creds = Credentials::for_tests_with_session_token();
|
||||
let config = s3::Config::builder()
|
||||
.credentials_provider(creds)
|
||||
.region(Region::new("us-east-1"))
|
||||
|
|
|
@ -14,7 +14,9 @@ use std::time::{Duration, UNIX_EPOCH};
|
|||
async fn test_s3_signer_query_string_with_all_valid_chars() {
|
||||
let (conn, rcvr) = capture_request(None);
|
||||
let sdk_config = SdkConfig::builder()
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.region(Region::new("us-east-1"))
|
||||
.http_connector(conn.clone())
|
||||
.build();
|
||||
|
|
|
@ -74,7 +74,7 @@ async fn three_retries_and_then_success() {
|
|||
let path = "tests/data/request-information-headers/three-retries_and-then-success.json";
|
||||
let conn = dvr::ReplayingConnection::from_file(path).unwrap();
|
||||
let config = aws_sdk_s3::Config::builder()
|
||||
.credentials_provider(Credentials::for_tests())
|
||||
.credentials_provider(Credentials::for_tests_with_session_token())
|
||||
.region(Region::new("us-east-1"))
|
||||
.http_connector(DynConnector::new(conn.clone()))
|
||||
.time_source(SharedTimeSource::new(time_source.clone()))
|
||||
|
|
|
@ -22,7 +22,9 @@ async fn test_signer() {
|
|||
http::Response::builder().status(200).body("").unwrap(),
|
||||
)]);
|
||||
let sdk_config = SdkConfig::builder()
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.region(Region::new("us-east-1"))
|
||||
.http_connector(conn.clone())
|
||||
.build();
|
||||
|
|
|
@ -25,7 +25,9 @@ async fn test_signer() {
|
|||
http::Response::builder().status(200).body("").unwrap(),
|
||||
)]);
|
||||
let sdk_config = SdkConfig::builder()
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.http_connector(conn.clone())
|
||||
.region(Region::new("us-east-1"))
|
||||
.build();
|
||||
|
|
|
@ -26,7 +26,9 @@ async fn do_endpoint_discovery() {
|
|||
.http_connector(conn.clone())
|
||||
.region(Region::from_static("us-west-2"))
|
||||
.sleep_impl(SharedAsyncSleep::new(sleep))
|
||||
.credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests()))
|
||||
.credentials_provider(SharedCredentialsProvider::new(
|
||||
Credentials::for_tests_with_session_token(),
|
||||
))
|
||||
.time_source(SharedTimeSource::new(ts.clone()))
|
||||
.build();
|
||||
let conf = query::config::Builder::from(&config)
|
||||
|
|
Loading…
Reference in New Issue