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

Add support for SSO bearer token authentication to the SDK #3453

Merged
merged 26 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fe5e1f5
Establish token provider trait (#3381)
jdisanti Jan 24, 2024
0491ee5
Merge remote-tracking branch 'origin/main' into feature-sso-token-pro…
jdisanti Jan 26, 2024
b31709b
Merge remote-tracking branch 'origin/main' into feature-sso-token-pro…
jdisanti Feb 19, 2024
b0b1f83
Merge remote-tracking branch 'origin/main' into feature-sso-token-pro…
jdisanti Feb 23, 2024
a9885d3
Implement the default token provider chain
jdisanti Feb 23, 2024
cc24998
Fix external type checks
jdisanti Feb 24, 2024
3d69194
Fix more external types
jdisanti Feb 26, 2024
fc8b3aa
Fix warning
jdisanti Feb 26, 2024
fe118f3
Implement the default token provider chain (#3442)
jdisanti Feb 28, 2024
414c137
Merge remote-tracking branch 'origin/main' into feature-sso-token-pro…
jdisanti Feb 28, 2024
98cb375
Connect token providers via codegen
jdisanti Feb 24, 2024
48d3ea4
Minor fixes
jdisanti Feb 27, 2024
e7cf976
Make the ServiceSpecificDecorator more generic
jdisanti Feb 28, 2024
374b39f
Use ConditionalDecorator
jdisanti Feb 29, 2024
51c925b
Refactor sig auth detection
jdisanti Feb 29, 2024
e7bfbce
Use IntoShared
jdisanti Feb 29, 2024
10105e9
Move ConditionalDecorator into codegen-client
jdisanti Mar 1, 2024
f742a35
Set test token in `ConfigLoader::test_credentials`
jdisanti Mar 1, 2024
3d924d6
Improve doc comments on token provider config methods
jdisanti Mar 1, 2024
b49b88d
Connect aws-config token providers to service config via codegen (#3443)
jdisanti Mar 1, 2024
c4c3859
Merge remote-tracking branch 'origin/main' into feature-sso-token-pro…
jdisanti Mar 1, 2024
ec3ba7a
Update changelog
jdisanti Mar 1, 2024
cacded0
Merge remote-tracking branch 'origin/main' into feature-sso-token-pro…
jdisanti Mar 1, 2024
5b8531d
Merge remote-tracking branch 'origin/main' into feature-sso-token-pro…
jdisanti Mar 6, 2024
89a2ea8
Incorporate feedback
jdisanti Mar 6, 2024
e231821
Merge branch 'main' into feature-sso-token-providers
jdisanti Mar 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.next.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,9 @@ message = "Add support for Lambda's `InvokeWithResponseStreaming` and Bedrock Ag
references = ["aws-sdk-rust#1075", "aws-sdk-rust#1080", "smithy-rs#3451"]
meta = { "breaking" = false, "bug" = false, "tada" = true }
author = "jdisanti"

[[aws-sdk-rust]]
message = "Added support for SSO bearer token authentication. The aws-sdk-codecatalyst crate can now send requests without erroring."
references = ["aws-sdk-rust#703", "smithy-rs#3453"]
meta = { "breaking" = false, "bug" = false, "tada" = true }
author = "jdisanti"
7 changes: 4 additions & 3 deletions aws/rust-runtime/aws-config/external-types.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
# to the exposed SDK crates happens.
allowed_external_types = [
"aws_credential_types::cache::CredentialsCache",
"aws_credential_types::provider::ProvideCredentials",
"aws_credential_types::provider::Result",
"aws_credential_types::provider::SharedCredentialsProvider",
"aws_credential_types::provider::credentials::ProvideCredentials",
"aws_credential_types::provider::credentials::Result",
"aws_credential_types::provider::credentials::SharedCredentialsProvider",
"aws_credential_types::provider::token::ProvideToken",
"aws_smithy_async::rt::sleep::AsyncSleep",
"aws_smithy_async::rt::sleep::SharedAsyncSleep",
"aws_smithy_async::time::SharedTimeSource",
Expand Down
4 changes: 4 additions & 0 deletions aws/rust-runtime/aws-config/src/default_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ pub mod use_fips;

/// Default dual-stack provider chain
pub mod use_dual_stack;

/// Default access token provider chain
#[cfg(feature = "sso")]
pub mod token;
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,8 @@ impl Builder {

#[cfg(test)]
mod test {
use crate::test_case::TestEnvironment;
use crate::{
default_provider::credentials::DefaultCredentialsChain, test_case::StaticTestProvider,
};
use crate::default_provider::credentials::DefaultCredentialsChain;
use crate::test_case::{StaticTestProvider, TestEnvironment};
use aws_credential_types::provider::ProvideCredentials;
use aws_smithy_async::time::StaticTimeSource;
use std::time::UNIX_EPOCH;
Expand Down Expand Up @@ -246,7 +244,10 @@ mod test {
#[tokio::test]
async fn $name() {
let _ = crate::test_case::TestEnvironment::from_dir(
concat!("./test-data/default-credential-provider-chain/", stringify!($name)),
concat!(
"./test-data/default-credential-provider-chain/",
stringify!($name)
),
crate::test_case::test_credentials_provider(|config| {
async move {
crate::default_provider::credentials::Builder::default()
Expand All @@ -256,7 +257,7 @@ mod test {
.provide_credentials()
.await
}
})
}),
)
.await
.unwrap()
Expand Down
129 changes: 129 additions & 0 deletions aws/rust-runtime/aws-config/src/default_provider/token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

use crate::{
meta::{region::ProvideRegion, token::TokenProviderChain},
provider_config::ProviderConfig,
};
use aws_credential_types::provider::{future, token::ProvideToken};

/// Default access token provider chain
///
/// The region from the default region provider will be used
pub async fn default_provider() -> impl ProvideToken {
DefaultTokenChain::builder().build().await
}

/// Default access token provider chain
///
/// Currently, the default chain only examines the shared config
/// (`~/.aws/config`) file and the SSO token cache to resolve an
/// access token.
///
/// The AWS CLI can be used to retrieve the initial access token into
/// the SSO token cache. Once it's there, the SDK can refresh automatically
/// long as the it remains refreshable (it will eventually expire).
///
/// # Examples
/// Create a default chain with a custom region:
/// ```no_run
/// use aws_types::region::Region;
/// use aws_config::default_provider::token::DefaultTokenChain;
/// let token_provider = DefaultTokenChain::builder()
/// .region(Region::new("us-west-1"))
/// .build();
/// ```
///
/// Create a default chain with no overrides:
/// ```no_run
/// use aws_config::default_provider::token::DefaultTokenChain;
/// let token_provider = DefaultTokenChain::builder().build();
/// ```
///
/// Create a default chain that uses a different profile:
/// ```no_run
/// use aws_config::default_provider::token::DefaultTokenChain;
/// let token_provider = DefaultTokenChain::builder()
/// .profile_name("otherprofile")
/// .build();
/// ```
#[derive(Debug)]
pub struct DefaultTokenChain {
provider_chain: TokenProviderChain,
}

impl DefaultTokenChain {
/// Builder for `DefaultTokenChain`.
pub fn builder() -> Builder {
Builder::default()
}
}

impl ProvideToken for DefaultTokenChain {
fn provide_token<'a>(&'a self) -> future::ProvideToken<'a>
where
Self: 'a,
{
self.provider_chain.provide_token()
}
}

/// Builder for [`DefaultTokenChain`].
#[derive(Debug, Default)]
pub struct Builder {
profile_file_builder: crate::profile::token::Builder,
region_override: Option<Box<dyn ProvideRegion>>,
region_chain: crate::default_provider::region::Builder,
conf: Option<ProviderConfig>,
}

impl Builder {
/// Sets the region used when making requests to AWS services
///
/// When unset, the default region resolver chain will be used.
pub fn region(mut self, region: impl ProvideRegion + 'static) -> Self {
self.set_region(Some(region));
self
}

/// Sets the region used when making requests to AWS services
///
/// When unset, the default region resolver chain will be used.
pub fn set_region(&mut self, region: Option<impl ProvideRegion + 'static>) -> &mut Self {
self.region_override = region.map(|provider| Box::new(provider) as _);
self
}

/// Override the profile name used by this provider
///
/// When unset, the value of the `AWS_PROFILE` environment variable will be used.
pub fn profile_name(mut self, name: &str) -> Self {
self.profile_file_builder = self.profile_file_builder.profile_name(name);
self.region_chain = self.region_chain.profile_name(name);
self
}

/// Override the configuration used for this provider
pub(crate) fn configure(mut self, config: ProviderConfig) -> Self {
self.region_chain = self.region_chain.configure(&config);
self.conf = Some(config);
self
}

/// Creates a [`DefaultTokenChain`].
pub async fn build(self) -> DefaultTokenChain {
let region = match self.region_override {
Some(provider) => provider.region().await,
None => self.region_chain.build().region().await,
};
let conf = self.conf.unwrap_or_default().with_region(region);

let provider_chain = TokenProviderChain::first_try(
"Profile",
self.profile_file_builder.configure(&conf).build(),
);
DefaultTokenChain { provider_chain }
}
}
56 changes: 54 additions & 2 deletions aws/rust-runtime/aws-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,10 @@ mod loader {
use crate::meta::region::ProvideRegion;
use crate::profile::profile_file::ProfileFiles;
use crate::provider_config::ProviderConfig;
use aws_credential_types::provider::{ProvideCredentials, SharedCredentialsProvider};
use aws_credential_types::provider::{
token::{ProvideToken, SharedTokenProvider},
ProvideCredentials, SharedCredentialsProvider,
};
use aws_credential_types::Credentials;
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep};
use aws_smithy_async::time::{SharedTimeSource, TimeSource};
Expand Down Expand Up @@ -253,6 +256,7 @@ mod loader {
app_name: Option<AppName>,
identity_cache: Option<SharedIdentityCache>,
credentials_provider: CredentialsProviderOption,
token_provider: Option<SharedTokenProvider>,
endpoint_url: Option<String>,
region: Option<Box<dyn ProvideRegion>>,
retry_config: Option<RetryConfig>,
Expand Down Expand Up @@ -490,7 +494,36 @@ mod loader {

/// Set test credentials for use when signing requests
pub fn test_credentials(self) -> Self {
self.credentials_provider(Credentials::for_tests())
#[allow(unused_mut)]
let mut ret = self.credentials_provider(Credentials::for_tests());
#[cfg(all(feature = "sso", feature = "test-util"))]
{
use aws_smithy_runtime_api::client::identity::http::Token;
ret = ret.token_provider(Token::for_tests());
}
ret
}

/// Override the access token provider used to build [`SdkConfig`].
///
/// # Examples
///
/// Override the token provider but load the default value for region:
/// ```no_run
/// # use aws_credential_types::Token;
/// # fn create_my_token_provider() -> Token {
/// # Token::new("example", None)
/// # }
/// # async fn create_config() {
/// let config = aws_config::from_env()
/// .token_provider(create_my_token_provider())
/// .load()
/// .await;
/// # }
/// ```
pub fn token_provider(mut self, token_provider: impl ProvideToken + 'static) -> Self {
self.token_provider = Some(SharedTokenProvider::new(token_provider));
self
}

/// Override the name of the app used to build [`SdkConfig`].
Expand Down Expand Up @@ -754,6 +787,24 @@ mod loader {
CredentialsProviderOption::ExplicitlyUnset => None,
};

let token_provider = match self.token_provider {
Some(provider) => Some(provider),
None => {
#[cfg(feature = "sso")]
{
let mut builder =
crate::default_provider::token::DefaultTokenChain::builder()
.configure(conf.clone());
builder.set_region(region.clone());
Some(SharedTokenProvider::new(builder.build().await))
}
#[cfg(not(feature = "sso"))]
{
None
}
}
};

let mut builder = SdkConfig::builder()
.region(region)
.retry_config(retry_config)
Expand All @@ -765,6 +816,7 @@ mod loader {
builder.set_app_name(app_name);
builder.set_identity_cache(self.identity_cache);
builder.set_credentials_provider(credentials_provider);
builder.set_token_provider(token_provider);
builder.set_sleep_impl(sleep_impl);
builder.set_endpoint_url(self.endpoint_url);
builder.set_use_fips(use_fips);
Expand Down
1 change: 1 addition & 0 deletions aws/rust-runtime/aws-config/src/meta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

pub mod credentials;
pub mod region;
pub mod token;
Loading
Loading