Skip to content

Commit

Permalink
Upgrade aws-config time source
Browse files Browse the repository at this point in the history
  • Loading branch information
rcoh committed May 25, 2023
1 parent 3f0fdfe commit af9c2b9
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 40 deletions.
7 changes: 4 additions & 3 deletions aws/rust-runtime/aws-config/src/imds/client/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use aws_credential_types::cache::ExpiringCache;
use aws_credential_types::time_source::TimeSource;
use aws_http::user_agent::UserAgentStage;
use aws_smithy_async::rt::sleep::AsyncSleep;
use aws_smithy_async::time::SharedTimeSource;
use aws_smithy_client::erase::DynConnector;
use aws_smithy_client::retry;
use aws_smithy_http::body::SdkBody;
Expand Down Expand Up @@ -65,7 +66,7 @@ pub(super) struct TokenMiddleware {
client: Arc<aws_smithy_client::Client<DynConnector, MapRequestLayer<UserAgentStage>>>,
token_parser: GetTokenResponseHandler,
token: ExpiringCache<Token, ImdsError>,
time_source: TimeSource,
time_source: SharedTimeSource,
endpoint: Uri,
token_ttl: Duration,
}
Expand All @@ -79,7 +80,7 @@ impl Debug for TokenMiddleware {
impl TokenMiddleware {
pub(super) fn new(
connector: DynConnector,
time_source: TimeSource,
time_source: SharedTimeSource,
endpoint: Uri,
token_ttl: Duration,
retry_config: retry::Config,
Expand Down Expand Up @@ -170,7 +171,7 @@ impl AsyncMapRequest for TokenMiddleware {

#[derive(Clone)]
struct GetTokenResponseHandler {
time: TimeSource,
time: SharedTimeSource,
}

impl ParseStrictResponse for GetTokenResponseHandler {
Expand Down
9 changes: 6 additions & 3 deletions aws/rust-runtime/aws-config/src/imds/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use crate::imds::client::LazyClient;
use crate::json_credentials::{parse_json_credentials, JsonCredentials, RefreshableCredentials};
use crate::provider_config::ProviderConfig;
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
use aws_credential_types::time_source::TimeSource;
use aws_credential_types::Credentials;
use aws_smithy_async::time::SharedTimeSource;
use aws_types::os_shim_internal::Env;
use std::borrow::Cow;
use std::error::Error as StdError;
Expand Down Expand Up @@ -53,7 +53,7 @@ pub struct ImdsCredentialsProvider {
client: LazyClient,
env: Env,
profile: Option<String>,
time_source: TimeSource,
time_source: SharedTimeSource,
last_retrieved_credentials: Arc<RwLock<Option<Credentials>>>,
}

Expand Down Expand Up @@ -390,7 +390,10 @@ mod test {
.build();
let creds = provider.provide_credentials().await.expect("valid creds");
// The expiry should be equal to what is originally set (==2021-09-21T04:16:53Z).
assert!(creds.expiry() == UNIX_EPOCH.checked_add(Duration::from_secs(1632197813)));
assert_eq!(
creds.expiry(),
UNIX_EPOCH.checked_add(Duration::from_secs(1632197813))
);
connection.assert_requests_match(&[]);

// There should not be logs indicating credentials are extended for stability.
Expand Down
4 changes: 3 additions & 1 deletion aws/rust-runtime/aws-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,9 @@ mod loader {
.unwrap_or_else(|| HttpConnector::ConnectorFn(Arc::new(default_connector)));

let credentials_cache = self.credentials_cache.unwrap_or_else(|| {
let mut builder = CredentialsCache::lazy_builder().time_source(conf.time_source());
let mut builder = CredentialsCache::lazy_builder().time_source(
aws_credential_types::time_source::TimeSource::shared(conf.time_source()),
);
builder.set_sleep(conf.sleep());
builder.into_credentials_cache()
});
Expand Down
7 changes: 6 additions & 1 deletion aws/rust-runtime/aws-config/src/profile/credentials/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ impl ProviderChain {
web_identity_token_file: web_identity_token_file.into(),
role_arn: role_arn.to_string(),
session_name: session_name.map(|sess| sess.to_string()).unwrap_or_else(
|| sts::util::default_session_name("web-identity-token-profile"),
|| {
sts::util::default_session_name(
"web-identity-token-profile",
provider_config.time_source(),
)
},
),
})
.configure(provider_config)
Expand Down
13 changes: 7 additions & 6 deletions aws/rust-runtime/aws-config/src/provider_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use aws_credential_types::time_source::TimeSource;
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep};
use aws_smithy_async::time::SharedTimeSource;
use aws_smithy_client::erase::DynConnector;
use aws_smithy_types::error::display::DisplayErrorContext;
use aws_types::os_shim_internal::{Env, Fs};
Expand Down Expand Up @@ -38,7 +39,7 @@ use crate::profile::{ProfileFileLoadError, ProfileSet};
pub struct ProviderConfig {
env: Env,
fs: Fs,
time_source: TimeSource,
time_source: SharedTimeSource,
connector: HttpConnector,
sleep: Option<Arc<dyn AsyncSleep>>,
region: Option<Region>,
Expand Down Expand Up @@ -72,7 +73,7 @@ impl Default for ProviderConfig {
Self {
env: Env::default(),
fs: Fs::default(),
time_source: TimeSource::default(),
time_source: SharedTimeSource::default(),
connector,
sleep: default_async_sleep(),
region: None,
Expand Down Expand Up @@ -100,7 +101,7 @@ impl ProviderConfig {
profile_files: ProfileFiles::default(),
env,
fs,
time_source: TimeSource::testing(&TestingTimeSource::new(UNIX_EPOCH)),
time_source: SharedTimeSource::new(UNIX_EPOCH),
connector: HttpConnector::Prebuilt(None),
sleep: None,
region: None,
Expand Down Expand Up @@ -140,7 +141,7 @@ impl ProviderConfig {
ProviderConfig {
env: Env::default(),
fs: Fs::default(),
time_source: TimeSource::default(),
time_source: SharedTimeSource::default(),
connector: HttpConnector::Prebuilt(None),
sleep: None,
region: None,
Expand Down Expand Up @@ -179,7 +180,7 @@ impl ProviderConfig {
}

#[allow(dead_code)]
pub(crate) fn time_source(&self) -> TimeSource {
pub(crate) fn time_source(&self) -> SharedTimeSource {
self.time_source.clone()
}

Expand Down Expand Up @@ -293,7 +294,7 @@ impl ProviderConfig {
#[doc(hidden)]
pub fn with_time_source(self, time_source: TimeSource) -> Self {
ProviderConfig {
time_source,
time_source: SharedTimeSource::new(time_source),
..self
}
}
Expand Down
7 changes: 4 additions & 3 deletions aws/rust-runtime/aws-config/src/sts/assume_role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,14 @@ impl AssumeRoleProviderBuilder {
let mut config = aws_sdk_sts::Config::builder()
.credentials_cache(credentials_cache)
.credentials_provider(provider)
.time_source(conf.time_source())
.region(self.region.clone())
.http_connector(expect_connector(conf.connector(&Default::default())));
config.set_sleep_impl(conf.sleep());

let session_name = self
.session_name
.unwrap_or_else(|| super::util::default_session_name("assume-role-provider"));
let session_name = self.session_name.unwrap_or_else(|| {
super::util::default_session_name("assume-role-provider", conf.time_source().now())
});

let sts_client = StsClient::from_conf(config.build());
let fluent_builder = sts_client
Expand Down
7 changes: 3 additions & 4 deletions aws/rust-runtime/aws-config/src/sts/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use aws_credential_types::provider::{self, error::CredentialsError};
use aws_credential_types::Credentials as AwsCredentials;
use aws_sdk_sts::types::Credentials as StsCredentials;

use aws_smithy_async::time::TimeSource;
use std::convert::TryFrom;
use std::time::{SystemTime, UNIX_EPOCH};

Expand Down Expand Up @@ -45,9 +46,7 @@ pub(crate) fn into_credentials(
/// STS Assume Role providers MUST assign a name to their generated session. When a user does not
/// provide a name for the session, the provider will choose a name composed of a base + a timestamp,
/// e.g. `profile-file-provider-123456789`
pub(crate) fn default_session_name(base: &str) -> String {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("post epoch");
pub(crate) fn default_session_name(base: &str, ts: SystemTime) -> String {
let now = ts.now().duration_since(UNIX_EPOCH).expect("post epoch");
format!("{}-{}", base, now.as_millis())
}
8 changes: 5 additions & 3 deletions aws/rust-runtime/aws-config/src/web_identity_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use crate::provider_config::ProviderConfig;
use crate::sts;
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
use aws_sdk_sts::Client as StsClient;
use aws_smithy_async::time::SharedTimeSource;
use aws_smithy_types::error::display::DisplayErrorContext;
use aws_types::os_shim_internal::{Env, Fs};
use std::borrow::Cow;
Expand All @@ -80,6 +81,7 @@ const ENV_VAR_SESSION_NAME: &str = "AWS_ROLE_SESSION_NAME";
#[derive(Debug)]
pub struct WebIdentityTokenCredentialsProvider {
source: Source,
time_source: SharedTimeSource,
fs: Fs,
sts_client: StsClient,
}
Expand Down Expand Up @@ -131,9 +133,9 @@ impl WebIdentityTokenCredentialsProvider {
"AWS_ROLE_ARN environment variable must be set",
)
})?;
let session_name = env
.get(ENV_VAR_SESSION_NAME)
.unwrap_or_else(|_| sts::util::default_session_name("web-identity-token"));
let session_name = env.get(ENV_VAR_SESSION_NAME).unwrap_or_else(|_| {
sts::util::default_session_name("web-identity-token", self.time_source.now())
});
Ok(Cow::Owned(StaticConfiguration {
web_identity_token_file: token_file.into(),
role_arn,
Expand Down
31 changes: 15 additions & 16 deletions aws/rust-runtime/aws-credential-types/src/time_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,23 @@
* SPDX-License-Identifier: Apache-2.0
*/

use aws_smithy_async::time::{SharedTimeSource, TimeSource as TimeSourceTrait};
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};

impl TimeSourceTrait for TimeSource {
fn now(&self) -> SystemTime {
self.now()
}
}

/// Time source abstraction
///
/// Simple abstraction representing time either real-time or manually-specified for testing
///
/// # Examples
///
/// ```rust
/// # struct Client {
/// # // stub
/// # }
/// #
/// # impl Client {
/// # fn with_timesource(ts: TimeSource) -> Self {
/// # Client { }
/// # }
/// # }
/// use aws_credential_types::time_source::TimeSource;
/// let time = TimeSource::default();
/// let client = Client::with_timesource(time);
/// ```
#[derive(Debug, Clone)]
// TODO(breakingChangeWindow): Delete this struct
pub struct TimeSource(Inner);

impl TimeSource {
Expand All @@ -36,11 +28,17 @@ impl TimeSource {
TimeSource(Inner::Testing(time_source.clone()))
}

/// Creates `TimeSource` from a shared time source
pub fn shared(time_source: SharedTimeSource) -> Self {
TimeSource(Inner::Shared(time_source))
}

/// Returns the current system time based on the mode.
pub fn now(&self) -> SystemTime {
match &self.0 {
Inner::Default => SystemTime::now(),
Inner::Testing(testing) => testing.now(),
Inner::Shared(ts) => ts.now(),
}
}
}
Expand Down Expand Up @@ -118,6 +116,7 @@ impl TestingTimeSource {
enum Inner {
Default,
Testing(TestingTimeSource),
Shared(SharedTimeSource),
}

#[cfg(test)]
Expand Down

0 comments on commit af9c2b9

Please sign in to comment.