diff --git a/CMakeLists.txt b/CMakeLists.txt index 59c9cb14e4b..39d9106d8bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ if (LEGACY_BUILD) option(ENABLE_PROTOCOL_TESTS "Enable protocol tests" OFF) option(DISABLE_DNS_REQUIRED_TESTS "Disable unit tests that require DNS lookup to succeed, useful when using a http client that does not perform DNS lookup" OFF) option(AWS_APPSTORE_SAFE "Remove reference to private Apple APIs for AES GCM in Common Crypto. If set to OFF you application will get rejected from the apple app store." OFF) + option(AWS_ENABLE_CORE_INTEGRATION_TEST "Enables the core integration tests to be built which contains dependencies on other clients for setup and tear down" OFF) set(AWS_USER_AGENT_CUSTOMIZATION "" CACHE STRING "User agent extension") diff --git a/cmake/sdksCommon.cmake b/cmake/sdksCommon.cmake index 5f4380af730..229940fc7f6 100644 --- a/cmake/sdksCommon.cmake +++ b/cmake/sdksCommon.cmake @@ -87,7 +87,11 @@ list(APPEND HIGH_LEVEL_SDK_LIST "text-to-speech") set(SDK_TEST_PROJECT_LIST "") list(APPEND SDK_TEST_PROJECT_LIST "cloudfront:tests/aws-cpp-sdk-cloudfront-integration-tests") list(APPEND SDK_TEST_PROJECT_LIST "cognito-identity:tests/aws-cpp-sdk-cognitoidentity-integration-tests") -list(APPEND SDK_TEST_PROJECT_LIST "core:tests/aws-cpp-sdk-core-tests") +if (AWS_ENABLE_CORE_INTEGRATION_TEST) + list(APPEND SDK_TEST_PROJECT_LIST "core:tests/aws-cpp-sdk-core-tests,tests/aws-cpp-sdk-core-integration-tests") +else () + list(APPEND SDK_TEST_PROJECT_LIST "core:tests/aws-cpp-sdk-core-tests") +endif () list(APPEND SDK_TEST_PROJECT_LIST "dynamodb:tests/aws-cpp-sdk-dynamodb-integration-tests") list(APPEND SDK_TEST_PROJECT_LIST "dynamodb:tests/aws-cpp-sdk-dynamodb-unit-tests") list(APPEND SDK_TEST_PROJECT_LIST "ec2:tests/aws-cpp-sdk-ec2-integration-tests") @@ -146,6 +150,9 @@ list(APPEND TEST_DEPENDENCY_LIST "sqs:access-management,cognito-identity,iam,cor list(APPEND TEST_DEPENDENCY_LIST "text-to-speech:polly,core") list(APPEND TEST_DEPENDENCY_LIST "transfer:s3,core") list(APPEND TEST_DEPENDENCY_LIST "logs:access-management,cognito-identity,iam,core") +if (AWS_ENABLE_CORE_INTEGRATION_TEST) + list(APPEND TEST_DEPENDENCY_LIST "core:sts,iam,cognito-identity") +endif () set(GENERATED_SERVICE_LIST ${SERVICE_CLIENT_LIST}) foreach(SERVICE_NAME IN LISTS SERVICE_CLIENT_LIST) diff --git a/src/aws-cpp-sdk-core/include/aws/core/Globals.h b/src/aws-cpp-sdk-core/include/aws/core/Globals.h index 08dfafce09d..7a45ddaeb0d 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/Globals.h +++ b/src/aws-cpp-sdk-core/include/aws/core/Globals.h @@ -6,6 +6,7 @@ #pragma once #include +#include namespace Aws { diff --git a/src/aws-cpp-sdk-core/include/aws/core/auth/STSCredentialsProvider.h b/src/aws-cpp-sdk-core/include/aws/core/auth/STSCredentialsProvider.h index fbac3009b05..8156caf5f98 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/auth/STSCredentialsProvider.h +++ b/src/aws-cpp-sdk-core/include/aws/core/auth/STSCredentialsProvider.h @@ -7,11 +7,15 @@ #pragma once #include -#include -#include -#include #include -#include + +namespace Aws { +namespace Crt { +namespace Auth { +class ICredentialsProvider; +} +} +} namespace Aws { @@ -27,6 +31,7 @@ namespace Aws public: STSAssumeRoleWebIdentityCredentialsProvider(); STSAssumeRoleWebIdentityCredentialsProvider(Aws::Client::ClientConfiguration::CredentialProviderConfiguration config); + virtual ~STSAssumeRoleWebIdentityCredentialsProvider(); /** * Retrieves the credentials if found, otherwise returns empty credential set. @@ -37,17 +42,14 @@ namespace Aws void Reload() override; private: - void RefreshIfExpired(); - Aws::String CalculateQueryString() const; - - Aws::UniquePtr m_client; - Aws::Auth::AWSCredentials m_credentials; - Aws::String m_roleArn; - Aws::String m_tokenFile; - Aws::String m_sessionName; - Aws::String m_token; - bool m_initialized; - bool ExpiresSoon() const; + enum class STATE { + INITIALIZED, + SHUT_DOWN, + } m_state{STATE::SHUT_DOWN}; + std::mutex m_refreshMutex; + std::condition_variable m_refreshSignal; + std::shared_ptr m_credentialsProvider; + std::chrono::milliseconds m_providerFuturesTimeoutMs; }; } // namespace Auth } // namespace Aws diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h index 4e9e34fd1a3..7727c493a1d 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h @@ -519,7 +519,33 @@ namespace Aws bool disableImdsV1; bool disableImds; } imdsConfig; - }credentialProviderConfig; + + /** + * Configuration for the STSCredentials provider + */ + struct STSCredentialsCredentialProviderConfiguration { + STSCredentialsCredentialProviderConfiguration() = default; + STSCredentialsCredentialProviderConfiguration(const Aws::String& role, const Aws::String& session, const String& tokenFile) + : roleArn(role), sessionName(session), tokenFilePath(tokenFile) {}; + /** + * Arn of the role to assume by fetching credentials for + */ + Aws::String roleArn; + /** + * Assumed role session identifier to be associated with the sourced credentials + */ + Aws::String sessionName; + /** + * The OAuth 2.0 access token or OpenID Connect ID token + */ + Aws::String tokenFilePath; + + /** + * Time out for the credentials future call. + */ + std::chrono::milliseconds retrieveCredentialsFutureTimeout = std::chrono::seconds(10); + } stsCredentialsProviderConfig; + } credentialProviderConfig; }; /** diff --git a/src/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp b/src/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp index 15a6931bcff..ddf0fbf89de 100644 --- a/src/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp +++ b/src/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp @@ -2,166 +2,111 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ - - +#include #include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include -using namespace Aws::Utils; -using namespace Aws::Utils::Logging; using namespace Aws::Auth; -using namespace Aws::Internal; -using namespace Aws::FileSystem; -using namespace Aws::Client; -using Aws::Utils::Threading::ReaderLockGuard; -using Aws::Utils::Threading::WriterLockGuard; +using namespace Aws::Utils; -static const char STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG[] = "STSAssumeRoleWithWebIdentityCredentialsProvider"; -static const int STS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD = 5 * 60 * 1000; // 5 Minutes. +namespace { +const char* STS_LOG_TAG = "STSAssumeRoleWebIdentityCredentialsProvider"; +} -STSAssumeRoleWebIdentityCredentialsProvider::STSAssumeRoleWebIdentityCredentialsProvider(Aws::Client::ClientConfiguration::CredentialProviderConfiguration credentialsConfig): - m_initialized(false) +STSAssumeRoleWebIdentityCredentialsProvider::STSAssumeRoleWebIdentityCredentialsProvider( + Aws::Client::ClientConfiguration::CredentialProviderConfiguration credentialsConfig) + : m_credentialsProvider(nullptr), m_providerFuturesTimeoutMs(credentialsConfig.stsCredentialsProviderConfig.retrieveCredentialsFutureTimeout) { - m_roleArn = Aws::Environment::GetEnv("AWS_ROLE_ARN"); - m_tokenFile = Aws::Environment::GetEnv("AWS_WEB_IDENTITY_TOKEN_FILE"); - m_sessionName = Aws::Environment::GetEnv("AWS_ROLE_SESSION_NAME"); - - // check profile_config if either m_roleArn or m_tokenFile is not loaded from environment variable - // region source is not enforced, but we need it to construct sts endpoint, if we can't find from environment, we should check if it's set in config file. - if (m_roleArn.empty() || m_tokenFile.empty()) - { - auto profile = Aws::Config::GetCachedConfigProfile(credentialsConfig.profile); - // If either of these two were not found from environment, use whatever found for all three in config file - if (m_roleArn.empty() || m_tokenFile.empty()) - { - m_roleArn = profile.GetRoleArn(); - m_tokenFile = profile.GetValue("web_identity_token_file"); - m_sessionName = profile.GetValue("role_session_name"); - } - } - - if (m_tokenFile.empty()) - { - AWS_LOGSTREAM_WARN(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Token file must be specified to use STS AssumeRole web identity creds provider."); - return; // No need to do further constructing - } - else - { - AWS_LOGSTREAM_DEBUG(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Resolved token_file from profile_config or environment variable to be " << m_tokenFile); - } - - if (m_roleArn.empty()) - { - AWS_LOGSTREAM_WARN(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "RoleArn must be specified to use STS AssumeRole web identity creds provider."); - return; // No need to do further constructing - } - else - { - AWS_LOGSTREAM_DEBUG(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Resolved role_arn from profile_config or environment variable to be " << m_roleArn); - } - - if (m_sessionName.empty()) - { - m_sessionName = Aws::Utils::UUID::PseudoRandomUUID(); - } - else - { - AWS_LOGSTREAM_DEBUG(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Resolved session_name from profile_config or environment variable to be " << m_sessionName); + Aws::Crt::Auth::CredentialsProviderSTSWebIdentityConfig stsConfig{}; + stsConfig.Bootstrap = GetDefaultClientBootstrap(); + Aws::Crt::Io::TlsContextOptions tlsCtxOptions = Aws::Crt::Io::TlsContextOptions::InitDefaultClient(); + const Aws::Crt::Io::TlsContext tlsContext(tlsCtxOptions, Aws::Crt::Io::TlsMode::CLIENT); + const auto tlsOptions = Aws::GetDefaultTlsConnectionOptions(); + if (tlsOptions) { + stsConfig.TlsConnectionOptions = *tlsOptions; + } + stsConfig.Region = credentialsConfig.region.c_str(); + stsConfig.TokenFilePath = credentialsConfig.stsCredentialsProviderConfig.tokenFilePath.c_str(); + stsConfig.RoleArn = credentialsConfig.stsCredentialsProviderConfig.roleArn.c_str(); + stsConfig.SessionName = [&credentialsConfig]() -> Aws::String { + if (!credentialsConfig.stsCredentialsProviderConfig.sessionName.empty()) { + return credentialsConfig.stsCredentialsProviderConfig.sessionName; } - - Aws::Client::ClientConfiguration config; - config.scheme = Aws::Http::Scheme::HTTPS; - config.region = credentialsConfig.region; - Aws::Vector retryableErrors; - retryableErrors.push_back("IDPCommunicationError"); - retryableErrors.push_back("InvalidIdentityToken"); - - config.retryStrategy = Aws::MakeShared(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, retryableErrors, 3/*maxRetries*/); - - m_client = Aws::MakeUnique(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, config); - m_initialized = true; - AWS_LOGSTREAM_INFO(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Creating STS AssumeRole with web identity creds provider."); + return UUID::RandomUUID(); + }().c_str(); + m_credentialsProvider = Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderSTSWebIdentity(stsConfig); + if (m_credentialsProvider && m_credentialsProvider->IsValid()) { + m_state = STATE::INITIALIZED; + } else { + AWS_LOGSTREAM_WARN(STS_LOG_TAG, "Failed to create STS credentials provider"); + } } -Aws::String LegacyGetRegion() { - auto region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); - if (region.empty()) { +Aws::String GetLegacySettingFromEnvOrProfile(const Aws::String& envVar, + std::function profileFetchFunction) +{ + auto value = Aws::Environment::GetEnv(envVar.c_str()); + if (value.empty()) { auto profile = Aws::Config::GetCachedConfigProfile(Aws::Auth::GetConfigProfileName()); - region = profile.GetRegion(); + value = profileFetchFunction(profile); } - return region; + return value; } STSAssumeRoleWebIdentityCredentialsProvider::STSAssumeRoleWebIdentityCredentialsProvider() : STSAssumeRoleWebIdentityCredentialsProvider( - Aws::Client::ClientConfiguration::CredentialProviderConfiguration{Aws::Auth::GetConfigProfileName(), LegacyGetRegion(), {}}) {} - -AWSCredentials STSAssumeRoleWebIdentityCredentialsProvider::GetAWSCredentials() -{ - // A valid client means required information like role arn and token file were constructed correctly. - // We can use this provider to load creds, otherwise, we can just return empty creds. - if (!m_initialized) - { - return Aws::Auth::AWSCredentials(); - } - RefreshIfExpired(); - ReaderLockGuard guard(m_reloadLock); - return m_credentials; -} - -void STSAssumeRoleWebIdentityCredentialsProvider::Reload() -{ - AWS_LOGSTREAM_INFO(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Credentials have expired, attempting to renew from STS."); - - Aws::IFStream tokenFile(m_tokenFile.c_str()); - if(tokenFile) - { - Aws::String token((std::istreambuf_iterator(tokenFile)), std::istreambuf_iterator()); - m_token = token; - } - else - { - AWS_LOGSTREAM_ERROR(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Can't open token file: " << m_tokenFile); - return; - } - STSCredentialsClient::STSAssumeRoleWithWebIdentityRequest request {m_sessionName, m_roleArn, m_token}; - - auto result = m_client->GetAssumeRoleWithWebIdentityCredentials(request); - AWS_LOGSTREAM_TRACE(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Successfully retrieved credentials with AWS_ACCESS_KEY: " << result.creds.GetAWSAccessKeyId()); - m_credentials = result.creds; -} + Aws::Client::ClientConfiguration::CredentialProviderConfiguration{ + Aws::Auth::GetConfigProfileName(), + GetLegacySettingFromEnvOrProfile("AWS_DEFAULT_REGION", + [](const Aws::Config::Profile& profile) -> Aws::String { return profile.GetRegion(); }), + {}, + { + GetLegacySettingFromEnvOrProfile("AWS_ROLE_ARN", + [](const Aws::Config::Profile& profile) -> Aws::String { return profile.GetRoleArn(); }), + GetLegacySettingFromEnvOrProfile("AWS_ROLE_SESSION_NAME", + [](const Aws::Config::Profile& profile) -> Aws::String { return profile.GetValue("role_session_name"); }), + GetLegacySettingFromEnvOrProfile("AWS_WEB_IDENTITY_TOKEN_FILE", + [](const Aws::Config::Profile& profile) -> Aws::String { return profile.GetValue("web_identity_token_file"); }) + }}) +{} + +STSAssumeRoleWebIdentityCredentialsProvider::~STSAssumeRoleWebIdentityCredentialsProvider() = default; + +AWSCredentials STSAssumeRoleWebIdentityCredentialsProvider::GetAWSCredentials() { + if (m_state != STATE::INITIALIZED) { + AWS_LOGSTREAM_DEBUG(STS_LOG_TAG, "STSCredentialsProvider is not initialized, returning empty credentials"); + return AWSCredentials{}; + } + AWSCredentials credentials{}; + auto refreshDone = false; + m_credentialsProvider->GetCredentials( + [this, &credentials, &refreshDone](std::shared_ptr crtCredentials, int errorCode) -> void { + { + const std::unique_lock lock{m_refreshMutex}; + if (errorCode != AWS_ERROR_SUCCESS) { + AWS_LOGSTREAM_ERROR(STS_LOG_TAG, "Failed to get credentials from STS: " << errorCode); + } else { + const auto accountIdCursor = crtCredentials->GetAccessKeyId(); + credentials.SetAWSAccessKeyId({reinterpret_cast(accountIdCursor.ptr), accountIdCursor.len}); + const auto secretKeuCursor = crtCredentials->GetSecretAccessKey(); + credentials.SetAWSSecretKey({reinterpret_cast(secretKeuCursor.ptr), secretKeuCursor.len}); + const auto expiration = crtCredentials->GetExpirationTimepointInSeconds(); + credentials.SetExpiration(DateTime{static_cast(expiration)}); + const auto sessionTokenCursor = crtCredentials->GetSessionToken(); + credentials.SetSessionToken({reinterpret_cast(sessionTokenCursor.ptr), sessionTokenCursor.len}); + } + refreshDone = true; + } + m_refreshSignal.notify_one(); + }); -bool STSAssumeRoleWebIdentityCredentialsProvider::ExpiresSoon() const -{ - return ((m_credentials.GetExpiration() - Aws::Utils::DateTime::Now()).count() < STS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD); + std::unique_lock lock{m_refreshMutex}; + m_refreshSignal.wait_for(lock, m_providerFuturesTimeoutMs, [&refreshDone]() -> bool { return refreshDone; }); + return credentials; } -void STSAssumeRoleWebIdentityCredentialsProvider::RefreshIfExpired() -{ - ReaderLockGuard guard(m_reloadLock); - if (!m_credentials.IsEmpty() && !ExpiresSoon()) - { - return; - } - - guard.UpgradeToWriterLock(); - if (!m_credentials.IsExpiredOrEmpty() && !ExpiresSoon()) // double-checked lock to avoid refreshing twice - { - return; - } - - Reload(); +void STSAssumeRoleWebIdentityCredentialsProvider::Reload() { + AWS_LOGSTREAM_DEBUG(STS_LOG_TAG, "Calling reload on STSCredentialsProvider is a no-op and no longer in the call path"); } diff --git a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp index d08d981deda..5513c03b2cc 100644 --- a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp +++ b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp @@ -45,6 +45,12 @@ static const char* AWS_METADATA_SERVICE_TIMEOUT_ENV_VAR = "AWS_METADATA_SERVICE_ static const char* AWS_METADATA_SERVICE_TIMEOUT_CONFIG_VAR = "metadata_service_timeout"; static const char* AWS_METADATA_SERVICE_NUM_ATTEMPTS_ENV_VAR = "AWS_METADATA_SERVICE_NUM_ATTEMPTS"; static const char* AWS_METADATA_SERVICE_NUM_ATTEMPTS_CONFIG_VAR = "metadata_service_num_attempts"; +static const char* AWS_IAM_ROLE_ARN_ENV_VAR = "AWS_IAM_ROLE_ARN"; +static const char* AWS_IAM_ROLE_ARN_CONFIG_FILE_OPTION = "role_arn"; +static const char* AWS_IAM_ROLE_SESSION_NAME_ENV_VAR = "AWS_IAM_ROLE_SESSION_NAME"; +static const char* AWS_IAM_ROLE_SESSION_NAME_CONFIG_FILE_OPTION = "role_session_name"; +static const char* AWS_WEB_IDENTITY_TOKEN_FILE_ENV_VAR = "AWS_WEB_IDENTITY_TOKEN_FILE"; +static const char* AWS_WEB_IDENTITY_TOKEN_FILE_CONFIG_FILE_OPTION = "web_identity_token_file"; using RequestChecksumConfigurationEnumMapping = std::pair; static const std::array REQUEST_CHECKSUM_CONFIG_MAPPING = {{ @@ -320,6 +326,24 @@ void setConfigFromEnvOrProfile(ClientConfiguration &config) // Initialize IMDS-specific retry strategy with configured number of attempts // Uses default retry mode with the specified max attempts from metadata_service_num_attempts config.credentialProviderConfig.imdsConfig.imdsRetryStrategy = InitRetryStrategy(attempts, ""); + + config.credentialProviderConfig.stsCredentialsProviderConfig.roleArn = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_IAM_ROLE_ARN_ENV_VAR, + config.profileName, + AWS_IAM_ROLE_ARN_CONFIG_FILE_OPTION, + {}, /* allowed values */ + "" /* default value */); + + config.credentialProviderConfig.stsCredentialsProviderConfig.sessionName = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_IAM_ROLE_SESSION_NAME_ENV_VAR, + config.profileName, + AWS_IAM_ROLE_SESSION_NAME_CONFIG_FILE_OPTION, + {}, /* allowed values */ + "" /* default value */); + + config.credentialProviderConfig.stsCredentialsProviderConfig.tokenFilePath = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_WEB_IDENTITY_TOKEN_FILE_ENV_VAR, + config.profileName, + AWS_WEB_IDENTITY_TOKEN_FILE_CONFIG_FILE_OPTION, + {}, /* allowed values */ + "" /* default value */); } ClientConfiguration::ClientConfiguration() diff --git a/tests/aws-cpp-sdk-core-integration-tests/CMakeLists.txt b/tests/aws-cpp-sdk-core-integration-tests/CMakeLists.txt new file mode 100644 index 00000000000..561948a0281 --- /dev/null +++ b/tests/aws-cpp-sdk-core-integration-tests/CMakeLists.txt @@ -0,0 +1,35 @@ +add_project(aws-cpp-sdk-core-integration-tests + "Integration tests for core components" + testing-resources + aws_test_main + aws-cpp-sdk-core + aws-cpp-sdk-cognito-identity + aws-cpp-sdk-sts + aws-cpp-sdk-iam) + +add_definitions(-DRESOURCES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/resources") + +if(MSVC AND BUILD_SHARED_LIBS) + add_definitions(-DGTEST_LINKED_AS_SHARED_LIBRARY=1) +endif() + +enable_testing() + +if(PLATFORM_ANDROID AND BUILD_SHARED_LIBS) + add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/STSWebIdentityProviderIntegrationTest.cpp) +else() + add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/STSWebIdentityProviderIntegrationTest.cpp) +endif() + +set_compiler_flags(${PROJECT_NAME}) +set_compiler_warnings(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBS}) + +if(MSVC AND BUILD_SHARED_LIBS) + set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/DELAYLOAD:aws-cpp-sdk-cognito-identity.dll /DELAYLOAD:aws-cpp-sdk-sts.dll /DELAYLOAD:aws-cpp-sdk-iam.dll /DELAYLOAD:aws-cpp-sdk-core.dll") + target_link_libraries(${PROJECT_NAME} delayimp.lib) +endif() + +include(GoogleTest) +gtest_add_tests(TARGET ${PROJECT_NAME}) diff --git a/tests/aws-cpp-sdk-core-integration-tests/STSWebIdentityProviderIntegrationTest.cpp b/tests/aws-cpp-sdk-core-integration-tests/STSWebIdentityProviderIntegrationTest.cpp new file mode 100644 index 00000000000..a8d489924ac --- /dev/null +++ b/tests/aws-cpp-sdk-core-integration-tests/STSWebIdentityProviderIntegrationTest.cpp @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Auth; +using namespace Aws::Utils; +using namespace Aws::IAM; +using namespace Aws::IAM::Model; +using namespace Aws::STS; +using namespace Aws::STS::Model; +using namespace Aws::CognitoIdentity; +using namespace Aws::CognitoIdentity::Model; + +namespace { +const char* TRUST_POLICY = R"({"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Federated":"cognito-identity.amazonaws.com"},"Action":"sts:AssumeRoleWithWebIdentity","Condition":{"StringEquals":{"cognito-identity.amazonaws.com:aud":"IDENTITY_POOL_ID_PLACEHOLDER"},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}},{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::TEST_ACCOUNT_ID:root"},"Action":"sts:AssumeRole"}]})"; +const char* ALLOW_S3_POLICY = R"({"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject","s3:ListBucket"],"Resource":["arn:aws:s3:::example-bucket/*","arn:aws:s3:::example-bucket"]}]})"; +// If it takes longer than 60s for a IAM role to be consistent -- thats a problem +// and we likely want to move on and fail the test +const std::chrono::milliseconds IAM_CONSISTENCY_SLEEP = std::chrono::seconds(1); +const size_t MAX_IAM_CONSISTENCY_RETRIES = 60; +} + +class CognitoIdentitySetup { + public: + CognitoIdentitySetup(const Aws::String& testIdentifier) + : m_tokenFile{std::ios_base::out | std::ios_base::trunc}, + m_roleName{"WebIdentityTestRole" + testIdentifier}, + m_policyName{"WebIdentityTestPolicy" + testIdentifier}, + m_poolName{"WebIdentityTestPool" + testIdentifier} { + const auto identityPoolResponse = m_cognitoIdentityClient.CreateIdentityPool(CreateIdentityPoolRequest{} + .WithIdentityPoolName(m_poolName) + .WithAllowUnauthenticatedIdentities(true)); + AWS_EXPECT_SUCCESS(identityPoolResponse); + m_identityPoolId = identityPoolResponse.GetResult().GetIdentityPoolId(); + Aws::String trustPolicyWithID{TRUST_POLICY}; + Aws::Utils::StringUtils::Replace(trustPolicyWithID, "IDENTITY_POOL_ID_PLACEHOLDER", m_identityPoolId.c_str()); + Aws::Utils::StringUtils::Replace(trustPolicyWithID, "TEST_ACCOUNT_ID", Aws::Environment::GetEnv("CATAPULT_TEST_ACCOUNT").c_str()); + + const auto createRoleResponse = m_iamClient.CreateRole(CreateRoleRequest{} + .WithRoleName(m_roleName) + .WithAssumeRolePolicyDocument(trustPolicyWithID)); + AWS_EXPECT_SUCCESS(createRoleResponse); + m_roleArn = createRoleResponse.GetResult().GetRole().GetArn(); + + const auto updateRoleResponse = m_iamClient.PutRolePolicy(PutRolePolicyRequest{} + .WithRoleName(m_roleName) + .WithPolicyName(m_policyName) + .WithPolicyDocument(ALLOW_S3_POLICY)); + AWS_EXPECT_SUCCESS(updateRoleResponse); + + // Force read after write consistency + AssumeRoleOutcome assumeRoleResponse; + size_t attempts = 0; + bool shouldSleep = false; + do { + if (shouldSleep) { + std::this_thread::sleep_for(IAM_CONSISTENCY_SLEEP); + } + assumeRoleResponse = m_stsClient.AssumeRole(AssumeRoleRequest{} + .WithRoleArn(m_roleArn) + .WithRoleSessionName("test")); + shouldSleep = true; + } while (!assumeRoleResponse.IsSuccess() && attempts++ < MAX_IAM_CONSISTENCY_RETRIES); + AWS_EXPECT_SUCCESS(assumeRoleResponse); + + const auto setIdentityPoolRulesResponse = m_cognitoIdentityClient.SetIdentityPoolRoles(SetIdentityPoolRolesRequest{} + .WithIdentityPoolId(m_identityPoolId) + .WithRoles({ + {"unauthenticated", m_roleArn} + })); + AWS_EXPECT_SUCCESS(setIdentityPoolRulesResponse); + + const auto getPoolIdResponse = m_cognitoIdentityClient.GetId(GetIdRequest{}.WithIdentityPoolId(m_identityPoolId)); + AWS_EXPECT_SUCCESS(getPoolIdResponse); + + const auto identityId = getPoolIdResponse.GetResult().GetIdentityId(); + + const auto getTokenResponse = m_cognitoIdentityClient.GetOpenIdToken(GetOpenIdTokenRequest{}.WithIdentityId(identityId)); + AWS_EXPECT_SUCCESS(getTokenResponse); + + const auto token = getTokenResponse.GetResult().GetToken(); + EXPECT_TRUE(m_tokenFile.good()); + m_tokenFile << token << std::endl; + m_tokenFile.close(); + } + + ~CognitoIdentitySetup() { + const auto deletePoolResponse = m_cognitoIdentityClient.DeleteIdentityPool(DeleteIdentityPoolRequest{} + .WithIdentityPoolId(m_identityPoolId)); + AWS_EXPECT_SUCCESS(deletePoolResponse); + + const auto deleteRolePolicyResponse = m_iamClient.DeleteRolePolicy(DeleteRolePolicyRequest{} + .WithRoleName(m_roleName) + .WithPolicyName(m_policyName)); + AWS_EXPECT_SUCCESS(deleteRolePolicyResponse); + + const auto deleteRoleResponse = m_iamClient.DeleteRole(DeleteRoleRequest{}.WithRoleName(m_roleName)); + AWS_EXPECT_SUCCESS(deleteRoleResponse); + } + + Aws::String GetRoleArn() { + return m_roleArn; + } + + Aws::String GetTokenFileName() { + return m_tokenFile.GetFileName(); + } + + private: + IAMClient m_iamClient; + STSClient m_stsClient; + CognitoIdentityClient m_cognitoIdentityClient; + TempFile m_tokenFile; + Aws::String m_roleName; + Aws::String m_policyName; + Aws::String m_poolName; + Aws::String m_roleArn; + Aws::String m_identityPoolId; +}; + +class STSWebIdentityProviderIntegrationTest : public testing::Test { + protected: + STSWebIdentityProviderIntegrationTest() { + m_options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; + InitAPI(m_options); + } + + ~STSWebIdentityProviderIntegrationTest() { + ShutdownAPI(m_options); + } + + SDKOptions m_options; +}; + +TEST_F(STSWebIdentityProviderIntegrationTest, ShouldWork) { + CognitoIdentitySetup testResourcesRAII{UUID::RandomUUID()}; + ClientConfiguration config; + config.credentialProviderConfig.region = config.region; + config.credentialProviderConfig.stsCredentialsProviderConfig.roleArn = testResourcesRAII.GetRoleArn(); + config.credentialProviderConfig.stsCredentialsProviderConfig.tokenFilePath = testResourcesRAII.GetTokenFileName(); + STSAssumeRoleWebIdentityCredentialsProvider provider{config.credentialProviderConfig}; + const auto credentials = provider.GetAWSCredentials(); + EXPECT_FALSE(credentials.IsEmpty()); +} diff --git a/tests/aws-cpp-sdk-core-tests/aws/auth/AWSCredentialsProviderTest.cpp b/tests/aws-cpp-sdk-core-tests/aws/auth/AWSCredentialsProviderTest.cpp index 6895ddf6b82..ae06724a8c9 100644 --- a/tests/aws-cpp-sdk-core-tests/aws/auth/AWSCredentialsProviderTest.cpp +++ b/tests/aws-cpp-sdk-core-tests/aws/auth/AWSCredentialsProviderTest.cpp @@ -3,25 +3,26 @@ * SPDX-License-Identifier: Apache-2.0. */ -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include +#include + #include -#include -#include +#include static const char *AllocationTag = "AWSCredentialsProviderTest"; @@ -573,220 +574,6 @@ TEST_F(ProcessCredentialsProviderTest, TestProcessCredentialsProviderCaptureInva Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); } -class STSAssumeRoleWithWebIdentityCredentialsProviderTest :public ProcessCredentialsProviderTest -{ -public: - void SetUp() - { - SaveEnvironmentVariable("AWS_CONFIG_FILE"); - SaveEnvironmentVariable("AWS_DEFAULT_PROFILE"); - SaveEnvironmentVariable("AWS_PROFILE"); - SaveEnvironmentVariable("AWS_WEB_IDENTITY_TOKEN_FILE"); - SaveEnvironmentVariable("AWS_ROLE_ARN"); - SaveEnvironmentVariable("AWS_DEFAULT_REGION"); - - Aws::StringStream ss; - ss << Aws::Auth::GetConfigProfileFilename() + "_blah" << std::this_thread::get_id(); - m_configFileName = ss.str(); - Aws::Environment::SetEnv("AWS_CONFIG_FILE", m_configFileName.c_str(), 1); - Aws::Environment::UnSetEnv("AWS_DEFAULT_PROFILE"); - Aws::Environment::UnSetEnv("AWS_PROFILE"); - // avoid reading region environment var when testing get correct region from config file - Aws::Environment::UnSetEnv("AWS_DEFAULT_REGION"); - - auto profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory(); - Aws::FileSystem::CreateDirectoryIfNotExists(profileDirectory.c_str()); - - mockHttpClient = Aws::MakeShared(AllocationTag); - mockHttpClientFactory = Aws::MakeShared(AllocationTag); - mockHttpClientFactory->SetClient(mockHttpClient); - SetHttpClientFactory(mockHttpClientFactory); - } - - void TearDown() - { - RestoreEnvironmentVariables(); - mockHttpClient = nullptr; - mockHttpClientFactory = nullptr; - - CleanupHttp(); - InitHttp(); - } - - std::shared_ptr mockHttpClient; - std::shared_ptr mockHttpClientFactory; -}; - -TEST_F(STSAssumeRoleWithWebIdentityCredentialsProviderTest, TestRetryStrategy) -{ - Aws::Vector retryableErrors; - retryableErrors.push_back("IDPCommunicationError"); - retryableErrors.push_back("InvalidIdentityToken"); - SpecifiedRetryableErrorsRetryStrategy retryStrategy(retryableErrors, 3/*max retries*/); - - auto error1 = AWSError(CoreErrors::UNKNOWN, "SomethingElse",/*ExceptionName*/ "ErrorMsg", true/*retry*/); - ASSERT_TRUE(retryStrategy.ShouldRetry(error1, 0)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error1, 1)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error1, 2)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error1, 3)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error1, 4)); - - auto error2 = AWSError(CoreErrors::UNKNOWN, "SomethingElse",/*ExceptionName*/ "ErrorMsg", false/*retry*/); - ASSERT_FALSE(retryStrategy.ShouldRetry(error2, 0)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error2, 1)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error2, 2)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error2, 3)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error2, 4)); - - auto error3 = AWSError(CoreErrors::UNKNOWN, "IDPCommunicationError",/*ExceptionName*/ "ErrorMsg", false/*retry*/); - ASSERT_TRUE(retryStrategy.ShouldRetry(error3, 0)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error3, 1)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error3, 2)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error3, 3)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error3, 4)); - - auto error4 = AWSError(CoreErrors::UNKNOWN, "IDPCommunicationError",/*ExceptionName*/ "ErrorMsg", true/*retry*/); - ASSERT_TRUE(retryStrategy.ShouldRetry(error4, 0)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error4, 1)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error4, 2)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error4, 3)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error4, 4)); - - auto error5 = AWSError(CoreErrors::UNKNOWN, "InvalidIdentityToken",/*ExceptionName*/ "ErrorMsg", false/*retry*/); - ASSERT_TRUE(retryStrategy.ShouldRetry(error5, 0)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error5, 1)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error5, 2)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error5, 3)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error5, 4)); - - auto error6 = AWSError(CoreErrors::UNKNOWN, "InvalidIdentityToken",/*ExceptionName*/ "ErrorMsg", true/*retry*/); - ASSERT_TRUE(retryStrategy.ShouldRetry(error6, 0)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error6, 1)); - ASSERT_TRUE(retryStrategy.ShouldRetry(error6, 2)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error6, 3)); - ASSERT_FALSE(retryStrategy.ShouldRetry(error6, 4)); - - ASSERT_EQ(0l, retryStrategy.CalculateDelayBeforeNextRetry(error1, 0)); - ASSERT_EQ(50l, retryStrategy.CalculateDelayBeforeNextRetry(error2, 1)); - ASSERT_EQ(100l, retryStrategy.CalculateDelayBeforeNextRetry(error2, 2)); - ASSERT_EQ(200l, retryStrategy.CalculateDelayBeforeNextRetry(error2, 3)); - ASSERT_EQ(400l, retryStrategy.CalculateDelayBeforeNextRetry(error2, 4)); - ASSERT_EQ(512*25l, retryStrategy.CalculateDelayBeforeNextRetry(error2, 9)); -} - -TEST_F(STSAssumeRoleWithWebIdentityCredentialsProviderTest, TestParseCredentialsFromConfigCorrectly) -{ - Aws::String tokenFileName = m_configFileName + "tokenFile"; - Aws::OFStream tokenFile(tokenFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); - Aws::String token = "AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE"; - tokenFile << token; - tokenFile.close(); - - // One of the required environment variables is not set, test it will load from config file and parse credentials correctly - Aws::Environment::UnSetEnv("AWS_ROLE_ARN"); - Aws::Environment::SetEnv("AWS_WEB_IDENTITY_TOKEN_FILE", tokenFileName.c_str(), 1/*override*/); - - Aws::OFStream configFile(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); - configFile << "[default]" << std::endl; - configFile << "region = us-west-2" << std::endl; - configFile << "web_identity_token_file = " << tokenFileName << std::endl; - configFile << " role_arn = arn:aws:iam::123456789012:role/demo " << std::endl; - configFile << "role_session_name = sessionId_1234_abcd_xxxx" << std::endl; - configFile << std::endl; - configFile.close(); - Aws::Config::ReloadCachedConfigFile(); - STSAssumeRoleWebIdentityCredentialsProvider provider; - - // No response is set to mockHttpClient, there will be no response - auto creds = provider.GetAWSCredentials(); - ASSERT_TRUE(creds.IsEmpty()); - - auto request = mockHttpClient->GetMostRecentHttpRequest(); - ASSERT_EQ("https://sts.us-west-2.amazonaws.com", request.GetURIString(false /*don't include querystring*/)); - Aws::StringStream ss; - ss << request.GetContentBody()->rdbuf(); - ASSERT_EQ("Action=AssumeRoleWithWebIdentity&Version=2011-06-15&RoleSessionName=sessionId_1234_abcd_xxxx&RoleArn=arn%3Aaws%3Aiam%3A%3A123456789012%3Arole%2Fdemo&WebIdentityToken=AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp%2BIEXAMPLE", ss.str()); - std::shared_ptr requestTmp = CreateHttpRequest(URI(request.GetURIString(true /*include querystring*/)), HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - //Made up credentials from https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html - Aws::String goodXml = "AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLEwJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY2226-10-24T23:00:23ZASgeIAIOSFODNN7EXAMPLEarn:aws:sts::123456789012:assumed-role/FederatedWebIdentityRole/app1AROACLKWSDQRAOEXAMPLE:app1"; - std::shared_ptr goodResponse = Aws::MakeShared(AllocationTag, requestTmp); - goodResponse->SetResponseCode(HttpResponseCode::OK); - goodResponse->GetResponseBody() << goodXml; - mockHttpClient->AddResponseToReturn(goodResponse); - - creds = provider.GetAWSCredentials(); - ASSERT_FALSE(creds.IsEmpty()); - ASSERT_EQ("AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE", creds.GetSessionToken()); - ASSERT_EQ("wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY", creds.GetAWSSecretKey()); - ASSERT_EQ("ASgeIAIOSFODNN7EXAMPLE", creds.GetAWSAccessKeyId()); - ASSERT_EQ("123456789012", creds.GetAccountId()); - - Aws::FileSystem::RemoveFileIfExists(tokenFileName.c_str()); - Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); -} - -TEST_F(STSAssumeRoleWithWebIdentityCredentialsProviderTest, TestInitializeFromEnvironmentVariables) -{ - Aws::String tokenFileName = m_configFileName + "tokenFile"; - Aws::OFStream tokenFile(tokenFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); - Aws::String token = "AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE"; - tokenFile << token; - tokenFile.close(); - - // Load from environment only when both AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE are available - Aws::Environment::SetEnv("AWS_ROLE_ARN", "arn:aws:iam::123456789012:role/env", 1/*override*/); - Aws::Environment::SetEnv("AWS_WEB_IDENTITY_TOKEN_FILE", tokenFileName.c_str(), 1/*override*/); - // Note this one is not required - Aws::Environment::SetEnv("AWS_ROLE_SESSION_NAME", "sessionId_abcd_1234_xxxx", 1/*override*/); - - // Construct config file to prove that we will not load from config file when those required two are available - Aws::OFStream configFile(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); - configFile << "[default]" << std::endl; - configFile << "region = us-west-2" << std::endl; - configFile << "web_identity_token_file = " << tokenFileName << std::endl; - configFile << " role_arn = arn:aws:iam::123456789012:role/demo " << std::endl; - configFile << "role_session_name = sessionId_1234_abcd_xxxx" << std::endl; - configFile << std::endl; - configFile.close(); - - Aws::Config::ReloadCachedConfigFile(); - STSAssumeRoleWebIdentityCredentialsProvider provider; - // No response is set to mockHttpClient, there will be no response - auto creds = provider.GetAWSCredentials(); - ASSERT_TRUE(creds.IsEmpty()); - auto request = mockHttpClient->GetMostRecentHttpRequest(); - Aws::StringStream ss; - ss << request.GetContentBody()->rdbuf(); - ASSERT_EQ("Action=AssumeRoleWithWebIdentity&Version=2011-06-15&RoleSessionName=sessionId_abcd_1234_xxxx&RoleArn=arn%3Aaws%3Aiam%3A%3A123456789012%3Arole%2Fenv&WebIdentityToken=AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp%2BIEXAMPLE", ss.str()); - - // Role session name will be an random uuid - Aws::Environment::UnSetEnv("AWS_ROLE_SESSION_NAME"); - STSAssumeRoleWebIdentityCredentialsProvider provider1; - // No response is set to mockHttpClient, there will be no response - auto creds1 = provider1.GetAWSCredentials(); - ASSERT_TRUE(creds1.IsEmpty()); - auto request1 = mockHttpClient->GetMostRecentHttpRequest(); - ss.str(""); - ss << request1.GetContentBody()->rdbuf(); - ASSERT_NE("Action=AssumeRoleWithWebIdentity&Version=2011-06-15&RoleSessionName=sessionId_abcd_1234_xxxx&RoleArn=arn%3Aaws%3Aiam%3A%3A123456789012%3Arole%2Fenv&WebIdentityToken=AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp%2BIEXAMPLE", ss.str()); - - // Set session name back - Aws::Environment::SetEnv("AWS_ROLE_SESSION_NAME", "sessionId_abcd_1234_xxxx", 1/*override*/); - // One of the required environment variable is not set - Aws::Environment::UnSetEnv("AWS_WEB_IDENTITY_TOKEN_FILE"); - STSAssumeRoleWebIdentityCredentialsProvider provider2; - // No response is set to mockHttpClient, there will be no response - auto creds2 = provider2.GetAWSCredentials(); - ASSERT_TRUE(creds2.IsEmpty()); - auto request2 = mockHttpClient->GetMostRecentHttpRequest(); - ss.str(""); - ss << request2.GetContentBody()->rdbuf(); - ASSERT_EQ("Action=AssumeRoleWithWebIdentity&Version=2011-06-15&RoleSessionName=sessionId_1234_abcd_xxxx&RoleArn=arn%3Aaws%3Aiam%3A%3A123456789012%3Arole%2Fdemo&WebIdentityToken=AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp%2BIEXAMPLE", ss.str()); - - Aws::FileSystem::RemoveFileIfExists(tokenFileName.c_str()); - Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); -} - class SSOCredentialsProviderTest :public ProcessCredentialsProviderTest { public: diff --git a/tests/aws-cpp-sdk-dynamodb-unit-tests/DynamoDBUnitTests.cpp b/tests/aws-cpp-sdk-dynamodb-unit-tests/DynamoDBUnitTests.cpp index 496c198141f..0490fc73fc5 100644 --- a/tests/aws-cpp-sdk-dynamodb-unit-tests/DynamoDBUnitTests.cpp +++ b/tests/aws-cpp-sdk-dynamodb-unit-tests/DynamoDBUnitTests.cpp @@ -582,63 +582,6 @@ TEST_F(DynamoDBUnitTest, ShouldUseAccountIDEndpointFromProcessCredentialsProvide EXPECT_TRUE(std::find(features.begin(), features.end(), "T") != features.end()); } -TEST_F(DynamoDBUnitTest, ShouldUseAccountIDEndpointFromSTSCredentialsProvider) -{ - Utils::TempFile tokenFile(std::ios_base::out | std::ios_base::trunc); - ASSERT_TRUE(tokenFile.good()); - Aws::String token = "seeyoulaterspacecowboy"; - tokenFile << token; - tokenFile.close(); - - Utils::TempFile configFile(std::ios_base::out | std::ios_base::trunc); - configFile << "[default]" << std::endl; - configFile << "web_identity_token_file = " << tokenFile.GetFileName() << std::endl; - configFile << "role_arn = arn:aws:iam::rocco:role/bounty " << std::endl; - configFile << "role_session_name = session_8" << std::endl; - configFile << std::endl; - configFile.close(); - Environment::EnvironmentRAII envVars{{{CONFIGURATION_FILE_ENV_VAR, configFile.GetFileName().c_str()}}}; - Aws::Config::ReloadCachedConfigFile(); - - ClientConfigurationInitValues initValues{}; - initValues.shouldDisableIMDS = true; - DynamoDBClientConfiguration configuration{initValues}; - configuration.region = "us-east-1"; - - auto credsProvider = Aws::MakeShared(LOG_TAG); - - const auto accountIdClient = Aws::MakeShared(LOG_TAG, std::move(credsProvider), nullptr, configuration); - - // make up sts response - std::shared_ptr requestTmp = CreateHttpRequest(URI{}, HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - Aws::String stsResponse = "waltzforvenuzarn:aws:sts::rocco:assumed-role/FederatedWebIdentityRole/musicboxstella"; - auto response = Aws::MakeShared(LOG_TAG, requestTmp); - response->SetResponseCode(HttpResponseCode::OK); - response->GetResponseBody() << stsResponse; - mock_http_client_->AddResponseToReturn(std::move(response)); - - // mock response - auto successStream = Aws::MakeShared(LOG_TAG, "cowboy.bebop/planets", HttpMethod::HTTP_GET); - successStream->SetResponseStreamFactory([]() -> IOStream* { - auto listTablesString = R"({"LastEvaluatedTableName": "Planets","TableNames": ["Planets"]}))"; - return Aws::New(LOG_TAG, listTablesString, std::ios_base::in | std::ios_base::binary); - }); - auto successResponse = Aws::MakeShared(LOG_TAG, successStream); - successResponse->SetResponseCode(HttpResponseCode::OK); - - mock_http_client_->AddResponseToReturn(successResponse); - const auto listTablesOutcome = accountIdClient->ListTables(); - EXPECT_TRUE(listTablesOutcome.IsSuccess()); - const auto requestSeen = mock_http_client_->GetMostRecentHttpRequest(); - EXPECT_EQ("https://rocco.ddb.us-east-1.amazonaws.com", requestSeen.GetUri().GetURIString()); - const auto features = GetFeaturesForRequest(requestSeen); - EXPECT_TRUE(!features.empty()); - // AccountId is disabled - EXPECT_TRUE(std::find(features.begin(), features.end(), "P") != features.end()); - // Identity resolved a accountId - EXPECT_TRUE(std::find(features.begin(), features.end(), "T") != features.end()); -} - TEST_F(DynamoDBUnitTest, ShouldUseAccountIDEndpointFromSSOCredentialsProvider) { Aws::OFStream tokenFile(m_ssoTokenFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc);; diff --git a/tools/scripts/build-tests/build-al2-debug-clang-cxx20.sh b/tools/scripts/build-tests/build-al2-debug-clang-cxx20.sh index 295440a425b..d539abebd4e 100755 --- a/tools/scripts/build-tests/build-al2-debug-clang-cxx20.sh +++ b/tools/scripts/build-tests/build-al2-debug-clang-cxx20.sh @@ -18,6 +18,6 @@ PREFIX_DIR="$1" mkdir "${PREFIX_DIR}/al2-build" mkdir "${PREFIX_DIR}/al2-install" cd "${PREFIX_DIR}/al2-build" -cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../aws-sdk-cpp/toolchains/clang-c++20.cmake -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" +cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../aws-sdk-cpp/toolchains/clang-c++20.cmake -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" -DAWS_ENABLE_CORE_INTEGRATION_TEST=ON ninja-build -j $(grep -c ^processor /proc/cpuinfo) ninja-build install diff --git a/tools/scripts/build-tests/build-al2-debug-default.sh b/tools/scripts/build-tests/build-al2-debug-default.sh index 39ae09d8295..c0377b59cfb 100755 --- a/tools/scripts/build-tests/build-al2-debug-default.sh +++ b/tools/scripts/build-tests/build-al2-debug-default.sh @@ -20,7 +20,7 @@ BUILD_TYPE="${2:-Debug}" mkdir "${PREFIX_DIR}/al2-build" mkdir "${PREFIX_DIR}/al2-install" cd "${PREFIX_DIR}/al2-build" -CMAKE_ARGS=(-GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DMINIMIZE_SIZE=ON -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" -DBUILD_PERFORMANCE_TESTS=ON) +CMAKE_ARGS=(-GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DMINIMIZE_SIZE=ON -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" -DBUILD_PERFORMANCE_TESTS=ON -DAWS_ENABLE_CORE_INTEGRATION_TEST=ON) if [ "$BUILD_TYPE" = "Debug" ]; then CMAKE_ARGS+=(-DCMAKE_CXX_FLAGS="-ggdb -fsanitize=address") fi diff --git a/tools/scripts/build-tests/build-al2-debug-gcc-cxx20.sh b/tools/scripts/build-tests/build-al2-debug-gcc-cxx20.sh index 8b70ecfe1b8..231c71bb866 100755 --- a/tools/scripts/build-tests/build-al2-debug-gcc-cxx20.sh +++ b/tools/scripts/build-tests/build-al2-debug-gcc-cxx20.sh @@ -18,6 +18,6 @@ PREFIX_DIR="$1" mkdir "${PREFIX_DIR}/al2-build" mkdir "${PREFIX_DIR}/al2-install" cd "${PREFIX_DIR}/al2-build" -cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../aws-sdk-cpp/toolchains/gcc10-c++20.cmake -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" +cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../aws-sdk-cpp/toolchains/gcc10-c++20.cmake -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" -DAWS_ENABLE_CORE_INTEGRATION_TEST=ON ninja-build -j $(grep -c ^processor /proc/cpuinfo) ninja-build install diff --git a/tools/scripts/build-tests/build-al2-debug-non-unity-default.sh b/tools/scripts/build-tests/build-al2-debug-non-unity-default.sh index 39842332a96..c7ffebd0cd6 100755 --- a/tools/scripts/build-tests/build-al2-debug-non-unity-default.sh +++ b/tools/scripts/build-tests/build-al2-debug-non-unity-default.sh @@ -18,6 +18,6 @@ PREFIX_DIR="$1" mkdir "${PREFIX_DIR}/al2-build" mkdir "${PREFIX_DIR}/al2-install" cd "${PREFIX_DIR}/al2-build" -cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DENABLE_UNITY_BUILD=OFF -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" +cmake -GNinja ../aws-sdk-cpp -DCMAKE_BUILD_TYPE=Debug -DENABLE_UNITY_BUILD=OFF -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" -DAWS_ENABLE_CORE_INTEGRATION_TEST=ON ninja-build -j $(grep -c ^processor /proc/cpuinfo) ninja-build install diff --git a/tools/scripts/build-tests/build-al2-default.sh b/tools/scripts/build-tests/build-al2-default.sh index f81caab0300..e7c3e7c4d10 100755 --- a/tools/scripts/build-tests/build-al2-default.sh +++ b/tools/scripts/build-tests/build-al2-default.sh @@ -18,6 +18,6 @@ PREFIX_DIR="$1" mkdir "${PREFIX_DIR}/al2-build" mkdir "${PREFIX_DIR}/al2-install" cd "${PREFIX_DIR}/al2-build" -cmake -GNinja ../aws-sdk-cpp -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" +cmake -GNinja ../aws-sdk-cpp -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/al2-install" -DAWS_ENABLE_CORE_INTEGRATION_TEST=ON cmake --build . --parallel $(grep -c ^processor /proc/cpuinfo) cmake --build . --target install diff --git a/tools/scripts/build-tests/build-mac-default.sh b/tools/scripts/build-tests/build-mac-default.sh index 42d2809b1e7..516fd5fa727 100755 --- a/tools/scripts/build-tests/build-mac-default.sh +++ b/tools/scripts/build-tests/build-mac-default.sh @@ -18,6 +18,6 @@ PREFIX_DIR="$1" mkdir "${PREFIX_DIR}/mac-build" mkdir "${PREFIX_DIR}/mac-install" cd "${PREFIX_DIR}/mac-build" -cmake ../aws-sdk-cpp -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/mac-install" +cmake ../aws-sdk-cpp -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/mac-install" -DAWS_ENABLE_CORE_INTEGRATION_TEST=ON cmake --build . --parallel $(sysctl -n hw.ncpu) cmake --install . diff --git a/tools/scripts/build-tests/build-windows-default.ps1 b/tools/scripts/build-tests/build-windows-default.ps1 index 4539e12895e..524b54392b3 100644 --- a/tools/scripts/build-tests/build-windows-default.ps1 +++ b/tools/scripts/build-tests/build-windows-default.ps1 @@ -10,7 +10,7 @@ param($PREFIX_DIR) mkdir "${PREFIX_DIR}/win-build" mkdir "${PREFIX_DIR}/win-install" cd "${PREFIX_DIR}/win-build" -&'C:\\Program Files\\CMake\\bin\\cmake.exe' ../aws-sdk-cpp -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/win-install" +&'C:\\Program Files\\CMake\\bin\\cmake.exe' ../aws-sdk-cpp -DCMAKE_INSTALL_PREFIX="${PREFIX_DIR}/win-install" -DAWS_ENABLE_CORE_INTEGRATION_TEST=ON &'C:\\Program Files\\CMake\\bin\\cmake.exe' --build . -j 8 &'C:\\Program Files\\CMake\\bin\\cmake.exe' --build . --target install &cmd.exe /c "del /s /q *.pdb" diff --git a/tools/scripts/run_integration_tests.py b/tools/scripts/run_integration_tests.py index 0c7125e53f8..a098e7ba652 100644 --- a/tools/scripts/run_integration_tests.py +++ b/tools/scripts/run_integration_tests.py @@ -36,6 +36,7 @@ def main(): exe_extension = ".exe" if platform.system() == "Windows" else "" test_list = [ + "aws-cpp-sdk-core-integration-tests", "aws-cpp-sdk-transcribestreaming-integ-tests", "aws-cpp-sdk-dynamodb-unit-tests", "aws-cpp-sdk-dynamodb-integration-tests",