From a6ee5a1a724212b9da060432ed392fe3c5344d4f Mon Sep 17 00:00:00 2001 From: Monthon Klongklaew Date: Mon, 16 Oct 2023 22:57:06 +0100 Subject: [PATCH] Refactor signing configuration (#545) Signed-off-by: Monthon Klongklaew --- mountpoint-s3-client/src/s3_crt_client.rs | 43 +++++++++------ mountpoint-s3-crt/src/auth/credentials.rs | 18 +++++- mountpoint-s3-crt/src/auth/signing_config.rs | 48 +++++++++++++++- mountpoint-s3-crt/src/s3/client.rs | 58 +++++++++----------- 4 files changed, 115 insertions(+), 52 deletions(-) diff --git a/mountpoint-s3-client/src/s3_crt_client.rs b/mountpoint-s3-client/src/s3_crt_client.rs index 184e21241..17a1c83bd 100644 --- a/mountpoint-s3-client/src/s3_crt_client.rs +++ b/mountpoint-s3-client/src/s3_crt_client.rs @@ -22,8 +22,8 @@ use mountpoint_s3_crt::io::event_loop::EventLoopGroup; use mountpoint_s3_crt::io::host_resolver::{HostResolver, HostResolverDefaultOptions}; use mountpoint_s3_crt::io::retry_strategy::{ExponentialBackoffJitterMode, RetryStrategy, StandardRetryOptions}; use mountpoint_s3_crt::s3::client::{ - init_default_signing_config, ChecksumConfig, Client, ClientConfig, MetaRequestOptions, MetaRequestResult, - MetaRequestType, RequestType, + init_signing_config, ChecksumConfig, Client, ClientConfig, MetaRequestOptions, MetaRequestResult, MetaRequestType, + RequestType, }; use async_trait::async_trait; @@ -251,26 +251,32 @@ impl S3CrtClientInner { let credentials_chain_default_options = CredentialsProviderChainDefaultOptions { bootstrap: &mut client_bootstrap, }; - Some( - CredentialsProvider::new_chain_default(&allocator, credentials_chain_default_options) - .map_err(NewClientError::ProviderFailure)?, - ) + CredentialsProvider::new_chain_default(&allocator, credentials_chain_default_options) + .map_err(NewClientError::ProviderFailure)? + } + S3ClientAuthConfig::NoSigning => { + CredentialsProvider::new_anonymous(&allocator).map_err(NewClientError::ProviderFailure)? } - S3ClientAuthConfig::NoSigning => None, S3ClientAuthConfig::Profile(profile_name) => { let credentials_profile_options = CredentialsProviderProfileOptions { bootstrap: &mut client_bootstrap, profile_name_override: &profile_name, }; - Some( - CredentialsProvider::new_profile(&allocator, credentials_profile_options) - .map_err(NewClientError::ProviderFailure)?, - ) + CredentialsProvider::new_profile(&allocator, credentials_profile_options) + .map_err(NewClientError::ProviderFailure)? } - S3ClientAuthConfig::Provider(provider) => Some(provider), + S3ClientAuthConfig::Provider(provider) => provider, }; let endpoint_config = config.endpoint_config; + let signing_config = init_signing_config( + endpoint_config.get_region(), + credentials_provider.clone(), + None, + None, + None, + ); + client_config.signing_config(signing_config); client_config .client_bootstrap(client_bootstrap) @@ -303,7 +309,7 @@ impl S3CrtClientInner { request_payer: config.request_payer, part_size: config.part_size, bucket_owner: config.bucket_owner, - credentials_provider, + credentials_provider: Some(credentials_provider), }) } @@ -325,12 +331,15 @@ impl S3CrtClientInner { } }; trace!(?auth_scheme, "resolved auth scheme"); - Some(init_default_signing_config( + let algorithm = Some(auth_scheme.scheme_name()); + let service = Some(auth_scheme.signing_name()); + let use_double_uri_encode = Some(!auth_scheme.disable_double_encoding()); + Some(init_signing_config( auth_scheme.signing_region(), - auth_scheme.scheme_name(), - auth_scheme.signing_name(), - !auth_scheme.disable_double_encoding(), credentials_provider.clone(), + algorithm, + service, + use_double_uri_encode, )) } else { None diff --git a/mountpoint-s3-crt/src/auth/credentials.rs b/mountpoint-s3-crt/src/auth/credentials.rs index 29772fda3..8f68ab41f 100644 --- a/mountpoint-s3-crt/src/auth/credentials.rs +++ b/mountpoint-s3-crt/src/auth/credentials.rs @@ -5,8 +5,9 @@ use std::ptr::NonNull; use mountpoint_s3_crt_sys::{ aws_credentials_provider, aws_credentials_provider_acquire, aws_credentials_provider_chain_default_options, - aws_credentials_provider_new_chain_default, aws_credentials_provider_new_profile, - aws_credentials_provider_new_static, aws_credentials_provider_profile_options, aws_credentials_provider_release, + aws_credentials_provider_new_anonymous, aws_credentials_provider_new_chain_default, + aws_credentials_provider_new_profile, aws_credentials_provider_new_static, + aws_credentials_provider_profile_options, aws_credentials_provider_release, aws_credentials_provider_static_options, }; @@ -85,6 +86,19 @@ impl CredentialsProvider { Ok(Self { inner }) } + /// Creates the anonymous credential provider. + /// Anonynous credentials provider gives you anonymous credentials which can be used to skip the signing process. + pub fn new_anonymous(allocator: &Allocator) -> Result { + auth_library_init(allocator); + + // SAFETY: allocator is a valid aws_allocator and shutdown_options is optional + let inner = unsafe { + aws_credentials_provider_new_anonymous(allocator.inner.as_ptr(), std::ptr::null_mut()).ok_or_last_error()? + }; + + Ok(Self { inner }) + } + /// Creates the profile credential provider. pub fn new_profile(allocator: &Allocator, options: CredentialsProviderProfileOptions) -> Result { auth_library_init(allocator); diff --git a/mountpoint-s3-crt/src/auth/signing_config.rs b/mountpoint-s3-crt/src/auth/signing_config.rs index 710d052df..95d9bae71 100644 --- a/mountpoint-s3-crt/src/auth/signing_config.rs +++ b/mountpoint-s3-crt/src/auth/signing_config.rs @@ -1,7 +1,8 @@ //! Configuration for signing requests to AWS APIs use crate::auth::credentials::CredentialsProvider; -use mountpoint_s3_crt_sys::{aws_signing_algorithm, aws_signing_config_aws}; +use crate::ToAwsByteCursor; +use mountpoint_s3_crt_sys::{aws_s3_init_default_signing_config, aws_signing_algorithm, aws_signing_config_aws}; use std::ffi::OsString; use std::fmt::Debug; use std::marker::PhantomPinned; @@ -18,7 +19,7 @@ pub(crate) struct SigningConfigInner { pub(crate) credentials_provider: CredentialsProvider, /// An owned copy of the service string, since the `aws_signing_config_aws` holds a pointer to it. - pub(crate) service: OsString, + pub(crate) service: Option, /// This forces the struct to be !Unpin, because the signing config can contain pointers to itself pub(crate) _pinned: PhantomPinned, @@ -32,6 +33,49 @@ impl Debug for SigningConfigInner { } } +impl SigningConfigInner { + /// Create a new [SigningConfig] with default options. + pub fn new(region: &str, credentials_provider: CredentialsProvider) -> Self { + let mut signing_config = SigningConfigInner { + inner: Default::default(), + region: region.to_owned().into(), + credentials_provider, + service: None, + _pinned: Default::default(), + }; + + let credentials_provider = signing_config.credentials_provider.inner.as_ptr(); + // SAFETY: `region` is owned by signing_config (see `region.to_owned()` above), + // so the byte cursors we create here will point to bytes that are valid as long as this SigningConfig is. + // singing_config owns `credential_provider` that is valid as long as this SingingConfig is. + unsafe { + let region_cursor = signing_config.region.as_aws_byte_cursor(); + aws_s3_init_default_signing_config(&mut signing_config.inner, region_cursor, credentials_provider); + } + + signing_config + } + + /// Set the service name + pub fn service(&mut self, service: &str) { + self.service = Some(service.to_owned().into()); + // SAFETY: `service` is owned by signing_config, + // so the byte cursors we create here will point to bytes that are valid as long as this SigningConfig is. + let service_cursor = unsafe { self.service.as_ref().unwrap().as_aws_byte_cursor() }; + self.inner.service = service_cursor; + } + + /// Set whether to use double URI encode or not + pub fn use_double_uri_encode(&mut self, use_double_uri_encode: bool) { + self.inner.flags.set_use_double_uri_encode(use_double_uri_encode as u32); + } + + /// Set the signing algorithm + pub fn algorithm(&mut self, algorithm: SigningAlgorithm) { + self.inner.algorithm = algorithm.into(); + } +} + /// Wrap the SigningConfigInner struct into a Pin>, so that it cannot be moved. #[derive(Debug)] pub struct SigningConfig(pub(crate) Pin>); diff --git a/mountpoint-s3-crt/src/s3/client.rs b/mountpoint-s3-crt/src/s3/client.rs index 39af719f5..a6a38be5d 100644 --- a/mountpoint-s3-crt/src/s3/client.rs +++ b/mountpoint-s3-crt/src/s3/client.rs @@ -10,7 +10,7 @@ use crate::http::request_response::{Headers, Message}; use crate::io::channel_bootstrap::ClientBootstrap; use crate::io::retry_strategy::RetryStrategy; use crate::s3::s3_library_init; -use crate::{aws_byte_cursor_as_slice, CrtError, ResultExt, ToAwsByteCursor}; +use crate::{aws_byte_cursor_as_slice, CrtError, ResultExt}; use mountpoint_s3_crt_sys::*; use std::ffi::{OsStr, OsString}; use std::fmt::Debug; @@ -50,6 +50,9 @@ pub struct ClientConfig { /// so we only need to hold onto it until this [ClientConfig] is consumed, at which point the /// client will take ownership. retry_strategy: Option, + + /// The default signing config for the CRT client. + signing_config: Option, } impl ClientConfig { @@ -72,6 +75,13 @@ impl ClientConfig { self } + /// Default signing config for the requests. + pub fn signing_config(&mut self, signing_config: SigningConfig) -> &mut Self { + self.inner.signing_config = signing_config.to_inner_ptr() as *mut aws_signing_config_aws; + self.signing_config = Some(signing_config); + self + } + /// Size of parts the files will be downloaded or uploaded in. pub fn part_size(&mut self, part_size: usize) -> &mut Self { self.inner.part_size = part_size as u64; @@ -1035,40 +1045,26 @@ impl From for RequestType { } } -/// Create a new [SigningConfig] with the default configuration for signing S3 requests to a region +/// Create a new [SigningConfig] with the given configuration for signing S3 requests to a region /// using the given [CredentialsProvider] -pub fn init_default_signing_config( +pub fn init_signing_config( region: &str, - algorithm: SigningAlgorithm, - service: &str, - use_double_uri_encode: bool, credentials_provider: CredentialsProvider, + algorithm: Option, + service: Option<&str>, + use_double_uri_encode: Option, ) -> SigningConfig { - let mut signing_config = Box::new(SigningConfigInner { - inner: Default::default(), - region: region.to_owned().into(), - credentials_provider, - service: service.to_owned().into(), - _pinned: Default::default(), - }); - - let credentials_provider = signing_config.credentials_provider.inner.as_ptr(); - // SAFETY: `region` and `service` are owned by signing_config (see e.g. `region.to_owned()` above), - // so the byte cursors we create here will point to bytes that are valid as long as this SigningConfig is. - // singing_config owns `credential_provider` that is valid as long as this SingingConfig is. - unsafe { - let region_cursor = signing_config.region.as_aws_byte_cursor(); - aws_s3_init_default_signing_config(&mut signing_config.inner, region_cursor, credentials_provider); - - let service_cursor = signing_config.service.as_aws_byte_cursor(); - signing_config.inner.service = service_cursor; - } - - signing_config - .inner - .flags - .set_use_double_uri_encode(use_double_uri_encode as u32); - signing_config.inner.algorithm = algorithm.into(); + let mut signing_config = Box::new(SigningConfigInner::new(region, credentials_provider)); + + if let Some(service) = service { + signing_config.service(service); + } + if let Some(use_double_uri_encode) = use_double_uri_encode { + signing_config.use_double_uri_encode(use_double_uri_encode); + } + if let Some(algorithm) = algorithm { + signing_config.algorithm(algorithm); + } SigningConfig(Box::into_pin(signing_config)) }