AWS SDK

AWS SDK

rev. 37276c5e0ace204ec6c0f1a727e085b17e15d36a

Files changed:

tmp-codegen-diff/aws-sdk/README.md

@@ -1,1 +57,57 @@
   17     17   
   18     18   
> For a step-by-step guide including several advanced use cases, check out the [Developer Guide](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/welcome.html).
   19     19   
   20     20   
The SDK provides one crate per AWS service. You must add [Tokio](https://crates.io/crates/tokio) as a dependency within your Rust project to execute asynchronous code.
   21     21   
   22     22   
1. Create a new Rust project: `cargo new sdk-example`
   23     23   
2. Add dependencies to DynamoDB and Tokio to your **Cargo.toml** file:
   24     24   
   25     25   
    ```toml
   26     26   
    [dependencies]
   27         -
    aws-config = { version= "1.8.3", features = ["behavior-version-latest"] }
          27  +
    aws-config = { version= "1.8.4", features = ["behavior-version-latest"] }
   28     28   
    aws-sdk-dynamodb = "0.0.0-local"
   29     29   
    tokio = { version = "1", features = ["full"] }
   30     30   
    ```
   31     31   
   32     32   
3. Provide your AWS credentials with the default credential provider chain, which currently looks in:
   33     33   
   - Environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`
   34     34   
   - The default credentials files located in `~/.aws/config` and `~/.aws/credentials` (location can vary per platform)
   35     35   
   - Web Identity Token credentials from the environment or container (including EKS)
   36     36   
   - ECS Container Credentials (IAM roles for tasks)
   37     37   
   - EC2 Instance Metadata Service (IAM Roles attached to instance)

tmp-codegen-diff/aws-sdk/sdk/aws-config/Cargo.toml

@@ -1,1 +34,34 @@
    1      1   
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
    2      2   
[package]
    3      3   
name = "aws-config"
    4         -
version = "1.8.3"
           4  +
version = "1.8.4"
    5      5   
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "Russell Cohen <rcoh@amazon.com>"]
    6      6   
description = "AWS SDK config and credential provider implementations."
    7      7   
edition = "2021"
    8      8   
exclude = ["test-data/*", "integration-tests/*"]
    9      9   
license = "Apache-2.0"
   10     10   
repository = "https://github.com/smithy-lang/smithy-rs"
   11     11   
[package.metadata.docs.rs]
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
@@ -44,44 +157,157 @@
   64     64   
version = "0.61.4"
   65     65   
   66     66   
[dependencies.aws-smithy-runtime]
   67     67   
path = "../aws-smithy-runtime"
   68     68   
features = ["client"]
   69     69   
version = "1.8.6"
   70     70   
   71     71   
[dependencies.aws-smithy-runtime-api]
   72     72   
path = "../aws-smithy-runtime-api"
   73     73   
features = ["client"]
   74         -
version = "1.8.5"
          74  +
version = "1.8.6"
   75     75   
   76     76   
[dependencies.aws-smithy-types]
   77     77   
path = "../aws-smithy-types"
   78     78   
version = "1.3.2"
   79     79   
   80     80   
[dependencies.aws-types]
   81     81   
path = "../aws-types"
   82     82   
version = "1.3.8"
   83     83   
   84     84   
[dependencies.time]
   85     85   
version = "0.3.4"
   86     86   
features = ["parsing"]
   87     87   
   88     88   
[dependencies.tokio]
   89     89   
version = "1.13.1"
   90     90   
features = ["sync"]
   91     91   
   92     92   
[dependencies.tracing]
   93     93   
version = "0.1"
   94     94   
   95     95   
[dependencies.aws-sdk-sso]
   96     96   
path = "../sso"
   97     97   
default-features = false
   98     98   
optional = true
   99     99   
version = "0.0.0-local"
  100    100   
  101    101   
[dependencies.ring]
  102    102   
version = "0.17.5"
  103    103   
optional = true
  104    104   
  105    105   
[dependencies.hex]
  106    106   
version = "0.4.3"
  107    107   
optional = true
  108    108   
  109    109   
[dependencies.zeroize]
  110    110   
version = "1"
  111    111   
optional = true
  112    112   
  113    113   
[dependencies.aws-sdk-ssooidc]
  114    114   
path = "../ssooidc"
  115    115   
default-features = false
  116    116   
optional = true
  117    117   
version = "0.0.0-local"
  118    118   
  119    119   
[dev-dependencies]
  120    120   
tracing-test = "0.2.4"
  121    121   
serde_json = "1"
  122    122   
  123    123   
[dev-dependencies.aws-smithy-async]
  124    124   
path = "../aws-smithy-async"
  125    125   
features = ["rt-tokio", "test-util"]
  126    126   
version = "1.2.5"
  127    127   
  128         -
[dev-dependencies.aws-smithy-runtime]
  129         -
path = "../aws-smithy-runtime"
  130         -
features = ["client", "test-util"]
  131         -
version = "1.8.6"
  132         -
  133    128   
[dev-dependencies.aws-smithy-http-client]
  134    129   
path = "../aws-smithy-http-client"
  135    130   
features = ["default-client", "test-util"]
  136    131   
version = "1.0.6"
  137    132   
         133  +
[dev-dependencies.aws-smithy-runtime]
         134  +
path = "../aws-smithy-runtime"
         135  +
features = ["client", "test-util"]
         136  +
version = "1.8.6"
         137  +
  138    138   
[dev-dependencies.aws-smithy-runtime-api]
  139    139   
path = "../aws-smithy-runtime-api"
  140    140   
features = ["test-util"]
  141         -
version = "1.8.5"
         141  +
version = "1.8.6"
  142    142   
  143    143   
[dev-dependencies.futures-util]
  144    144   
version = "0.3.29"
  145    145   
default-features = false
  146    146   
  147    147   
[dev-dependencies.tracing-subscriber]
  148    148   
version = "0.3.16"
  149    149   
features = ["fmt", "json"]
  150    150   
  151    151   
[dev-dependencies.tokio]

tmp-codegen-diff/aws-sdk/sdk/aws-config/external-types.toml

@@ -1,1 +39,41 @@
    9      9   
   "aws_runtime::env_config::error::EnvConfigFileLoadError",
   10     10   
   "aws_runtime::env_config::file::Builder",
   11     11   
   "aws_runtime::env_config::file::EnvConfigFileKind",
   12     12   
   "aws_runtime::env_config::file::EnvConfigFiles",
   13     13   
   "aws_runtime::env_config::parse::EnvConfigParseError",
   14     14   
   "aws_runtime::env_config::property::Property",
   15     15   
   "aws_runtime::env_config::section::EnvConfigSections",
   16     16   
   "aws_runtime::env_config::section::Profile",
   17     17   
   "aws_smithy_async::rt::sleep::AsyncSleep",
   18     18   
   "aws_smithy_async::time::TimeSource",
          19  +
   "aws_smithy_http_client::test_util::replay::StaticReplayClient",
   19     20   
   "aws_smithy_runtime::client::identity::cache::IdentityCache",
   20     21   
   "aws_smithy_runtime::client::identity::cache::lazy::LazyCacheBuilder",
   21     22   
   "aws_smithy_runtime_api::client::auth::AuthSchemePreference",
          23  +
   "aws_smithy_runtime_api::client::orchestrator::HttpRequest",
   22     24   
   "aws_smithy_runtime_api::box_error::BoxError",
   23     25   
   "aws_smithy_runtime_api::client::behavior_version::BehaviorVersion",
   24     26   
   "aws_smithy_runtime_api::client::dns::ResolveDns",
   25     27   
   "aws_smithy_runtime_api::client::http::HttpClient",
   26     28   
   "aws_smithy_runtime_api::client::identity::ResolveCachedIdentity",
   27     29   
   "aws_smithy_runtime_api::client::identity::ResolveIdentity",
   28     30   
   "aws_smithy_runtime_api::client::orchestrator::HttpResponse",
   29     31   
   "aws_smithy_runtime_api::client::retries::classifiers::ClassifyRetry",
   30     32   
   "aws_smithy_runtime_api::client::retries::classifiers::SharedRetryClassifier",
   31     33   
   "aws_smithy_runtime_api::client::stalled_stream_protection::StalledStreamProtectionConfig",

tmp-codegen-diff/aws-sdk/sdk/aws-config/fuzz/Cargo.toml

@@ -1,1 +30,30 @@
   13     13   
edition = "2021"
   14     14   
   15     15   
[package.metadata]
   16     16   
cargo-fuzz = true
   17     17   
   18     18   
[dependencies]
   19     19   
libfuzzer-sys = "=0.4.7"
   20     20   
   21     21   
[dependencies.aws-config]
   22     22   
path = ".."
   23         -
version = "1.8.3"
          23  +
version = "1.8.4"
   24     24   
   25     25   
[dependencies.aws-types]
   26     26   
path = "../../../sdk/build/aws-sdk/sdk/aws-types"
   27     27   
version = "1.3.8"
   28     28   
   29     29   
[workspace]
   30     30   
members = ["."]

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/credential_process.rs

@@ -1,1 +42,43 @@
    3      3   
 * SPDX-License-Identifier: Apache-2.0
    4      4   
 */
    5      5   
    6      6   
#![cfg(feature = "credentials-process")]
    7      7   
    8      8   
//! Credentials Provider for external process
    9      9   
   10     10   
use crate::json_credentials::{json_parse_loop, InvalidJsonCredentials};
   11     11   
use crate::sensitive_command::CommandWithSensitiveArgs;
   12     12   
use aws_credential_types::attributes::AccountId;
          13  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
   13     14   
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
   14     15   
use aws_credential_types::Credentials;
   15     16   
use aws_smithy_json::deserialize::Token;
   16     17   
use std::borrow::Cow;
   17     18   
use std::process::Command;
   18     19   
use std::time::SystemTime;
   19     20   
use time::format_description::well_known::Rfc3339;
   20     21   
use time::OffsetDateTime;
   21     22   
   22     23   
/// External process credentials provider
@@ -95,96 +162,168 @@
  115    116   
            )));
  116    117   
        }
  117    118   
  118    119   
        let output = std::str::from_utf8(&output.stdout).map_err(|e| {
  119    120   
            CredentialsError::provider_error(format!(
  120    121   
                "Error retrieving credentials from external process: could not decode output as UTF-8: {}",
  121    122   
                e
  122    123   
            ))
  123    124   
        })?;
  124    125   
  125         -
        parse_credential_process_json_credentials(output, self.profile_account_id.as_ref()).map_err(
  126         -
            |invalid| {
         126  +
        parse_credential_process_json_credentials(output, self.profile_account_id.as_ref())
         127  +
            .map(|mut creds| {
         128  +
                creds
         129  +
                    .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
         130  +
                    .push(AwsCredentialFeature::CredentialsProcess);
         131  +
                creds
         132  +
            })
         133  +
            .map_err(|invalid| {
  127    134   
                CredentialsError::provider_error(format!(
  128    135   
                "Error retrieving credentials from external process, could not parse response: {}",
  129    136   
                invalid
  130    137   
            ))
  131         -
            },
  132         -
        )
         138  +
            })
  133    139   
    }
  134    140   
}
  135    141   
  136    142   
#[derive(Debug, Default)]
  137    143   
pub(crate) struct Builder {
  138    144   
    command: Option<CommandWithSensitiveArgs<String>>,
  139    145   
    profile_account_id: Option<AccountId>,
  140    146   
}
  141    147   
  142    148   
impl Builder {
@@ -237,243 +296,303 @@
  257    263   
        .map_err(|err| InvalidJsonCredentials::InvalidField {
  258    264   
            field: "Expiration",
  259    265   
            err: err.into(),
  260    266   
        })
  261    267   
}
  262    268   
  263    269   
#[cfg(test)]
  264    270   
mod test {
  265    271   
    use crate::credential_process::CredentialProcessProvider;
  266    272   
    use crate::sensitive_command::CommandWithSensitiveArgs;
         273  +
    use aws_credential_types::credential_feature::AwsCredentialFeature;
  267    274   
    use aws_credential_types::provider::ProvideCredentials;
  268    275   
    use std::time::{Duration, SystemTime};
  269    276   
    use time::format_description::well_known::Rfc3339;
  270    277   
    use time::OffsetDateTime;
  271    278   
    use tokio::time::timeout;
  272    279   
  273    280   
    // TODO(https://github.com/awslabs/aws-sdk-rust/issues/1117) This test is ignored on Windows because it uses Unix-style paths
  274    281   
    #[tokio::test]
  275    282   
    #[cfg_attr(windows, ignore)]
  276    283   
    async fn test_credential_process() {
@@ -312,319 +342,364 @@
  332    339   
    async fn fallback_account_id_shadowed_by_account_id_in_process_output() {
  333    340   
        let provider = CredentialProcessProvider::builder()
  334    341   
            .command(CommandWithSensitiveArgs::new(String::from(
  335    342   
                r#"echo '{ "Version": 1, "AccessKeyId": "ASIARTESTID", "SecretAccessKey": "TESTSECRETKEY", "AccountId": "111122223333" }'"#,
  336    343   
            )))
  337    344   
            .account_id("012345678901")
  338    345   
            .build();
  339    346   
        let creds = provider.provide_credentials().await.unwrap();
  340    347   
        assert_eq!("111122223333", creds.account_id().unwrap().as_str());
  341    348   
    }
         349  +
         350  +
    #[tokio::test]
         351  +
    async fn credential_feature() {
         352  +
        let provider = CredentialProcessProvider::builder()
         353  +
            .command(CommandWithSensitiveArgs::new(String::from(
         354  +
                r#"echo '{ "Version": 1, "AccessKeyId": "ASIARTESTID", "SecretAccessKey": "TESTSECRETKEY", "AccountId": "111122223333" }'"#,
         355  +
            )))
         356  +
            .account_id("012345678901")
         357  +
            .build();
         358  +
        let creds = provider.provide_credentials().await.unwrap();
         359  +
        assert_eq!(
         360  +
            &vec![AwsCredentialFeature::CredentialsProcess],
         361  +
            creds.get_property::<Vec<AwsCredentialFeature>>().unwrap()
         362  +
        );
         363  +
    }
  342    364   
}

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/environment/credentials.rs

@@ -1,1 +142,148 @@
    1      1   
/*
    2      2   
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    3      3   
 * SPDX-License-Identifier: Apache-2.0
    4      4   
 */
    5      5   
    6      6   
use std::env::VarError;
    7      7   
    8      8   
use aws_credential_types::attributes::AccountId;
           9  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
    9     10   
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
   10     11   
use aws_credential_types::Credentials;
   11     12   
use aws_types::os_shim_internal::Env;
   12     13   
   13     14   
/// Load Credentials from Environment Variables
   14     15   
///
   15     16   
/// `EnvironmentVariableCredentialsProvider` uses the following variables:
   16     17   
/// - `AWS_ACCESS_KEY_ID`
   17     18   
/// - `AWS_SECRET_ACCESS_KEY` with fallback to `SECRET_ACCESS_KEY`
   18     19   
/// - `AWS_SESSION_TOKEN` (optional)
   19     20   
/// - `AWS_ACCOUNT_ID` (optional)
   20     21   
#[derive(Debug, Clone)]
   21     22   
pub struct EnvironmentVariableCredentialsProvider {
   22     23   
    env: Env,
   23     24   
}
   24     25   
   25     26   
impl EnvironmentVariableCredentialsProvider {
   26     27   
    fn credentials(&self) -> provider::Result {
   27     28   
        let access_key = self
   28     29   
            .env
   29     30   
            .get("AWS_ACCESS_KEY_ID")
   30     31   
            .and_then(err_if_blank)
   31     32   
            .map_err(to_cred_error)?;
   32     33   
        let secret_key = self
   33     34   
            .env
   34     35   
            .get("AWS_SECRET_ACCESS_KEY")
   35     36   
            .and_then(err_if_blank)
   36     37   
            .or_else(|_| self.env.get("SECRET_ACCESS_KEY"))
   37     38   
            .and_then(err_if_blank)
   38     39   
            .map_err(to_cred_error)?;
   39     40   
        let session_token =
   40     41   
            self.env
   41     42   
                .get("AWS_SESSION_TOKEN")
   42     43   
                .ok()
   43     44   
                .and_then(|token| match token.trim() {
   44     45   
                    "" => None,
   45     46   
                    s => Some(s.to_string()),
   46     47   
                });
   47     48   
        let account_id =
   48     49   
            self.env
   49     50   
                .get("AWS_ACCOUNT_ID")
   50     51   
                .ok()
   51     52   
                .and_then(|account_id| match account_id.trim() {
   52     53   
                    "" => None,
   53     54   
                    s => Some(AccountId::from(s)),
   54     55   
                });
   55     56   
        let mut builder = Credentials::builder()
   56     57   
            .access_key_id(access_key)
   57     58   
            .secret_access_key(secret_key)
   58     59   
            .provider_name(ENV_PROVIDER);
   59     60   
        builder.set_session_token(session_token);
   60     61   
        builder.set_account_id(account_id);
   61         -
        Ok(builder.build())
          62  +
        let mut creds = builder.build();
          63  +
        creds
          64  +
            .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
          65  +
            .push(AwsCredentialFeature::CredentialsEnvVars);
          66  +
        Ok(creds)
   62     67   
    }
   63     68   
}
   64     69   
   65     70   
impl EnvironmentVariableCredentialsProvider {
   66     71   
    /// Create a `EnvironmentVariableCredentialsProvider`
   67     72   
    pub fn new() -> Self {
   68     73   
        Self::new_with_env(Env::real())
   69     74   
    }
   70     75   
   71     76   
    /// Create a new `EnvironmentVariableCredentialsProvider` with `Env` overridden
   72     77   
    ///
   73     78   
    /// This function is intended for tests that mock out the process environment.
   74     79   
    pub(crate) fn new_with_env(env: Env) -> Self {
   75     80   
        Self { env }
   76     81   
    }
   77     82   
}
   78     83   
   79     84   
impl Default for EnvironmentVariableCredentialsProvider {
   80     85   
    fn default() -> Self {
   81     86   
        Self::new()
   82     87   
    }
   83     88   
}
   84     89   
   85     90   
const ENV_PROVIDER: &str = "EnvironmentVariable";
   86     91   
   87     92   
impl ProvideCredentials for EnvironmentVariableCredentialsProvider {
   88     93   
    fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a>
   89     94   
    where
   90     95   
        Self: 'a,
   91     96   
    {
   92     97   
        future::ProvideCredentials::ready(self.credentials())
   93     98   
    }
   94     99   
}
   95    100   
   96    101   
fn to_cred_error(err: VarError) -> CredentialsError {
   97    102   
    match err {
   98    103   
        VarError::NotPresent => CredentialsError::not_loaded("environment variable not set"),
   99    104   
        e @ VarError::NotUnicode(_) => CredentialsError::unhandled(e),
  100    105   
    }
  101    106   
}
  102    107   
  103    108   
fn err_if_blank(value: String) -> Result<String, VarError> {
  104    109   
    if value.trim().is_empty() {
  105    110   
        Err(VarError::NotPresent)
  106    111   
    } else {
  107    112   
        Ok(value)
  108    113   
    }
  109    114   
}
  110    115   
  111    116   
#[cfg(test)]
  112    117   
mod test {
         118  +
    use aws_credential_types::credential_feature::AwsCredentialFeature;
  113    119   
    use aws_credential_types::provider::{error::CredentialsError, ProvideCredentials};
  114    120   
    use aws_types::os_shim_internal::Env;
  115    121   
    use futures_util::FutureExt;
  116    122   
  117    123   
    use super::EnvironmentVariableCredentialsProvider;
  118    124   
  119    125   
    fn make_provider(vars: &[(&str, &str)]) -> EnvironmentVariableCredentialsProvider {
  120    126   
        EnvironmentVariableCredentialsProvider {
  121    127   
            env: Env::from_slice(vars),
  122    128   
        }
@@ -223,229 +259,285 @@
  243    249   
  244    250   
            let err = provider
  245    251   
                .provide_credentials()
  246    252   
                .now_or_never()
  247    253   
                .unwrap()
  248    254   
                .expect_err("no credentials defined");
  249    255   
            assert!(matches!(err, CredentialsError::CredentialsNotLoaded { .. }));
  250    256   
        }
  251    257   
    }
  252    258   
         259  +
    #[test]
         260  +
    fn credentials_feature() {
         261  +
        let provider = make_provider(&[
         262  +
            ("AWS_ACCESS_KEY_ID", "access"),
         263  +
            ("AWS_SECRET_ACCESS_KEY", "secret"),
         264  +
            ("SECRET_ACCESS_KEY", "secret"),
         265  +
            ("AWS_SESSION_TOKEN", "token"),
         266  +
        ]);
         267  +
         268  +
        let creds = provider
         269  +
            .provide_credentials()
         270  +
            .now_or_never()
         271  +
            .unwrap()
         272  +
            .expect("valid credentials");
         273  +
        assert_eq!(
         274  +
            &vec![AwsCredentialFeature::CredentialsEnvVars],
         275  +
            creds.get_property::<Vec<AwsCredentialFeature>>().unwrap()
         276  +
        );
         277  +
    }
         278  +
  253    279   
    #[test]
  254    280   
    fn real_environment() {
  255    281   
        let provider = EnvironmentVariableCredentialsProvider::new();
  256    282   
        // we don't know what's in the env, just make sure it doesn't crash.
  257    283   
        let _fut = provider.provide_credentials();
  258    284   
    }
  259    285   
}

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/http_credential_provider.rs

@@ -1,1 +87,97 @@
    4      4   
 */
    5      5   
    6      6   
//! Generalized HTTP credential provider. Currently, this cannot be used directly and can only
    7      7   
//! be used via the ECS credential provider.
    8      8   
//!
    9      9   
//! Future work will stabilize this interface and enable it to be used directly.
   10     10   
   11     11   
use crate::json_credentials::{parse_json_credentials, JsonCredentials, RefreshableCredentials};
   12     12   
use crate::provider_config::ProviderConfig;
   13     13   
use aws_credential_types::attributes::AccountId;
          14  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
   14     15   
use aws_credential_types::provider::{self, error::CredentialsError};
   15     16   
use aws_credential_types::Credentials;
   16     17   
use aws_smithy_runtime::client::metrics::MetricsRuntimePlugin;
   17     18   
use aws_smithy_runtime::client::orchestrator::operation::Operation;
   18     19   
use aws_smithy_runtime::client::retries::classifiers::{
   19     20   
    HttpStatusCodeClassifier, TransientErrorClassifier,
   20     21   
};
   21     22   
use aws_smithy_runtime_api::client::http::HttpConnectorSettings;
   22     23   
use aws_smithy_runtime_api::client::interceptors::context::{Error, InterceptorContext};
   23     24   
use aws_smithy_runtime_api::client::orchestrator::{
   24     25   
    HttpResponse, Metadata, OrchestratorError, SensitiveOutput,
   25     26   
};
   26     27   
use aws_smithy_runtime_api::client::result::SdkError;
   27     28   
use aws_smithy_runtime_api::client::retries::classifiers::ClassifyRetry;
   28     29   
use aws_smithy_runtime_api::client::retries::classifiers::RetryAction;
   29     30   
use aws_smithy_runtime_api::client::runtime_plugin::StaticRuntimePlugin;
   30     31   
use aws_smithy_types::body::SdkBody;
   31     32   
use aws_smithy_types::config_bag::Layer;
   32     33   
use aws_smithy_types::retry::RetryConfig;
   33     34   
use aws_smithy_types::timeout::TimeoutConfig;
   34     35   
use http::header::{ACCEPT, AUTHORIZATION};
   35     36   
use http::HeaderValue;
   36     37   
use std::time::Duration;
   37     38   
   38     39   
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(5);
   39     40   
const DEFAULT_CONNECT_TIMEOUT: Duration = Duration::from_secs(2);
   40     41   
   41     42   
#[derive(Debug)]
   42     43   
struct HttpProviderAuth {
   43     44   
    auth: Option<HeaderValue>,
   44     45   
}
   45     46   
   46     47   
#[derive(Debug)]
   47     48   
pub(crate) struct HttpCredentialProvider {
   48     49   
    operation: Operation<HttpProviderAuth, Credentials, CredentialsError>,
   49     50   
}
   50     51   
   51     52   
impl HttpCredentialProvider {
   52     53   
    pub(crate) fn builder() -> Builder {
   53     54   
        Builder::default()
   54     55   
    }
   55     56   
   56     57   
    pub(crate) async fn credentials(&self, auth: Option<HeaderValue>) -> provider::Result {
   57         -
        let credentials = self.operation.invoke(HttpProviderAuth { auth }).await;
          58  +
        let credentials =
          59  +
            self.operation
          60  +
                .invoke(HttpProviderAuth { auth })
          61  +
                .await
          62  +
                .map(|mut creds| {
          63  +
                    creds
          64  +
                        .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
          65  +
                        .push(AwsCredentialFeature::CredentialsHttp);
          66  +
                    creds
          67  +
                });
   58     68   
        match credentials {
   59     69   
            Ok(creds) => Ok(creds),
   60     70   
            Err(SdkError::ServiceError(context)) => Err(context.into_err()),
   61     71   
            Err(other) => Err(CredentialsError::unhandled(other)),
   62     72   
        }
   63     73   
    }
   64     74   
}
   65     75   
   66     76   
#[derive(Default)]
   67     77   
pub(crate) struct Builder {
@@ -206,216 +265,276 @@
  226    236   
            }
  227    237   
        }
  228    238   
  229    239   
        RetryAction::NoActionIndicated
  230    240   
    }
  231    241   
}
  232    242   
  233    243   
#[cfg(test)]
  234    244   
mod test {
  235    245   
    use super::*;
         246  +
    use aws_credential_types::credential_feature::AwsCredentialFeature;
  236    247   
    use aws_credential_types::provider::error::CredentialsError;
  237    248   
    use aws_smithy_http_client::test_util::{ReplayEvent, StaticReplayClient};
  238    249   
    use aws_smithy_types::body::SdkBody;
  239    250   
    use http::{Request, Response, Uri};
  240    251   
    use std::time::SystemTime;
  241    252   
  242    253   
    async fn provide_creds(
  243    254   
        http_client: StaticReplayClient,
  244    255   
    ) -> Result<Credentials, CredentialsError> {
  245    256   
        let provider_config = ProviderConfig::default().with_http_client(http_client.clone());
@@ -319,330 +349,370 @@
  339    350   
        )]);
  340    351   
        let err = provide_creds(http_client.clone())
  341    352   
            .await
  342    353   
            .expect_err("it should fail");
  343    354   
        assert!(
  344    355   
            matches!(err, CredentialsError::ProviderError { .. }),
  345    356   
            "should be CredentialsError::ProviderError: {err}",
  346    357   
        );
  347    358   
        http_client.assert_requests_match(&[]);
  348    359   
    }
         360  +
         361  +
    #[tokio::test]
         362  +
    async fn credentials_feature() {
         363  +
        let http_client = StaticReplayClient::new(vec![successful_req_resp()]);
         364  +
        let creds = provide_creds(http_client.clone()).await.expect("success");
         365  +
        assert_eq!(
         366  +
            &vec![AwsCredentialFeature::CredentialsHttp],
         367  +
            creds.get_property::<Vec<AwsCredentialFeature>>().unwrap()
         368  +
        );
         369  +
    }
  349    370   
}

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/imds/client.rs

@@ -614,614 +765,769 @@
  634    634   
        } else {
  635    635   
            // This is the default behavior.
  636    636   
            // Don't retry timeouts for IMDS, or else it will take ~30 seconds for the default
  637    637   
            // credentials provider chain to fail to provide credentials.
  638    638   
            // Also don't retry non-responses.
  639    639   
            RetryAction::NoActionIndicated
  640    640   
        }
  641    641   
    }
  642    642   
}
  643    643   
  644         -
#[cfg(test)]
         644  +
#[cfg(all(test, feature = "test-util"))]
  645    645   
pub(crate) mod test {
  646    646   
    use crate::imds::client::{Client, EndpointMode, ImdsResponseRetryClassifier};
  647    647   
    use crate::provider_config::ProviderConfig;
  648    648   
    use aws_smithy_async::rt::sleep::TokioSleep;
  649    649   
    use aws_smithy_async::test_util::{instant_time_and_sleep, InstantSleep};
  650    650   
    use aws_smithy_http_client::test_util::{capture_request, ReplayEvent, StaticReplayClient};
  651    651   
    use aws_smithy_runtime::test_util::capture_test_logs::capture_test_logs;
  652    652   
    use aws_smithy_runtime_api::client::interceptors::context::{
  653    653   
        Input, InterceptorContext, Output,
  654    654   
    };
  655         -
    use aws_smithy_runtime_api::client::orchestrator::{
  656         -
        HttpRequest, HttpResponse, OrchestratorError,
  657         -
    };
         655  +
    use aws_smithy_runtime_api::client::orchestrator::OrchestratorError;
         656  +
    use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
  658    657   
    use aws_smithy_runtime_api::client::result::ConnectorError;
  659    658   
    use aws_smithy_runtime_api::client::retries::classifiers::{
  660    659   
        ClassifyRetry, RetryAction, SharedRetryClassifier,
  661    660   
    };
  662    661   
    use aws_smithy_types::body::SdkBody;
  663    662   
    use aws_smithy_types::error::display::DisplayErrorContext;
  664    663   
    use aws_types::os_shim_internal::{Env, Fs};
  665    664   
    use http::header::USER_AGENT;
  666    665   
    use http::Uri;
  667    666   
    use serde::Deserialize;
  668    667   
    use std::collections::HashMap;
  669    668   
    use std::error::Error;
  670    669   
    use std::io;
  671    670   
    use std::time::SystemTime;
  672    671   
    use std::time::{Duration, UNIX_EPOCH};
  673    672   
    use tracing_test::traced_test;
  674    673   
  675    674   
    macro_rules! assert_full_error_contains {
  676    675   
        ($err:expr, $contains:expr) => {
  677    676   
            let err = $err;
  678    677   
            let message = format!(
  679    678   
                "{}",
  680    679   
                aws_smithy_types::error::display::DisplayErrorContext(&err)
  681    680   
            );
  682    681   
            assert!(
  683    682   
                message.contains($contains),
  684    683   
                "Error message '{message}' didn't contain text '{}'",
  685    684   
                $contains
  686    685   
            );
  687    686   
        };
  688    687   
    }
  689    688   
  690    689   
    const TOKEN_A: &str = "AQAEAFTNrA4eEGx0AQgJ1arIq_Cc-t4tWt3fB0Hd8RKhXlKc5ccvhg==";
  691    690   
    const TOKEN_B: &str = "alternatetoken==";
  692    691   
         692  +
    /// Create a simple token request
  693    693   
    pub(crate) fn token_request(base: &str, ttl: u32) -> HttpRequest {
  694    694   
        http::Request::builder()
  695    695   
            .uri(format!("{}/latest/api/token", base))
  696    696   
            .header("x-aws-ec2-metadata-token-ttl-seconds", ttl)
  697    697   
            .method("PUT")
  698    698   
            .body(SdkBody::empty())
  699    699   
            .unwrap()
  700    700   
            .try_into()
  701    701   
            .unwrap()
  702    702   
    }
  703    703   
         704  +
    /// Create a simple token response
  704    705   
    pub(crate) fn token_response(ttl: u32, token: &'static str) -> HttpResponse {
  705    706   
        HttpResponse::try_from(
  706    707   
            http::Response::builder()
  707    708   
                .status(200)
  708    709   
                .header("X-aws-ec2-metadata-token-ttl-seconds", ttl)
  709    710   
                .body(SdkBody::from(token))
  710    711   
                .unwrap(),
  711    712   
        )
  712    713   
        .unwrap()
  713    714   
    }
  714    715   
         716  +
    /// Create a simple IMDS request
  715    717   
    pub(crate) fn imds_request(path: &'static str, token: &str) -> HttpRequest {
  716    718   
        http::Request::builder()
  717    719   
            .uri(Uri::from_static(path))
  718    720   
            .method("GET")
  719    721   
            .header("x-aws-ec2-metadata-token", token)
  720    722   
            .body(SdkBody::empty())
  721    723   
            .unwrap()
  722    724   
            .try_into()
  723    725   
            .unwrap()
  724    726   
    }
  725    727   
         728  +
    /// Create a simple IMDS response
  726    729   
    pub(crate) fn imds_response(body: &'static str) -> HttpResponse {
  727    730   
        HttpResponse::try_from(
  728    731   
            http::Response::builder()
  729    732   
                .status(200)
  730    733   
                .body(SdkBody::from(body))
  731    734   
                .unwrap(),
  732    735   
        )
  733    736   
        .unwrap()
  734    737   
    }
  735    738   
         739  +
    /// Create an IMDS client with an underlying [StaticReplayClient]
  736    740   
    pub(crate) fn make_imds_client(http_client: &StaticReplayClient) -> super::Client {
  737    741   
        tokio::time::pause();
  738    742   
        super::Client::builder()
  739    743   
            .configure(
  740    744   
                &ProviderConfig::no_configuration()
  741    745   
                    .with_sleep_impl(InstantSleep::unlogged())
  742    746   
                    .with_http_client(http_client.clone()),
  743    747   
            )
  744    748   
            .build()
  745    749   
    }

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/imds/credentials.rs

@@ -1,1 +44,45 @@
    5      5   
    6      6   
//! IMDSv2 Credentials Provider
    7      7   
//!
    8      8   
//! # Important
    9      9   
//! This credential provider will NOT fallback to IMDSv1. Ensure that IMDSv2 is enabled on your instances.
   10     10   
   11     11   
use super::client::error::ImdsError;
   12     12   
use crate::imds::{self, Client};
   13     13   
use crate::json_credentials::{parse_json_credentials, JsonCredentials, RefreshableCredentials};
   14     14   
use crate::provider_config::ProviderConfig;
          15  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
   15     16   
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
   16     17   
use aws_credential_types::Credentials;
   17     18   
use aws_smithy_async::time::SharedTimeSource;
   18     19   
use aws_types::os_shim_internal::Env;
   19     20   
use std::borrow::Cow;
   20     21   
use std::error::Error as StdError;
   21     22   
use std::fmt;
   22     23   
use std::sync::{Arc, RwLock};
   23     24   
use std::time::{Duration, SystemTime};
   24     25   
@@ -242,243 +322,330 @@
  262    263   
            }
  263    264   
            Ok(JsonCredentials::Error { code, message }) => {
  264    265   
                Err(CredentialsError::provider_error(format!(
  265    266   
                    "Error retrieving credentials from IMDS: {} {}",
  266    267   
                    code, message
  267    268   
                )))
  268    269   
            }
  269    270   
            // got bad data from IMDS, should not occur during normal operation:
  270    271   
            Err(invalid) => Err(CredentialsError::unhandled(invalid)),
  271    272   
        }
         273  +
        .map(|mut creds| {
         274  +
            creds
         275  +
                .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
         276  +
                .push(AwsCredentialFeature::CredentialsImds);
         277  +
            creds
         278  +
        })
  272    279   
    }
  273    280   
  274    281   
    async fn credentials(&self) -> provider::Result {
  275    282   
        match self.retrieve_credentials().await {
  276    283   
            creds @ Ok(_) => creds,
  277    284   
            // Any failure while retrieving credentials MUST NOT impede use of existing credentials.
  278    285   
            err => match &*self.last_retrieved_credentials.read().unwrap() {
  279    286   
                Some(creds) => Ok(creds.clone()),
  280    287   
                _ => err,
  281    288   
            },
  282    289   
        }
  283    290   
    }
  284    291   
}
  285    292   
  286    293   
#[cfg(test)]
  287    294   
mod test {
  288    295   
    use super::*;
  289    296   
    use crate::imds::client::test::{
  290    297   
        imds_request, imds_response, make_imds_client, token_request, token_response,
  291    298   
    };
  292    299   
    use crate::provider_config::ProviderConfig;
         300  +
    use aws_credential_types::credential_feature::AwsCredentialFeature;
  293    301   
    use aws_credential_types::provider::ProvideCredentials;
  294    302   
    use aws_smithy_async::test_util::instant_time_and_sleep;
  295    303   
    use aws_smithy_http_client::test_util::{ReplayEvent, StaticReplayClient};
  296    304   
    use aws_smithy_types::body::SdkBody;
  297    305   
    use std::time::{Duration, UNIX_EPOCH};
  298    306   
    use tracing_test::traced_test;
  299    307   
  300    308   
    const TOKEN_A: &str = "token_a";
  301    309   
  302    310   
    #[tokio::test]
@@ -502,510 +532,575 @@
  522    530   
            .imds_client(make_imds_client(&http_client))
  523    531   
            .configure(&ProviderConfig::no_configuration())
  524    532   
            .build();
  525    533   
        let creds1 = provider.provide_credentials().await.expect("valid creds");
  526    534   
        assert_eq!(creds1.access_key_id(), "ASIARTEST");
  527    535   
        // `creds1` should be returned as fallback credentials and assigned to `creds2`
  528    536   
        let creds2 = provider.provide_credentials().await.expect("valid creds");
  529    537   
        assert_eq!(creds1, creds2);
  530    538   
        http_client.assert_requests_match(&[]);
  531    539   
    }
         540  +
         541  +
    #[tokio::test]
         542  +
    async fn credentials_feature() {
         543  +
        let http_client = StaticReplayClient::new(vec![
         544  +
            ReplayEvent::new(
         545  +
                token_request("http://169.254.169.254", 21600),
         546  +
                token_response(21600, TOKEN_A),
         547  +
            ),
         548  +
            ReplayEvent::new(
         549  +
                imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/", TOKEN_A),
         550  +
                imds_response(r#"profile-name"#),
         551  +
            ),
         552  +
            ReplayEvent::new(
         553  +
                imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/profile-name", TOKEN_A),
         554  +
                imds_response("{\n  \"Code\" : \"Success\",\n  \"LastUpdated\" : \"2021-09-20T21:42:26Z\",\n  \"Type\" : \"AWS-HMAC\",\n  \"AccessKeyId\" : \"ASIARTEST\",\n  \"SecretAccessKey\" : \"testsecret\",\n  \"Token\" : \"testtoken\",\n  \"Expiration\" : \"2021-09-21T04:16:53Z\"\n}"),
         555  +
            ),
         556  +
            ReplayEvent::new(
         557  +
                imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/", TOKEN_A),
         558  +
                imds_response(r#"different-profile"#),
         559  +
            ),
         560  +
            ReplayEvent::new(
         561  +
                imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/different-profile", TOKEN_A),
         562  +
                imds_response("{\n  \"Code\" : \"Success\",\n  \"LastUpdated\" : \"2021-09-20T21:42:26Z\",\n  \"Type\" : \"AWS-HMAC\",\n  \"AccessKeyId\" : \"ASIARTEST2\",\n  \"SecretAccessKey\" : \"testsecret\",\n  \"Token\" : \"testtoken\",\n  \"Expiration\" : \"2021-09-21T04:16:53Z\"\n}"),
         563  +
            ),
         564  +
        ]);
         565  +
        let client = ImdsCredentialsProvider::builder()
         566  +
            .imds_client(make_imds_client(&http_client))
         567  +
            .configure(&ProviderConfig::no_configuration())
         568  +
            .build();
         569  +
        let creds = client.provide_credentials().await.expect("valid creds");
         570  +
        assert_eq!(
         571  +
            &vec![AwsCredentialFeature::CredentialsImds],
         572  +
            creds.get_property::<Vec<AwsCredentialFeature>>().unwrap()
         573  +
        );
         574  +
    }
  532    575   
}

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/profile/credentials.rs

@@ -1,1 +60,61 @@
   21     21   
//!   build it from `~/.aws/credentials` and `~/.aws/config`.
   22     22   
//! - `exec` which contains a chain representation of providers to implement passing bootstrapped credentials
   23     23   
//!   through a series of providers.
   24     24   
   25     25   
use crate::profile::cell::ErrorTakingOnceCell;
   26     26   
#[allow(deprecated)]
   27     27   
use crate::profile::profile_file::ProfileFiles;
   28     28   
use crate::profile::Profile;
   29     29   
use crate::profile::ProfileFileLoadError;
   30     30   
use crate::provider_config::ProviderConfig;
          31  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
   31     32   
use aws_credential_types::{
   32     33   
    provider::{self, error::CredentialsError, future, ProvideCredentials},
   33     34   
    Credentials,
   34     35   
};
   35     36   
use aws_smithy_types::error::display::DisplayErrorContext;
   36     37   
use std::borrow::Cow;
   37     38   
use std::collections::HashMap;
   38     39   
use std::error::Error;
   39     40   
use std::fmt::{Display, Formatter};
   40     41   
use std::sync::Arc;
@@ -159,160 +219,225 @@
  179    180   
                                ))),
  180    181   
                            },
  181    182   
                        }
  182    183   
                    }
  183    184   
                },
  184    185   
                CredentialsError::unhandled(
  185    186   
                    "profile file credentials provider initialization error already taken",
  186    187   
                ),
  187    188   
            )
  188    189   
            .await?;
  189         -
        inner_provider.provide_credentials().await
         190  +
        inner_provider.provide_credentials().await.map(|mut creds| {
         191  +
            creds
         192  +
                .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
         193  +
                .push(AwsCredentialFeature::CredentialsProfile);
         194  +
            creds
         195  +
        })
  190    196   
    }
  191    197   
}
  192    198   
  193    199   
impl ProvideCredentials for ProfileFileCredentialsProvider {
  194    200   
    fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a>
  195    201   
    where
  196    202   
        Self: 'a,
  197    203   
    {
  198    204   
        future::ProvideCredentials::new(self.load_credentials())
  199    205   
    }
@@ -599,605 +767,801 @@
  619    625   
  620    626   
    make_test!(assume_role_override_global_env_url);
  621    627   
    make_test!(assume_role_override_service_env_url);
  622    628   
    make_test!(assume_role_override_global_profile_url);
  623    629   
    make_test!(assume_role_override_service_profile_url);
  624    630   
}
  625    631   
  626    632   
#[cfg(all(test, feature = "sso"))]
  627    633   
mod sso_tests {
  628    634   
    use crate::{profile::credentials::Builder, provider_config::ProviderConfig};
         635  +
    use aws_credential_types::credential_feature::AwsCredentialFeature;
  629    636   
    use aws_credential_types::provider::ProvideCredentials;
  630    637   
    use aws_sdk_sso::config::RuntimeComponents;
  631    638   
    use aws_smithy_runtime_api::client::{
  632    639   
        http::{
  633    640   
            HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings,
  634    641   
            SharedHttpConnector,
  635    642   
        },
  636    643   
        orchestrator::{HttpRequest, HttpResponse},
  637    644   
    };
  638    645   
    use aws_smithy_types::body::SdkBody;
  639    646   
    use aws_types::os_shim_internal::{Env, Fs};
  640    647   
    use std::collections::HashMap;
  641    648   
  642         -
    // TODO(https://github.com/awslabs/aws-sdk-rust/issues/1117) This test is ignored on Windows because it uses Unix-style paths
  643         -
    #[cfg_attr(windows, ignore)]
  644         -
    // In order to preserve the SSO token cache, the inner provider must only
  645         -
    // be created once, rather than once per credential resolution.
  646         -
    #[tokio::test]
  647         -
    async fn create_inner_provider_exactly_once() {
  648         -
        #[derive(Debug)]
  649         -
        struct ClientInner {
  650         -
            expected_token: &'static str,
  651         -
        }
  652         -
        impl HttpConnector for ClientInner {
  653         -
            fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
  654         -
                assert_eq!(
  655         -
                    self.expected_token,
  656         -
                    request.headers().get("x-amz-sso_bearer_token").unwrap()
  657         -
                );
  658         -
                HttpConnectorFuture::ready(Ok(HttpResponse::new(
         649  +
    #[derive(Debug)]
         650  +
    struct ClientInner {
         651  +
        expected_token: &'static str,
         652  +
    }
         653  +
    impl HttpConnector for ClientInner {
         654  +
        fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
         655  +
            assert_eq!(
         656  +
                self.expected_token,
         657  +
                request.headers().get("x-amz-sso_bearer_token").unwrap()
         658  +
            );
         659  +
            HttpConnectorFuture::ready(Ok(HttpResponse::new(
  659    660   
                    200.try_into().unwrap(),
  660    661   
                    SdkBody::from("{\"roleCredentials\":{\"accessKeyId\":\"ASIARTESTID\",\"secretAccessKey\":\"TESTSECRETKEY\",\"sessionToken\":\"TESTSESSIONTOKEN\",\"expiration\": 1651516560000}}"),
  661    662   
                )))
  662         -
            }
  663    663   
        }
  664         -
        #[derive(Debug)]
  665         -
        struct Client {
  666         -
            inner: SharedHttpConnector,
  667         -
        }
  668         -
        impl Client {
  669         -
            fn new(expected_token: &'static str) -> Self {
  670         -
                Self {
  671         -
                    inner: SharedHttpConnector::new(ClientInner { expected_token }),
  672         -
                }
         664  +
    }
         665  +
    #[derive(Debug)]
         666  +
    struct Client {
         667  +
        inner: SharedHttpConnector,
         668  +
    }
         669  +
    impl Client {
         670  +
        fn new(expected_token: &'static str) -> Self {
         671  +
            Self {
         672  +
                inner: SharedHttpConnector::new(ClientInner { expected_token }),
  673    673   
            }
  674    674   
        }
  675         -
        impl HttpClient for Client {
  676         -
            fn http_connector(
  677         -
                &self,
  678         -
                _settings: &HttpConnectorSettings,
  679         -
                _components: &RuntimeComponents,
  680         -
            ) -> SharedHttpConnector {
  681         -
                self.inner.clone()
  682         -
            }
         675  +
    }
         676  +
    impl HttpClient for Client {
         677  +
        fn http_connector(
         678  +
            &self,
         679  +
            _settings: &HttpConnectorSettings,
         680  +
            _components: &RuntimeComponents,
         681  +
        ) -> SharedHttpConnector {
         682  +
            self.inner.clone()
  683    683   
        }
         684  +
    }
  684    685   
  685         -
        let fs = Fs::from_map({
         686  +
    fn create_test_fs() -> Fs {
         687  +
        Fs::from_map({
  686    688   
            let mut map = HashMap::new();
  687    689   
            map.insert(
  688    690   
                "/home/.aws/config".to_string(),
  689    691   
                br#"
  690    692   
[profile default]
  691    693   
sso_session = dev
  692    694   
sso_account_id = 012345678901
  693    695   
sso_role_name = SampleRole
  694    696   
region = us-east-1
  695    697   
  696    698   
[sso-session dev]
  697    699   
sso_region = us-east-1
  698    700   
sso_start_url = https://d-abc123.awsapps.com/start
  699    701   
                "#
  700    702   
                .to_vec(),
  701    703   
            );
  702    704   
            map.insert(
  703    705   
                "/home/.aws/sso/cache/34c6fceca75e456f25e7e99531e2425c6c1de443.json".to_string(),
  704    706   
                br#"
  705    707   
                {
  706    708   
                    "accessToken": "secret-access-token",
  707    709   
                    "expiresAt": "2199-11-14T04:05:45Z",
  708    710   
                    "refreshToken": "secret-refresh-token",
  709    711   
                    "clientId": "ABCDEFG323242423121312312312312312",
  710    712   
                    "clientSecret": "ABCDE123",
  711    713   
                    "registrationExpiresAt": "2199-03-06T19:53:17Z",
  712    714   
                    "region": "us-east-1",
  713    715   
                    "startUrl": "https://d-abc123.awsapps.com/start"
  714    716   
                }
  715    717   
                "#
  716    718   
                .to_vec(),
  717    719   
            );
  718    720   
            map
  719         -
        });
         721  +
        })
         722  +
    }
         723  +
         724  +
    // TODO(https://github.com/awslabs/aws-sdk-rust/issues/1117) This test is ignored on Windows because it uses Unix-style paths
         725  +
    #[cfg_attr(windows, ignore)]
         726  +
    // In order to preserve the SSO token cache, the inner provider must only
         727  +
    // be created once, rather than once per credential resolution.
         728  +
    #[tokio::test]
         729  +
    async fn create_inner_provider_exactly_once() {
         730  +
        let fs = create_test_fs();
         731  +
  720    732   
        let provider_config = ProviderConfig::empty()
  721    733   
            .with_fs(fs.clone())
  722    734   
            .with_env(Env::from_slice(&[("HOME", "/home")]))
  723    735   
            .with_http_client(Client::new("secret-access-token"));
  724    736   
        let provider = Builder::default().configure(&provider_config).build();
  725    737   
  726    738   
        let first_creds = provider.provide_credentials().await.unwrap();
  727    739   
  728    740   
        // Write to the token cache with an access token that won't match the fake client's
  729    741   
        // expected access token, and thus, won't return SSO credentials.
  730    742   
        fs.write(
  731    743   
            "/home/.aws/sso/cache/34c6fceca75e456f25e7e99531e2425c6c1de443.json",
  732    744   
            r#"
  733    745   
            {
  734    746   
                "accessToken": "NEW!!secret-access-token",
  735    747   
                "expiresAt": "2199-11-14T04:05:45Z",
  736    748   
                "refreshToken": "secret-refresh-token",
  737    749   
                "clientId": "ABCDEFG323242423121312312312312312",
  738    750   
                "clientSecret": "ABCDE123",
  739    751   
                "registrationExpiresAt": "2199-03-06T19:53:17Z",
  740    752   
                "region": "us-east-1",
  741    753   
                "startUrl": "https://d-abc123.awsapps.com/start"
  742    754   
            }
  743    755   
            "#,
  744    756   
        )
  745    757   
        .await
  746    758   
        .unwrap();
  747    759   
  748    760   
        // Loading credentials will still work since the SSOTokenProvider should have only
  749    761   
        // been created once, and thus, the correct token is still in an in-memory cache.
  750    762   
        let second_creds = provider
  751    763   
            .provide_credentials()
  752    764   
            .await
  753    765   
            .expect("used cached token instead of loading from the file system");
  754    766   
        assert_eq!(first_creds, second_creds);
  755    767   
  756    768   
        // Now create a new provider, which should use the new cached token value from the file system
  757    769   
        // since it won't have the in-memory cache. We do this just to verify that the FS mutation above
  758    770   
        // actually worked correctly.
  759    771   
        let provider_config = ProviderConfig::empty()
  760    772   
            .with_fs(fs.clone())
  761    773   
            .with_env(Env::from_slice(&[("HOME", "/home")]))
  762    774   
            .with_http_client(Client::new("NEW!!secret-access-token"));
  763    775   
        let provider = Builder::default().configure(&provider_config).build();
  764    776   
        let third_creds = provider.provide_credentials().await.unwrap();
  765    777   
        assert_eq!(second_creds, third_creds);
  766    778   
    }
         779  +
         780  +
    #[cfg_attr(windows, ignore)]
         781  +
    #[tokio::test]
         782  +
    async fn credential_feature() {
         783  +
        let fs = create_test_fs();
         784  +
         785  +
        let provider_config = ProviderConfig::empty()
         786  +
            .with_fs(fs.clone())
         787  +
            .with_env(Env::from_slice(&[("HOME", "/home")]))
         788  +
            .with_http_client(Client::new("secret-access-token"));
         789  +
        let provider = Builder::default().configure(&provider_config).build();
         790  +
         791  +
        let creds = provider.provide_credentials().await.unwrap();
         792  +
         793  +
        assert_eq!(
         794  +
            &vec![
         795  +
                AwsCredentialFeature::CredentialsSso,
         796  +
                AwsCredentialFeature::CredentialsProfile
         797  +
            ],
         798  +
            creds.get_property::<Vec<AwsCredentialFeature>>().unwrap()
         799  +
        )
         800  +
    }
  767    801   
}

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/sso/credentials.rs

@@ -1,1 +46,47 @@
    7      7   
//!
    8      8   
//! This credentials provider enables loading credentials from `~/.aws/sso/cache`. For more information,
    9      9   
//! see [Using AWS SSO Credentials](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/sso-credentials.html)
   10     10   
//!
   11     11   
//! This provider is included automatically when profiles are loaded.
   12     12   
   13     13   
use super::cache::load_cached_token;
   14     14   
use crate::identity::IdentityCache;
   15     15   
use crate::provider_config::ProviderConfig;
   16     16   
use crate::sso::SsoTokenProvider;
          17  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
   17     18   
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
   18     19   
use aws_credential_types::Credentials;
   19     20   
use aws_sdk_sso::types::RoleCredentials;
   20     21   
use aws_sdk_sso::Client as SsoClient;
   21     22   
use aws_smithy_async::time::SharedTimeSource;
   22     23   
use aws_smithy_types::DateTime;
   23     24   
use aws_types::os_shim_internal::{Env, Fs};
   24     25   
use aws_types::region::Region;
   25     26   
use aws_types::SdkConfig;
   26     27   
@@ -61,62 +120,127 @@
   81     82   
    async fn credentials(&self) -> provider::Result {
   82     83   
        load_sso_credentials(
   83     84   
            &self.sso_provider_config,
   84     85   
            &self.sdk_config,
   85     86   
            self.token_provider.as_ref(),
   86     87   
            &self.env,
   87     88   
            &self.fs,
   88     89   
            self.time_source.clone(),
   89     90   
        )
   90     91   
        .await
          92  +
        .map(|mut creds| {
          93  +
            creds
          94  +
                .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
          95  +
                .push(AwsCredentialFeature::CredentialsSso);
          96  +
            creds
          97  +
        })
   91     98   
    }
   92     99   
}
   93    100   
   94    101   
impl ProvideCredentials for SsoCredentialsProvider {
   95    102   
    fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a>
   96    103   
    where
   97    104   
        Self: 'a,
   98    105   
    {
   99    106   
        future::ProvideCredentials::new(self.credentials())
  100    107   
    }

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/sts/assume_role.rs

@@ -1,1 +37,38 @@
    1      1   
/*
    2      2   
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    3      3   
 * SPDX-License-Identifier: Apache-2.0
    4      4   
 */
    5      5   
    6      6   
//! Assume credentials for a role through the AWS Security Token Service (STS).
    7      7   
           8  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
    8      9   
use aws_credential_types::provider::{
    9     10   
    self, error::CredentialsError, future, ProvideCredentials, SharedCredentialsProvider,
   10     11   
};
   11     12   
use aws_sdk_sts::operation::assume_role::builders::AssumeRoleFluentBuilder;
   12     13   
use aws_sdk_sts::operation::assume_role::AssumeRoleError;
   13     14   
use aws_sdk_sts::types::PolicyDescriptorType;
   14     15   
use aws_sdk_sts::Client as StsClient;
   15     16   
use aws_smithy_runtime::client::identity::IdentityCache;
   16     17   
use aws_smithy_runtime_api::client::result::SdkError;
   17     18   
use aws_smithy_types::error::display::DisplayErrorContext;
@@ -258,259 +365,374 @@
  278    279   
        self.sdk_config = Some(conf);
  279    280   
        self.build().await
  280    281   
    }
  281    282   
}
  282    283   
  283    284   
impl Inner {
  284    285   
    async fn credentials(&self) -> provider::Result {
  285    286   
        tracing::debug!("retrieving assumed credentials");
  286    287   
  287    288   
        let assumed = self.fluent_builder.clone().send().in_current_span().await;
  288         -
        match assumed {
         289  +
        let assumed = match assumed {
  289    290   
            Ok(assumed) => {
  290    291   
                tracing::debug!(
  291    292   
                    access_key_id = ?assumed.credentials.as_ref().map(|c| &c.access_key_id),
  292    293   
                    "obtained assumed credentials"
  293    294   
                );
  294    295   
                super::util::into_credentials(
  295    296   
                    assumed.credentials,
  296    297   
                    assumed.assumed_role_user,
  297    298   
                    "AssumeRoleProvider",
  298    299   
                )
  299    300   
            }
  300    301   
            Err(SdkError::ServiceError(ref context))
  301    302   
                if matches!(
  302    303   
                    context.err(),
  303    304   
                    AssumeRoleError::RegionDisabledException(_)
  304    305   
                        | AssumeRoleError::MalformedPolicyDocumentException(_)
  305    306   
                ) =>
  306    307   
            {
  307    308   
                Err(CredentialsError::invalid_configuration(
  308    309   
                    assumed.err().unwrap(),
  309    310   
                ))
  310    311   
            }
  311    312   
            Err(SdkError::ServiceError(ref context)) => {
  312    313   
                tracing::warn!(error = %DisplayErrorContext(context.err()), "STS refused to grant assume role");
  313    314   
                Err(CredentialsError::provider_error(assumed.err().unwrap()))
  314    315   
            }
  315    316   
            Err(err) => Err(CredentialsError::provider_error(err)),
  316         -
        }
         317  +
        };
         318  +
         319  +
        assumed.map(|mut creds| {
         320  +
            creds
         321  +
                .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
         322  +
                .push(AwsCredentialFeature::CredentialsStsAssumeRole);
         323  +
            creds
         324  +
        })
  317    325   
    }
  318    326   
}
  319    327   
  320    328   
impl ProvideCredentials for AssumeRoleProvider {
  321    329   
    fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a>
  322    330   
    where
  323    331   
        Self: 'a,
  324    332   
    {
  325    333   
        future::ProvideCredentials::new(
  326    334   
            self.inner
  327    335   
                .credentials()
  328    336   
                .instrument(tracing::debug_span!("assume_role")),
  329    337   
        )
  330    338   
    }
  331    339   
}
  332    340   
  333    341   
#[cfg(test)]
  334    342   
mod test {
  335    343   
    use crate::sts::AssumeRoleProvider;
         344  +
    use aws_credential_types::credential_feature::AwsCredentialFeature;
  336    345   
    use aws_credential_types::credential_fn::provide_credentials_fn;
  337    346   
    use aws_credential_types::provider::{ProvideCredentials, SharedCredentialsProvider};
  338    347   
    use aws_credential_types::Credentials;
  339    348   
    use aws_smithy_async::rt::sleep::{SharedAsyncSleep, TokioSleep};
  340    349   
    use aws_smithy_async::test_util::instant_time_and_sleep;
  341    350   
    use aws_smithy_async::time::StaticTimeSource;
  342    351   
    use aws_smithy_http_client::test_util::{capture_request, ReplayEvent, StaticReplayClient};
  343    352   
    use aws_smithy_runtime::test_util::capture_test_logs::capture_test_logs;
  344    353   
    use aws_smithy_runtime_api::client::behavior_version::BehaviorVersion;
  345    354   
    use aws_smithy_types::body::SdkBody;
@@ -416,425 +515,566 @@
  436    445   
        let auth_header = req.headers().get(AUTHORIZATION).unwrap().to_string();
  437    446   
        let expect = "Credential=123-key/20090213/us-west-17/sts/aws4_request";
  438    447   
        assert!(
  439    448   
            auth_header.contains(expect),
  440    449   
            "Expected header to contain {expect} but it was {auth_header}"
  441    450   
        );
  442    451   
        // ensure that FIPS & DualStack are also respected
  443    452   
        assert_eq!("https://sts-fips.us-west-17.api.aws/", req.uri())
  444    453   
    }
  445    454   
  446         -
    #[tokio::test]
  447         -
    async fn provider_does_not_cache_credentials_by_default() {
  448         -
        let http_client = StaticReplayClient::new(vec![
         455  +
    fn create_test_http_client() -> StaticReplayClient {
         456  +
        StaticReplayClient::new(vec![
  449    457   
            ReplayEvent::new(http::Request::new(SdkBody::from("request body")),
  450    458   
            http::Response::builder().status(200).body(SdkBody::from(
  451    459   
                "<AssumeRoleResponse xmlns=\"https://sts.amazonaws.com/doc/2011-06-15/\">\n  <AssumeRoleResult>\n    <AssumedRoleUser>\n      <AssumedRoleId>AROAR42TAWARILN3MNKUT:assume-role-from-profile-1632246085998</AssumedRoleId>\n      <Arn>arn:aws:sts::130633740322:assumed-role/assume-provider-test/assume-role-from-profile-1632246085998</Arn>\n    </AssumedRoleUser>\n    <Credentials>\n      <AccessKeyId>ASIARCORRECT</AccessKeyId>\n      <SecretAccessKey>secretkeycorrect</SecretAccessKey>\n      <SessionToken>tokencorrect</SessionToken>\n      <Expiration>2009-02-13T23:31:30Z</Expiration>\n    </Credentials>\n  </AssumeRoleResult>\n  <ResponseMetadata>\n    <RequestId>d9d47248-fd55-4686-ad7c-0fb7cd1cddd7</RequestId>\n  </ResponseMetadata>\n</AssumeRoleResponse>\n"
  452    460   
            )).unwrap()),
  453    461   
            ReplayEvent::new(http::Request::new(SdkBody::from("request body")),
  454    462   
            http::Response::builder().status(200).body(SdkBody::from(
  455    463   
                "<AssumeRoleResponse xmlns=\"https://sts.amazonaws.com/doc/2011-06-15/\">\n  <AssumeRoleResult>\n    <AssumedRoleUser>\n      <AssumedRoleId>AROAR42TAWARILN3MNKUT:assume-role-from-profile-1632246085998</AssumedRoleId>\n      <Arn>arn:aws:sts::130633740322:assumed-role/assume-provider-test/assume-role-from-profile-1632246085998</Arn>\n    </AssumedRoleUser>\n    <Credentials>\n      <AccessKeyId>ASIARCORRECT</AccessKeyId>\n      <SecretAccessKey>TESTSECRET</SecretAccessKey>\n      <SessionToken>tokencorrect</SessionToken>\n      <Expiration>2009-02-13T23:33:30Z</Expiration>\n    </Credentials>\n  </AssumeRoleResult>\n  <ResponseMetadata>\n    <RequestId>c2e971c2-702d-4124-9b1f-1670febbea18</RequestId>\n  </ResponseMetadata>\n</AssumeRoleResponse>\n"
  456    464   
            )).unwrap()),
  457         -
        ]);
         465  +
        ])
         466  +
    }
         467  +
         468  +
    #[tokio::test]
         469  +
    async fn provider_does_not_cache_credentials_by_default() {
         470  +
        let http_client = create_test_http_client();
  458    471   
  459    472   
        let (testing_time_source, sleep) = instant_time_and_sleep(
  460    473   
            UNIX_EPOCH + Duration::from_secs(1234567890 - 120), // 1234567890 since UNIX_EPOCH is 2009-02-13T23:31:30Z
  461    474   
        );
  462    475   
  463    476   
        let sdk_config = SdkConfig::builder()
  464    477   
            .sleep_impl(SharedAsyncSleep::new(sleep))
  465    478   
            .time_source(testing_time_source.clone())
  466    479   
            .http_client(http_client)
  467    480   
            .behavior_version(crate::BehaviorVersion::latest())
  468    481   
            .build();
  469    482   
        let credentials_list = std::sync::Arc::new(std::sync::Mutex::new(vec![
  470    483   
            Credentials::new(
  471    484   
                "test",
  472    485   
                "test",
  473    486   
                None,
  474    487   
                Some(UNIX_EPOCH + Duration::from_secs(1234567890 + 1)),
  475    488   
                "test",
  476    489   
            ),
  477    490   
            Credentials::new(
  478    491   
                "test",
  479    492   
                "test",
  480    493   
                None,
  481    494   
                Some(UNIX_EPOCH + Duration::from_secs(1234567890 + 120)),
  482    495   
                "test",
  483    496   
            ),
  484    497   
        ]));
  485    498   
        let credentials_list_cloned = credentials_list.clone();
  486    499   
        let provider = AssumeRoleProvider::builder("myrole")
  487    500   
            .configure(&sdk_config)
  488    501   
            .region(Region::new("us-east-1"))
  489    502   
            .build_from_provider(provide_credentials_fn(move || {
  490    503   
                let list = credentials_list.clone();
  491    504   
                async move {
  492    505   
                    let next = list.lock().unwrap().remove(0);
  493    506   
                    Ok(next)
  494    507   
                }
  495    508   
            }))
  496    509   
            .await;
  497    510   
  498    511   
        let creds_first = provider
  499    512   
            .provide_credentials()
  500    513   
            .await
  501    514   
            .expect("should return valid credentials");
  502    515   
  503    516   
        // After time has been advanced by 120 seconds, the first credentials _could_ still be valid
  504    517   
        // if `LazyCredentialsCache` were used, but the provider uses `NoCredentialsCache` by default
  505    518   
        // so the first credentials will not be used.
  506    519   
        testing_time_source.advance(Duration::from_secs(120));
  507    520   
  508    521   
        let creds_second = provider
  509    522   
            .provide_credentials()
  510    523   
            .await
  511    524   
            .expect("should return the second credentials");
  512    525   
        assert_ne!(creds_first, creds_second);
  513    526   
        assert!(credentials_list_cloned.lock().unwrap().is_empty());
  514    527   
    }
         528  +
         529  +
    #[tokio::test]
         530  +
    async fn credentials_feature() {
         531  +
        let http_client = create_test_http_client();
         532  +
         533  +
        let (testing_time_source, sleep) = instant_time_and_sleep(
         534  +
            UNIX_EPOCH + Duration::from_secs(1234567890), // 1234567890 since UNIX_EPOCH is 2009-02-13T23:31:30Z
         535  +
        );
         536  +
         537  +
        let sdk_config = SdkConfig::builder()
         538  +
            .sleep_impl(SharedAsyncSleep::new(sleep))
         539  +
            .time_source(testing_time_source.clone())
         540  +
            .http_client(http_client)
         541  +
            .behavior_version(crate::BehaviorVersion::latest())
         542  +
            .build();
         543  +
        let credentials = Credentials::new(
         544  +
            "test",
         545  +
            "test",
         546  +
            None,
         547  +
            Some(UNIX_EPOCH + Duration::from_secs(1234567890 + 1)),
         548  +
            "test",
         549  +
        );
         550  +
        let provider = AssumeRoleProvider::builder("myrole")
         551  +
            .configure(&sdk_config)
         552  +
            .region(Region::new("us-east-1"))
         553  +
            .build_from_provider(credentials)
         554  +
            .await;
         555  +
         556  +
        let creds = provider
         557  +
            .provide_credentials()
         558  +
            .await
         559  +
            .expect("should return valid credentials");
         560  +
         561  +
        assert_eq!(
         562  +
            &vec![AwsCredentialFeature::CredentialsStsAssumeRole],
         563  +
            creds.get_property::<Vec<AwsCredentialFeature>>().unwrap()
         564  +
        )
         565  +
    }
  515    566   
}

tmp-codegen-diff/aws-sdk/sdk/aws-config/src/web_identity_token.rs

@@ -36,36 +95,96 @@
   56     56   
//! use aws_config::web_identity_token::WebIdentityTokenCredentialsProvider;
   57     57   
//! use aws_config::provider_config::ProviderConfig;
   58     58   
//! let provider = WebIdentityTokenCredentialsProvider::builder()
   59     59   
//!     .configure(&ProviderConfig::with_default_region().await)
   60     60   
//!     .build();
   61     61   
//! # }
   62     62   
//! ```
   63     63   
   64     64   
use crate::provider_config::ProviderConfig;
   65     65   
use crate::sts;
          66  +
use aws_credential_types::credential_feature::AwsCredentialFeature;
   66     67   
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
   67     68   
use aws_sdk_sts::{types::PolicyDescriptorType, Client as StsClient};
   68     69   
use aws_smithy_async::time::SharedTimeSource;
   69     70   
use aws_smithy_types::error::display::DisplayErrorContext;
   70     71   
use aws_types::os_shim_internal::{Env, Fs};
   71     72   
   72     73   
use std::borrow::Cow;
   73     74   
use std::path::{Path, PathBuf};
   74     75   
   75     76   
const ENV_VAR_TOKEN_FILE: &str = "AWS_WEB_IDENTITY_TOKEN_FILE";
@@ -133,134 +192,199 @@
  153    154   
        load_credentials(
  154    155   
            &self.fs,
  155    156   
            &self.sts_client,
  156    157   
            self.policy.clone(),
  157    158   
            self.policy_arns.clone(),
  158    159   
            &conf.web_identity_token_file,
  159    160   
            &conf.role_arn,
  160    161   
            &conf.session_name,
  161    162   
        )
  162    163   
        .await
         164  +
        .map(|mut creds| {
         165  +
            creds
         166  +
                .get_property_mut_or_default::<Vec<AwsCredentialFeature>>()
         167  +
                .push(AwsCredentialFeature::CredentialsProfileStsWebIdToken);
         168  +
            creds
         169  +
        })
  163    170   
    }
  164    171   
}
  165    172   
  166    173   
/// Builder for [`WebIdentityTokenCredentialsProvider`].
  167    174   
#[derive(Debug, Default)]
  168    175   
pub struct Builder {
  169    176   
    source: Option<Source>,
  170    177   
    config: Option<ProviderConfig>,
  171    178   
    policy: Option<String>,
  172    179   
    policy_arns: Option<Vec<PolicyDescriptorType>>,

tmp-codegen-diff/aws-sdk/sdk/aws-credential-types/Cargo.toml

@@ -7,7 +49,49 @@
   27     27   
path = "../aws-smithy-async"
   28     28   
version = "1.2.5"
   29     29   
   30     30   
[dependencies.aws-smithy-types]
   31     31   
path = "../aws-smithy-types"
   32     32   
version = "1.3.2"
   33     33   
   34     34   
[dependencies.aws-smithy-runtime-api]
   35     35   
path = "../aws-smithy-runtime-api"
   36     36   
features = ["client", "http-auth"]
   37         -
version = "1.8.5"
          37  +
version = "1.8.6"
   38     38   
   39     39   
[dev-dependencies]
   40     40   
async-trait = "0.1.74"
   41     41   
   42     42   
[dev-dependencies.aws-smithy-runtime-api]
   43     43   
path = "../aws-smithy-runtime-api"
   44     44   
features = ["test-util"]
   45         -
version = "1.8.5"
          45  +
version = "1.8.6"
   46     46   
   47     47   
[dev-dependencies.tokio]
   48     48   
version = "1.23.1"
   49     49   
features = ["full", "test-util", "rt"]

tmp-codegen-diff/aws-sdk/sdk/aws-credential-types/src/credentials_impl.rs

@@ -69,69 +128,131 @@
   89     89   
                creds.field("expires_after", &formatted);
   90     90   
            } else {
   91     91   
                creds.field("expires_after", &expiry);
   92     92   
            }
   93     93   
        } else {
   94     94   
            creds.field("expires_after", &"never");
   95     95   
        }
   96     96   
        if let Some(account_id) = &self.0.account_id {
   97     97   
            creds.field("account_id", &account_id.as_str());
   98     98   
        }
          99  +
        for (i, prop) in self.1.values().enumerate() {
         100  +
            creds.field(&format!("property_{i}"), prop);
         101  +
        }
   99    102   
        creds.finish()
  100    103   
    }
  101    104   
}
  102    105   
  103    106   
#[cfg(feature = "hardcoded-credentials")]
  104    107   
const STATIC_CREDENTIALS: &str = "Static";
  105    108   
  106    109   
impl Credentials {
  107    110   
    /// Returns builder for `Credentials`.
  108    111   
    pub fn builder() -> CredentialsBuilder {