Skip to content

Commit

Permalink
Refactor signing configuration (#545)
Browse files Browse the repository at this point in the history
Signed-off-by: Monthon Klongklaew <[email protected]>
  • Loading branch information
monthonk authored Oct 16, 2023
1 parent 8490e8b commit a6ee5a1
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 52 deletions.
43 changes: 26 additions & 17 deletions mountpoint-s3-client/src/s3_crt_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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),
})
}

Expand All @@ -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
Expand Down
18 changes: 16 additions & 2 deletions mountpoint-s3-crt/src/auth/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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<Self, Error> {
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<Self, Error> {
auth_library_init(allocator);
Expand Down
48 changes: 46 additions & 2 deletions mountpoint-s3-crt/src/auth/signing_config.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<OsString>,

/// This forces the struct to be !Unpin, because the signing config can contain pointers to itself
pub(crate) _pinned: PhantomPinned,
Expand All @@ -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<Box<_>>, so that it cannot be moved.
#[derive(Debug)]
pub struct SigningConfig(pub(crate) Pin<Box<SigningConfigInner>>);
Expand Down
58 changes: 27 additions & 31 deletions mountpoint-s3-crt/src/s3/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<RetryStrategy>,

/// The default signing config for the CRT client.
signing_config: Option<SigningConfig>,
}

impl ClientConfig {
Expand All @@ -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;
Expand Down Expand Up @@ -1035,40 +1045,26 @@ impl From<aws_s3_request_type> 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<SigningAlgorithm>,
service: Option<&str>,
use_double_uri_encode: Option<bool>,
) -> 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))
}
Expand Down

0 comments on commit a6ee5a1

Please sign in to comment.