Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop S3ExpressSigner and override session token name via RuntimePlugin #3457

Merged
47 changes: 38 additions & 9 deletions aws/rust-runtime/aws-inlineable/src/s3_express.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@

/// Supporting code for S3 Express auth
pub(crate) mod auth {
use aws_runtime::auth::apply_signing_instructions;
use aws_runtime::auth::sigv4::SigV4Signer;
use aws_sigv4::http_request::{SignatureLocation, SigningSettings};
use aws_sigv4::http_request::{
sign, SignableBody, SignableRequest, SignatureLocation, SigningParams, SigningSettings,
};
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::auth::{
AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Sign,
Expand Down Expand Up @@ -66,17 +69,43 @@ pub(crate) mod auth {
) -> Result<(), BoxError> {
let operation_config =
SigV4Signer::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
let request_time = runtime_components.time_source().unwrap_or_default().now();
let mut settings = SigV4Signer::signing_settings(&operation_config);
override_session_token_name(&mut settings)?;

SigV4Signer.sign_http_request(
request,
identity,
settings,
&operation_config,
runtime_components,
config_bag,
)
let signing_params =
SigV4Signer::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
// (any sort of streaming body or presigned request) will be signed via UNSIGNED-PAYLOAD.
let signable_body = operation_config
.signing_options
.payload_override
.as_ref()
// the payload_override is a cheap clone because it contains either a
// reference or a short checksum (we're not cloning the entire body)
.cloned()
.unwrap_or_else(|| {
request
.body()
.bytes()
.map(SignableBody::Bytes)
.unwrap_or(SignableBody::UnsignedPayload)
});

let signable_request = SignableRequest::new(
request.method(),
request.uri(),
request.headers().iter(),
signable_body,
)?;
sign(signable_request, &SigningParams::V4(signing_params))?
}
.into_parts();

apply_signing_instructions(signing_instructions, request)?;
Ok(())
}
}

Expand Down
27 changes: 19 additions & 8 deletions aws/rust-runtime/aws-runtime/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,14 @@ fn settings(operation_config: &SigV4OperationSigningConfig) -> SigningSettings {
settings
}

/// Errors that can occur while signing with SigV4.
#[derive(Debug)]
enum SigV4SigningError {
pub struct SigV4SigningError {
kind: ErrorKind,
}

#[derive(Debug)]
pub(crate) enum ErrorKind {
MissingOperationSigningConfig,
MissingSigningRegion,
#[cfg(feature = "sigv4a")]
Expand All @@ -142,9 +148,9 @@ enum SigV4SigningError {

impl fmt::Display for SigV4SigningError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use SigV4SigningError::*;
use ErrorKind::*;
let mut w = |s| f.write_str(s);
match self {
match &self.kind {
MissingOperationSigningConfig => w("missing operation signing config"),
MissingSigningRegion => w("missing signing region"),
#[cfg(feature = "sigv4a")]
Expand All @@ -168,24 +174,28 @@ impl StdError for SigV4SigningError {}
fn extract_endpoint_auth_scheme_signing_name(
endpoint_config: &AuthSchemeEndpointConfig<'_>,
) -> Result<Option<SigningName>, SigV4SigningError> {
use SigV4SigningError::BadTypeInEndpointAuthSchemeConfig as UnexpectedType;
use ErrorKind::BadTypeInEndpointAuthSchemeConfig as UnexpectedType;

match extract_field_from_endpoint_config("signingName", endpoint_config) {
Some(Document::String(s)) => Ok(Some(SigningName::from(s.to_string()))),
None => Ok(None),
_ => Err(UnexpectedType("signingName")),
_ => Err(SigV4SigningError {
kind: UnexpectedType("signingName"),
}),
}
}

fn extract_endpoint_auth_scheme_signing_region(
endpoint_config: &AuthSchemeEndpointConfig<'_>,
) -> Result<Option<SigningRegion>, SigV4SigningError> {
use SigV4SigningError::BadTypeInEndpointAuthSchemeConfig as UnexpectedType;
use ErrorKind::BadTypeInEndpointAuthSchemeConfig as UnexpectedType;

match extract_field_from_endpoint_config("signingRegion", endpoint_config) {
Some(Document::String(s)) => Ok(Some(SigningRegion::from(Region::new(s.clone())))),
None => Ok(None),
_ => Err(UnexpectedType("signingRegion")),
_ => Err(SigV4SigningError {
kind: UnexpectedType("signingRegion"),
}),
}
}

Expand All @@ -199,7 +209,8 @@ fn extract_field_from_endpoint_config<'a>(
.and_then(|config| config.get(field_name))
}

fn apply_signing_instructions(
/// Applies the instructions to the given `request`.
pub fn apply_signing_instructions(
ysaito1001 marked this conversation as resolved.
Show resolved Hide resolved
instructions: SigningInstructions,
request: &mut HttpRequest,
) -> Result<(), BoxError> {
Expand Down
87 changes: 36 additions & 51 deletions aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use crate::auth;
use crate::auth::{
extract_endpoint_auth_scheme_signing_name, extract_endpoint_auth_scheme_signing_region,
SigV4OperationSigningConfig, SigV4SigningError,
ErrorKind, SigV4OperationSigningConfig, SigV4SigningError,
};
use aws_credential_types::Credentials;
use aws_sigv4::http_request::{
Expand Down Expand Up @@ -77,15 +77,18 @@ impl SigV4Signer {
super::settings(operation_config)
}

fn signing_params<'a>(
/// Creates a [`SigningParams`] from the given arguments.
pub fn signing_params<'a>(
settings: SigningSettings,
identity: &'a Identity,
operation_config: &'a SigV4OperationSigningConfig,
request_timestamp: SystemTime,
) -> Result<v4::SigningParams<'a, SigningSettings>, SigV4SigningError> {
let creds = identity
.data::<Credentials>()
.ok_or_else(|| SigV4SigningError::WrongIdentityType(identity.clone()))?;
.ok_or_else(|| SigV4SigningError {
kind: ErrorKind::WrongIdentityType(identity.clone()),
})?;

if let Some(expires_in) = settings.expires_in {
if let Some(creds_expires_time) = creds.expiry() {
Expand All @@ -102,14 +105,18 @@ impl SigV4Signer {
operation_config
.region
.as_ref()
.ok_or(SigV4SigningError::MissingSigningRegion)?
.ok_or(SigV4SigningError {
kind: ErrorKind::MissingSigningRegion,
})?
.as_ref(),
)
.name(
operation_config
.name
.as_ref()
.ok_or(SigV4SigningError::MissingSigningName)?
.ok_or(SigV4SigningError {
kind: ErrorKind::MissingSigningName,
})?
.as_ref(),
)
.time(request_timestamp)
Expand All @@ -122,10 +129,13 @@ impl SigV4Signer {
pub fn extract_operation_config<'a>(
auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'a>,
config_bag: &'a ConfigBag,
) -> Result<Cow<'a, SigV4OperationSigningConfig>, BoxError> {
let operation_config = config_bag
.load::<SigV4OperationSigningConfig>()
.ok_or(SigV4SigningError::MissingOperationSigningConfig)?;
) -> Result<Cow<'a, SigV4OperationSigningConfig>, SigV4SigningError> {
let operation_config =
config_bag
.load::<SigV4OperationSigningConfig>()
.ok_or(SigV4SigningError {
kind: ErrorKind::MissingOperationSigningConfig,
})?;

let name = extract_endpoint_auth_scheme_signing_name(&auth_scheme_endpoint_config)?
.or(config_bag.load::<SigningName>().cloned());
Expand All @@ -143,27 +153,31 @@ impl SigV4Signer {
}
}
}
}

/// Signs the given `request`.
///
/// This is a helper used by [`Sign::sign_http_request`] and will be useful if calling code
/// needs to pass a configured `settings`.
///
/// TODO(S3Express): Make this method more user friendly, possibly returning a builder
/// instead of taking these input parameters. The builder will have a `sign` method that
/// does what this method body currently does.
pub fn sign_http_request(
impl Sign for SigV4Signer {
fn sign_http_request(
&self,
request: &mut HttpRequest,
identity: &Identity,
settings: SigningSettings,
operation_config: &SigV4OperationSigningConfig,
auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
runtime_components: &RuntimeComponents,
#[allow(unused_variables)] config_bag: &ConfigBag,
config_bag: &ConfigBag,
) -> Result<(), BoxError> {
let operation_config =
Self::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
let request_time = runtime_components.time_source().unwrap_or_default().now();

if identity.data::<Credentials>().is_none() {
return Err(SigV4SigningError {
kind: ErrorKind::WrongIdentityType(identity.clone()),
}
.into());
};

let settings = Self::signing_settings(&operation_config);
let signing_params =
Self::signing_params(settings, identity, 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
Expand Down Expand Up @@ -219,35 +233,6 @@ impl SigV4Signer {
}
}

impl Sign for SigV4Signer {
fn sign_http_request(
&self,
request: &mut HttpRequest,
identity: &Identity,
auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
runtime_components: &RuntimeComponents,
config_bag: &ConfigBag,
) -> Result<(), BoxError> {
if identity.data::<Credentials>().is_none() {
return Err(SigV4SigningError::WrongIdentityType(identity.clone()).into());
};

let operation_config =
Self::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;

let settings = Self::signing_settings(&operation_config);

self.sign_http_request(
request,
identity,
settings,
&operation_config,
runtime_components,
config_bag,
)
}
}

#[cfg(feature = "event-stream")]
mod event_stream {
use aws_sigv4::event_stream::{sign_empty_message, sign_message};
Expand Down
30 changes: 21 additions & 9 deletions aws/rust-runtime/aws-runtime/src/auth/sigv4a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

use crate::auth::{
apply_signing_instructions, extract_endpoint_auth_scheme_signing_name,
apply_signing_instructions, extract_endpoint_auth_scheme_signing_name, ErrorKind,
SigV4OperationSigningConfig, SigV4SigningError,
};
use aws_credential_types::Credentials;
Expand Down Expand Up @@ -95,14 +95,18 @@ impl SigV4aSigner {
operation_config
.region_set
.as_ref()
.ok_or(SigV4SigningError::MissingSigningRegionSet)?
.ok_or(SigV4SigningError {
kind: ErrorKind::MissingSigningRegionSet,
})?
.as_ref(),
)
.name(
operation_config
.name
.as_ref()
.ok_or(SigV4SigningError::MissingSigningName)?
.ok_or(SigV4SigningError {
kind: ErrorKind::MissingSigningName,
})?
.as_ref(),
)
.time(request_timestamp)
Expand All @@ -115,9 +119,12 @@ impl SigV4aSigner {
auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'a>,
config_bag: &'a ConfigBag,
) -> Result<Cow<'a, SigV4OperationSigningConfig>, SigV4SigningError> {
let operation_config = config_bag
.load::<SigV4OperationSigningConfig>()
.ok_or(SigV4SigningError::MissingOperationSigningConfig)?;
let operation_config =
config_bag
.load::<SigV4OperationSigningConfig>()
.ok_or(SigV4SigningError {
kind: ErrorKind::MissingOperationSigningConfig,
})?;

let name = extract_endpoint_auth_scheme_signing_name(&auth_scheme_endpoint_config)?
.or(config_bag.load::<SigningName>().cloned());
Expand All @@ -142,7 +149,7 @@ fn extract_endpoint_auth_scheme_signing_region_set(
endpoint_config: &AuthSchemeEndpointConfig<'_>,
) -> Result<Option<SigningRegionSet>, SigV4SigningError> {
use aws_smithy_types::Document::Array;
use SigV4SigningError::BadTypeInEndpointAuthSchemeConfig as UnexpectedType;
use ErrorKind::BadTypeInEndpointAuthSchemeConfig as UnexpectedType;

match super::extract_field_from_endpoint_config("signingRegionSet", endpoint_config) {
Some(Array(docs)) => {
Expand All @@ -153,7 +160,9 @@ fn extract_endpoint_auth_scheme_signing_region_set(
Ok(Some(region_set))
}
None => Ok(None),
_it => Err(UnexpectedType("signingRegionSet")),
_it => Err(SigV4SigningError {
kind: UnexpectedType("signingRegionSet"),
}),
}
}

Expand All @@ -171,7 +180,10 @@ impl Sign for SigV4aSigner {
let request_time = runtime_components.time_source().unwrap_or_default().now();

if identity.data::<Credentials>().is_none() {
return Err(SigV4SigningError::WrongIdentityType(identity.clone()).into());
return Err(SigV4SigningError {
kind: ErrorKind::WrongIdentityType(identity.clone()),
}
.into());
}

let settings = Self::settings(&operation_config);
Expand Down
Loading