diff options
author | dakovalkov <dakovalkov@yandex-team.com> | 2023-12-03 13:33:55 +0300 |
---|---|---|
committer | dakovalkov <dakovalkov@yandex-team.com> | 2023-12-03 14:04:39 +0300 |
commit | 2a718325637e5302334b6d0a6430f63168f8dbb3 (patch) | |
tree | 64be81080b7df9ec1d86d053a0c394ae53fcf1fe /contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config | |
parent | e0d94a470142d95c3007e9c5d80380994940664a (diff) | |
download | ydb-2a718325637e5302334b6d0a6430f63168f8dbb3.tar.gz |
Update contrib/libs/aws-sdk-cpp to 1.11.37
Diffstat (limited to 'contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config')
6 files changed, 1194 insertions, 571 deletions
diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp new file mode 100644 index 0000000000..ba0079bb5e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp @@ -0,0 +1,629 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/utils/memory/stl/AWSSet.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <fstream> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + static const char REGION_KEY[] = "region"; + static const char ACCESS_KEY_ID_KEY[] = "aws_access_key_id"; + static const char SECRET_KEY_KEY[] = "aws_secret_access_key"; + static const char SESSION_TOKEN_KEY[] = "aws_session_token"; + static const char SSO_START_URL_KEY[] = "sso_start_url"; + static const char SSO_REGION_KEY[] = "sso_region"; + static const char SSO_ACCOUNT_ID_KEY[] = "sso_account_id"; + static const char SSO_ROLE_NAME_KEY[] = "sso_role_name"; + static const char SSO_SESSION_KEY[] = "sso_session"; + static const char ROLE_ARN_KEY[] = "role_arn"; + static const char EXTERNAL_ID_KEY[] = "external_id"; + static const char CREDENTIAL_PROCESS_COMMAND[] = "credential_process"; + static const char SOURCE_PROFILE_KEY[] = "source_profile"; + static const char PROFILE_SECTION[] = "profile"; + static const char DEFAULT[] = "default"; + static const char SSO_SESSION_SECTION[] = "sso-session"; + static const char DEFAULTS_MODE_KEY[] = "defaults_mode"; + static const char EQ = '='; + static const char LEFT_BRACKET = '['; + static const char RIGHT_BRACKET = ']'; + static const char PARSER_TAG[] = "Aws::Config::ConfigFileProfileFSM"; + + // generated by python from identifier regex pattern from the spec: R"([A-Za-z0-9_\-/.%@:\+]+)": + // #py: ''.join(chr(i) for i in range(128) if re.match("[A-Za-z0-9_\-\/.%@:\+]", chr(i))) + const char IDENTIFIER_ALLOWED_CHARACTERS[] = R"(%+-./0123456789:@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz)"; + static const size_t IDENTIFIER_ALLOWED_CHARACTERS_SZ = sizeof(IDENTIFIER_ALLOWED_CHARACTERS) - 1; + const char WHITESPACE_CHARACTERS[] = "\t "; + static const size_t WHITESPACE_CHARACTERS_SZ = sizeof(WHITESPACE_CHARACTERS) - 1; + const char COMMENT_START[] = "#;"; + static const size_t COMMENT_START_SZ = sizeof(COMMENT_START) - 1; + + struct ProfilePropertyAccessFunctions + { + const char* PropertyKey; + std::function<void(Profile&, const Aws::String&)> Setter; + std::function<const Aws::String&(const Profile&)> Getter; + }; + + static const ProfilePropertyAccessFunctions PROFILE_PROPERTY_FUNCS[] = + {{REGION_KEY, &Profile::SetRegion, &Profile::GetRegion}, + //ACCESS_KEY_ID_KEY, - AwsCredentials require special handling + //SECRET_KEY_KEY, + //SESSION_TOKEN_KEY, + {SSO_START_URL_KEY, &Profile::SetSsoStartUrl, &Profile::GetSsoStartUrl}, + {SSO_REGION_KEY, &Profile::SetSsoRegion, &Profile::GetSsoRegion}, + {SSO_ACCOUNT_ID_KEY, &Profile::SetSsoAccountId, &Profile::GetSsoAccountId}, + {SSO_ROLE_NAME_KEY, &Profile::SetSsoRoleName, &Profile::GetSsoRoleName}, + //SSO_SESSION_KEY - SsoSession requires special handling + {ROLE_ARN_KEY, &Profile::SetRoleArn, &Profile::GetRoleArn}, + {EXTERNAL_ID_KEY, &Profile::SetExternalId, &Profile::GetExternalId}, + {CREDENTIAL_PROCESS_COMMAND, &Profile::SetCredentialProcess, &Profile::GetCredentialProcess}, + {SOURCE_PROFILE_KEY, &Profile::SetSourceProfile, &Profile::GetSourceProfile}, + {DEFAULTS_MODE_KEY, &Profile::SetDefaultsMode, &Profile::GetDefaultsMode}}; + + template<typename EntryT, size_t N> + const EntryT* FindInStaticArray(const EntryT (&array)[N], const Aws::String& searchKey) + { + const EntryT* found = std::find_if(array, array + N, + [&searchKey](const EntryT& entry) + { + return searchKey == entry.PropertyKey; + }); + + if(!!found && found != array + N) + return found; + + return nullptr; + } + + static const char* PROFILE_KEY_SPECIAL_HANDLING[] = + {ACCESS_KEY_ID_KEY, SECRET_KEY_KEY, SESSION_TOKEN_KEY, SSO_SESSION_KEY}; + static const size_t PROFILE_KEY_SPECIAL_HANDLING_SZ = sizeof(PROFILE_KEY_SPECIAL_HANDLING) / sizeof(PROFILE_KEY_SPECIAL_HANDLING[0]); + + struct SsoSessionPropertyAccessFunctions + { + const char* PropertyKey; + std::function<void(Profile::SsoSession&, const Aws::String&)> Setter; + std::function<const Aws::String&(const Profile::SsoSession&)> Getter; + }; + static const SsoSessionPropertyAccessFunctions SSO_SESSION_PROPERTY_FUNCS[] = + {{SSO_REGION_KEY, &Profile::SsoSession::SetSsoRegion, &Profile::SsoSession::GetSsoRegion}, + {SSO_START_URL_KEY, &Profile::SsoSession::SetSsoStartUrl, &Profile::SsoSession::GetSsoStartUrl}}; + + class ConfigFileProfileFSM + { + public: + ConfigFileProfileFSM(bool useProfilePrefix) + : m_useProfilePrefix(useProfilePrefix) + {} + + const Aws::Map<String, Profile>& GetProfiles() const { return m_foundProfiles; } + + void ParseStream(Aws::IStream& stream) + { + static const size_t ASSUME_EMPTY_LEN = 3; + State currentState = START; + Aws::String currentSectionName; + Aws::Map<Aws::String, Aws::String> currentKeyValues; + + Aws::String rawLine; + while(std::getline(stream, rawLine) && currentState != FAILURE) + { + Aws::String line = rawLine.substr(0, rawLine.find_first_of(COMMENT_START)); // ignore comments + if (line.empty() || line.length() < ASSUME_EMPTY_LEN || line.find_first_not_of(WHITESPACE_CHARACTERS) == Aws::String::npos) + { + continue; + } + + auto openPos = line.find(LEFT_BRACKET); + auto closePos = line.find(RIGHT_BRACKET); + + if(openPos != std::string::npos && closePos != std::string::npos) + { + FlushSection(currentState, currentSectionName, currentKeyValues); + currentKeyValues.clear(); + ParseSectionDeclaration(line, currentSectionName, currentState); + continue; + } + + if(PROFILE_FOUND == currentState || SSO_SESSION_FOUND == currentState) + { + auto equalsPos = line.find(EQ); + if (equalsPos != std::string::npos) + { + auto key = StringUtils::Trim(line.substr(0, equalsPos).c_str()); + auto value = StringUtils::Trim(line.substr(equalsPos + 1).c_str()); + currentKeyValues[key] = value; + continue; + } + } + + if(UNKNOWN_SECTION_FOUND == currentState) + { + // skip any unknown sections + continue; + } + + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Unexpected line in the aws shared profile: " << rawLine); + currentState = FAILURE; + break; + } + + FlushSection(currentState, currentSectionName, currentKeyValues); + + // Put sso-sessions into profiles + for(auto& profile : m_foundProfiles) + { + const Aws::String& profileSsoSessionName = profile.second.GetValue(SSO_SESSION_KEY); + if(!profileSsoSessionName.empty()) + { + auto ssoSessionIt = m_foundSsoSessions.find(profileSsoSessionName); + if(ssoSessionIt == m_foundSsoSessions.end()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "AWS profile has reference to a missing sso_session: " << profileSsoSessionName); + currentState = FAILURE; + continue; + } + auto ssoSession = ssoSessionIt->second; + auto prof = profile.second; + // If sso session and profile have conflicting start url or region, fail to parse + // the session/sso specific profile properties + auto hasConflictingStartUrls = !ssoSession.GetSsoStartUrl().empty() + && !prof.GetSsoStartUrl().empty() + && ssoSession.GetSsoStartUrl() != prof.GetSsoStartUrl(); + auto hasConflictingRegions = !ssoSession.GetSsoRegion().empty() + && !prof.GetSsoRegion().empty() + && ssoSession.GetSsoRegion() != prof.GetSsoRegion(); + if (hasConflictingStartUrls || hasConflictingRegions) { + AWS_LOGSTREAM_ERROR(PARSER_TAG, + "SSO profile has a start url or region conflict with sso session"); + prof.SetSsoStartUrl(""); + prof.SetSsoRegion(""); + prof.SetSsoAccountId(""); + prof.SetSsoRoleName(""); + continue; + } + profile.second.SetSsoSession(ssoSessionIt->second); + } + } + + if(FAILURE == currentState) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "AWS shared profile config parsing failed"); + } + } + + private: + // true means Shared Config parsing, false means Shared Credentials parsing + bool m_useProfilePrefix = false; + + enum State + { + START = 0, + PROFILE_FOUND, + SSO_SESSION_FOUND, + UNKNOWN_SECTION_FOUND, + FAILURE + }; + + /** + * Helper function to parse a single word (aka section identifier) containing allowed characters from a line and a pos + * i.e. line="[ profile default ]";identifierBegin=10 will return "default" + * @param line, a section definition line being parsed + * @param identifierBegin, an Aws::String position to start parsing + * @param oErrorMsg, a reference to Aws::String to store error message in case of a parsing error. + * @return Aws::String, e.g. "default" + */ + Aws::String ParseIdentifier(const Aws::String& line, Aws::String::size_type identifierBegin, Aws::String& oErrorMsg) + { + // pos at the beginning of section Identifier (or sso_session section keyword) + Aws::String::size_type identifierLength = 0; + Aws::String::size_type pos = identifierBegin; + while(pos < line.length()) + { + if(std::find(IDENTIFIER_ALLOWED_CHARACTERS, + IDENTIFIER_ALLOWED_CHARACTERS + IDENTIFIER_ALLOWED_CHARACTERS_SZ, + line[pos]) != IDENTIFIER_ALLOWED_CHARACTERS + IDENTIFIER_ALLOWED_CHARACTERS_SZ) + { + identifierLength++; + pos++; + } + else + { + break; + } + } + const Aws::String SECTION_END_CHARS_TO_SKIP = Aws::String(WHITESPACE_CHARACTERS) + RIGHT_BRACKET; + + if(identifierLength == 0) + { + oErrorMsg = "identifier is missing"; + return ""; + } + if(pos >= line.size() || SECTION_END_CHARS_TO_SKIP.find(line[pos]) == Aws::String::npos) { + oErrorMsg = "a blank space character or closing bracket is expected after Identifier"; + return ""; + } + Aws::String sectionIdentifier = line.substr(identifierBegin, identifierLength); + + return sectionIdentifier; + } + + /** + * A helper function to parse config section declaration line + * @param line, an input line, e.g. "[profile default]" + * @param ioSectionName, a return argument representing parsed section Identifier, e.g. "default" + * @param ioState, a return argument representing parser state, e.g. PROFILE_FOUND + */ + void ParseSectionDeclaration(const Aws::String& line, + Aws::String& ioSectionName, + State& ioState) + { + do { // goto in a form of "do { break; } while(0);" + Aws::String::size_type pos = 0; + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos != Aws::String::npos && LEFT_BRACKET != line[pos]) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "First non-blank space character of a section definition must be [, line:" << line); + break; + } + pos++; + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos == Aws::String::npos || pos >= line.size()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Unknown section found in the aws config file: " << line); + break; + } + bool defaultProfileOrSsoSectionRequired = false; + if (m_useProfilePrefix) + { + // in configuration files, the profile name must start with profile. (eg. [profile profile-name]), + // except where the profile name is default. When the profile name is default it may start with profile + static const size_t PROFILE_KEYWORD_LENGTH = 7; + if(line.rfind(PROFILE_SECTION, pos + PROFILE_KEYWORD_LENGTH) != Aws::String::npos) + { + // skipping required (optional for default) profile keyword + pos += PROFILE_KEYWORD_LENGTH; + if(pos >= line.size() || + std::find(WHITESPACE_CHARACTERS, + WHITESPACE_CHARACTERS + WHITESPACE_CHARACTERS_SZ, + line[pos]) == WHITESPACE_CHARACTERS + WHITESPACE_CHARACTERS_SZ) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Expected a blank space after \"profile\" keyword: " << line); + break; + } + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + } + else + { + defaultProfileOrSsoSectionRequired = true; + } + } + + Aws::String errorMsg; + Aws::String sectionIdentifier = ParseIdentifier(line, pos, errorMsg); + if (!errorMsg.empty()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Failed to parse section identifier: " << errorMsg << " " << line); + break; + } + pos += sectionIdentifier.length(); + + if(defaultProfileOrSsoSectionRequired) + { + if (sectionIdentifier != DEFAULT && sectionIdentifier != SSO_SESSION_SECTION) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "In configuration files, the profile name must start with " + "profile keyword (except default profile): " << line); + break; + } + if (sectionIdentifier != SSO_SESSION_SECTION) + { + // profile found, still pending check for closing bracket + ioState = PROFILE_FOUND; + ioSectionName = sectionIdentifier; + } + } + + if(!m_useProfilePrefix || sectionIdentifier != SSO_SESSION_SECTION) + { + // profile found, still pending check for closing bracket + ioState = PROFILE_FOUND; + ioSectionName = sectionIdentifier; + } + + if(m_useProfilePrefix && sectionIdentifier == SSO_SESSION_SECTION) + { + // "[sso_session..." found, continue parsing for sso_session identifier + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos == Aws::String::npos) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Expected a blank space after \"sso_session\" keyword: " << line); + break; + } + + sectionIdentifier = ParseIdentifier(line, pos, errorMsg); + if (!errorMsg.empty()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Failed to parse section identifier: " << errorMsg << " " << line); + break; + } + pos += sectionIdentifier.length(); + // sso_session found, still pending check for closing bracket + ioState = SSO_SESSION_FOUND; + ioSectionName = sectionIdentifier; + } + + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos == Aws::String::npos) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Expected a non-blank space after section identifier (i.e. missing \"]\"): " << line); + break; + } + if(line[pos] != RIGHT_BRACKET) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Missing closing bracket after Section Identifier " + "(i.e. missing \"]\" or extra non-blank characters before \"]\"): " << line); + break; + } + pos++; + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos != Aws::String::npos && + std::find(COMMENT_START, COMMENT_START + COMMENT_START_SZ, line[pos]) == COMMENT_START + COMMENT_START_SZ) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Found unexpected characters after closing bracket of Section Identifier " << line); + break; + } + // the rest is a comment, and we don't care about it. + if ((ioState != SSO_SESSION_FOUND && ioState != PROFILE_FOUND) || ioSectionName.empty()) + { + AWS_LOGSTREAM_FATAL(PARSER_TAG, "Unexpected parser state after attempting to parse section " << line); + break; + } + return; + } while(0); // end of goto in a form of "do { break; } while(0);" + + ioSectionName.erase(); + ioState = UNKNOWN_SECTION_FOUND; + return; + } + + /** + * A helper function to store currently being parsed section along with its properties + * (i.e. [profile default] and its key1=val1 under). + * @param currentState, a current parser State, e.g. PROFILE_FOUND + * @param currentSectionName, a current section identifier, e.g. "default" + * @param currentKeyValues, a map of parsed key-value properties of a section definition being recorded + */ + void FlushSection(const State currentState, const Aws::String& currentSectionName, Aws::Map<Aws::String, Aws::String>& currentKeyValues) + { + if(START == currentState || currentSectionName.empty()) + { + return; //nothing to flush + } + + if(PROFILE_FOUND == currentState) + { + Profile& profile = m_foundProfiles[currentSectionName]; + + for(const auto& keyVal : currentKeyValues) + { + auto setterFuncPtr = FindInStaticArray(PROFILE_PROPERTY_FUNCS, keyVal.first); + if(setterFuncPtr) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "Found " << setterFuncPtr->PropertyKey << " " << keyVal.second); + setterFuncPtr->Setter(profile, keyVal.second); + } + else + { + auto specialPropertyKey = std::find_if(PROFILE_KEY_SPECIAL_HANDLING, PROFILE_KEY_SPECIAL_HANDLING + PROFILE_KEY_SPECIAL_HANDLING_SZ, + [&keyVal](const char* entry) + { + return !!entry && keyVal.first == entry; + }); + + if (specialPropertyKey && specialPropertyKey != PROFILE_KEY_SPECIAL_HANDLING + PROFILE_KEY_SPECIAL_HANDLING_SZ) + { + AWS_LOGSTREAM_INFO(PARSER_TAG, "Unknown property: " << keyVal.first << " in the profile: " << currentSectionName); + } + } + } + + auto accessKeyIdIter = currentKeyValues.find(ACCESS_KEY_ID_KEY); + Aws::String accessKey, secretKey, sessionToken; + if (accessKeyIdIter != currentKeyValues.end()) + { + accessKey = accessKeyIdIter->second; + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found access key " << accessKey); + + auto secretAccessKeyIter = currentKeyValues.find(SECRET_KEY_KEY); + auto sessionTokenIter = currentKeyValues.find(SESSION_TOKEN_KEY); + if (secretAccessKeyIter != currentKeyValues.end()) + { + secretKey = secretAccessKeyIter->second; + } + else + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "No secret access key found even though an access key was specified. This will cause all signed AWS calls to fail."); + } + + if (sessionTokenIter != currentKeyValues.end()) + { + sessionToken = sessionTokenIter->second; + } + + profile.SetCredentials(Aws::Auth::AWSCredentials(accessKey, secretKey, sessionToken)); + } + + if (!profile.GetSsoStartUrl().empty() || !profile.GetSsoRegion().empty() + || !profile.GetSsoAccountId().empty() || !profile.GetSsoRoleName().empty()) + { + // If there is no sso session, all fields are required. If an SSO session is present, + // then only account id and sso role name are required. + auto hasSession = currentKeyValues.find(SSO_SESSION_KEY) != currentKeyValues.end(); + auto hasInvalidProfileWithoutSession = !hasSession && + (profile.GetSsoStartUrl().empty() + || profile.GetSsoRegion().empty() + || profile.GetSsoAccountId().empty() + || profile.GetSsoRoleName().empty()); + auto hasInvalidProfileWithSession = hasSession && + (profile.GetSsoAccountId().empty() + || profile.GetSsoRoleName().empty()); + if (hasInvalidProfileWithoutSession || hasInvalidProfileWithSession) { + profile.SetSsoStartUrl(""); + profile.SetSsoRegion(""); + profile.SetSsoAccountId(""); + profile.SetSsoRoleName(""); + AWS_LOGSTREAM_ERROR(PARSER_TAG, "invalid SSO configuration for aws profile " << currentSectionName); + } + } + + profile.SetName(currentSectionName); + profile.SetAllKeyValPairs(std::move(currentKeyValues)); + } + else if (SSO_SESSION_FOUND == currentState) { + Profile::SsoSession& ssoSession = m_foundSsoSessions[currentSectionName]; + for(const auto& keyVal : currentKeyValues) + { + auto setterFuncPtr = FindInStaticArray(SSO_SESSION_PROPERTY_FUNCS, keyVal.first); + if(setterFuncPtr) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "Found sso-session property " << setterFuncPtr->PropertyKey << " " << keyVal.second); + setterFuncPtr->Setter(ssoSession, keyVal.second); + } + else + { + AWS_LOGSTREAM_INFO(PARSER_TAG, "Unknown property: " << keyVal.first << " in the sso-session: " << currentSectionName); + } + } + ssoSession.SetName(currentSectionName); + ssoSession.SetAllKeyValPairs(std::move(currentKeyValues)); + } + else + { + AWS_LOGSTREAM_FATAL(PARSER_TAG, "Unknown parser error: unexpected state " << currentState); + } + } + + Aws::Map<String, Profile> m_foundProfiles; + Aws::Map<String, Profile::SsoSession> m_foundSsoSessions; + }; + + static const char* const CONFIG_FILE_LOADER = "Aws::Config::AWSConfigFileProfileConfigLoader"; + + AWSConfigFileProfileConfigLoader::AWSConfigFileProfileConfigLoader(const Aws::String& fileName, bool useProfilePrefix) : + m_fileName(fileName), m_useProfilePrefix(useProfilePrefix) + { + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Initializing config loader against fileName " + << fileName << " and using profilePrefix = " << useProfilePrefix); + } + + bool AWSConfigFileProfileConfigLoader::LoadInternal() + { + m_profiles.clear(); + + Aws::IFStream inputFile(m_fileName.c_str()); + if(inputFile) + { + ConfigFileProfileFSM parser(m_useProfilePrefix); + parser.ParseStream(inputFile); + m_profiles = parser.GetProfiles(); + return m_profiles.size() > 0; + } + + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for reading."); + + return false; + } + + bool AWSConfigFileProfileConfigLoader::PersistInternal(const Aws::Map<Aws::String, Profile>& profiles) + { + Aws::OFStream outputFile(m_fileName.c_str(), std::ios_base::out | std::ios_base::trunc); + if(outputFile) + { + Aws::UnorderedMap<Aws::String, std::reference_wrapper<const Profile::SsoSession>> ssoSessionsToDump; + + for(const auto& profile : profiles) + { + Aws::String prefix = m_useProfilePrefix ? PROFILE_SECTION : ""; + + AWS_LOGSTREAM_DEBUG(CONFIG_FILE_LOADER, "Writing profile " << profile.first << " to disk."); + + outputFile << LEFT_BRACKET << prefix << " " << profile.second.GetName() << RIGHT_BRACKET << std::endl; + const Aws::Auth::AWSCredentials& credentials = profile.second.GetCredentials(); + if (!credentials.GetAWSAccessKeyId().empty()) { + outputFile << ACCESS_KEY_ID_KEY << EQ << credentials.GetAWSAccessKeyId() << std::endl; + } + if (!credentials.GetAWSSecretKey().empty()) { + outputFile << SECRET_KEY_KEY << EQ << credentials.GetAWSSecretKey() << std::endl; + } + if(!credentials.GetSessionToken().empty()) { + outputFile << SESSION_TOKEN_KEY << EQ << credentials.GetSessionToken() << std::endl; + } + // credentials.GetExpiration().Millis() <- is not present in a config. + + for(const auto& profilePropertyPair : PROFILE_PROPERTY_FUNCS) + { + const auto& profilePropertyValue = profilePropertyPair.Getter(profile.second); + if(!profilePropertyValue.empty()) + { + outputFile << profilePropertyPair.PropertyKey << EQ << profilePropertyValue << std::endl; + } + } + + if(profile.second.IsSsoSessionSet()) + { + const auto& ssoSession = profile.second.GetSsoSession(); + const auto alreadyScheduledForDumpIt = ssoSessionsToDump.find(ssoSession.GetName()); + if (alreadyScheduledForDumpIt != ssoSessionsToDump.end() && + alreadyScheduledForDumpIt->second.get() != ssoSession) + { + AWS_LOGSTREAM_WARN(CONFIG_FILE_LOADER, "2 or more profiles reference 'sso-session' section " + "with the same name but different properties: " << ssoSession.GetName()); + } + else + { + ssoSessionsToDump.insert({ssoSession.GetName(), std::cref(ssoSession)}); + } + outputFile << SSO_SESSION_KEY << EQ << ssoSession.GetName() << std::endl; + } + outputFile << std::endl; + } + + for(const auto& ssoSessionPair : ssoSessionsToDump) + { + AWS_LOGSTREAM_DEBUG(CONFIG_FILE_LOADER, "Writing sso-session " << ssoSessionPair.first << " to disk."); + const Profile::SsoSession& ssoSession = ssoSessionPair.second.get(); + outputFile << LEFT_BRACKET << SSO_SESSION_SECTION << " " << ssoSession.GetName() << RIGHT_BRACKET << std::endl; + for(const auto& ssoSessionPropertyPair : SSO_SESSION_PROPERTY_FUNCS) + { + const auto& profilePropertyValue = ssoSessionPropertyPair.Getter(ssoSession); + if(!profilePropertyValue.empty()) + { + outputFile << ssoSessionPropertyPair.PropertyKey << EQ << profilePropertyValue << std::endl; + } + } + outputFile << std::endl; + } + + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Profiles written to config file " << m_fileName); + + return true; + } + + AWS_LOGSTREAM_WARN(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for writing."); + + return false; + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp deleted file mode 100644 index bb6acd0b3a..0000000000 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/** - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -#include <aws/core/config/AWSProfileConfigLoader.h> -#include <aws/core/internal/AWSHttpResourceClient.h> -#include <aws/core/auth/AWSCredentialsProvider.h> -#include <aws/core/utils/memory/stl/AWSList.h> -#include <aws/core/utils/memory/stl/AWSStreamFwd.h> -#include <aws/core/utils/StringUtils.h> -#include <aws/core/utils/logging/LogMacros.h> -#include <aws/core/utils/json/JsonSerializer.h> -#include <fstream> - -namespace Aws -{ - namespace Config - { - using namespace Aws::Utils; - using namespace Aws::Auth; - - static const char* const CONFIG_LOADER_TAG = "Aws::Config::AWSProfileConfigLoader"; - #ifdef _MSC_VER - // VS2015 compiler's bug, warning s_CoreErrorsMapper: symbol will be dynamically initialized (implementation limitation) - AWS_SUPPRESS_WARNING(4592, - static Aws::UniquePtr<ConfigAndCredentialsCacheManager> s_configManager(nullptr); - ) - #else - static Aws::UniquePtr<ConfigAndCredentialsCacheManager> s_configManager(nullptr); - #endif - - static const char CONFIG_CREDENTIALS_CACHE_MANAGER_TAG[] = "ConfigAndCredentialsCacheManager"; - - bool AWSProfileConfigLoader::Load() - { - if(LoadInternal()) - { - AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Successfully reloaded configuration."); - m_lastLoadTime = DateTime::Now(); - AWS_LOGSTREAM_TRACE(CONFIG_LOADER_TAG, "reloaded config at " - << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); - return true; - } - - AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Failed to reload configuration."); - return false; - } - - bool AWSProfileConfigLoader::PersistProfiles(const Aws::Map<Aws::String, Profile>& profiles) - { - if(PersistInternal(profiles)) - { - AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Successfully persisted configuration."); - m_profiles = profiles; - m_lastLoadTime = DateTime::Now(); - AWS_LOGSTREAM_TRACE(CONFIG_LOADER_TAG, "persisted config at " - << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); - return true; - } - - AWS_LOGSTREAM_WARN(CONFIG_LOADER_TAG, "Failed to persist configuration."); - return false; - } - - static const char REGION_KEY[] = "region"; - static const char ACCESS_KEY_ID_KEY[] = "aws_access_key_id"; - static const char SECRET_KEY_KEY[] = "aws_secret_access_key"; - static const char SESSION_TOKEN_KEY[] = "aws_session_token"; - static const char SSO_START_URL_KEY[] = "sso_start_url"; - static const char SSO_REGION_KEY[] = "sso_region"; - static const char SSO_ACCOUNT_ID_KEY[] = "sso_account_id"; - static const char SSO_ROLE_NAME_KEY[] = "sso_role_name"; - static const char ROLE_ARN_KEY[] = "role_arn"; - static const char EXTERNAL_ID_KEY[] = "external_id"; - static const char CREDENTIAL_PROCESS_COMMAND[] = "credential_process"; - static const char SOURCE_PROFILE_KEY[] = "source_profile"; - static const char PROFILE_PREFIX[] = "profile "; - static const char EQ = '='; - static const char LEFT_BRACKET = '['; - static const char RIGHT_BRACKET = ']'; - static const char PARSER_TAG[] = "Aws::Config::ConfigFileProfileFSM"; - - class ConfigFileProfileFSM - { - public: - ConfigFileProfileFSM() : m_parserState(START) {} - - const Aws::Map<String, Profile>& GetProfiles() const { return m_foundProfiles; } - - void ParseStream(Aws::IStream& stream) - { - static const size_t ASSUME_EMPTY_LEN = 3; - - Aws::String line; - while(std::getline(stream, line) && m_parserState != FAILURE) - { - if (line.empty() || line.length() < ASSUME_EMPTY_LEN) - { - continue; - } - - auto openPos = line.find(LEFT_BRACKET); - auto closePos = line.find(RIGHT_BRACKET); - - switch(m_parserState) - { - - case START: - if(openPos != std::string::npos && closePos != std::string::npos) - { - FlushProfileAndReset(line, openPos, closePos); - m_parserState = PROFILE_FOUND; - } - break; - - //fallthrough here is intentional to reduce duplicate logic - case PROFILE_KEY_VALUE_FOUND: - if(openPos != std::string::npos && closePos != std::string::npos) - { - m_parserState = PROFILE_FOUND; - FlushProfileAndReset(line, openPos, closePos); - break; - } - // fall through - case PROFILE_FOUND: - { - auto equalsPos = line.find(EQ); - if (equalsPos != std::string::npos) - { - auto key = line.substr(0, equalsPos); - auto value = line.substr(equalsPos + 1); - m_profileKeyValuePairs[StringUtils::Trim(key.c_str())] = - StringUtils::Trim(value.c_str()); - m_parserState = PROFILE_KEY_VALUE_FOUND; - } - - break; - } - default: - m_parserState = FAILURE; - break; - } - } - - FlushProfileAndReset(line, std::string::npos, std::string::npos); - } - - private: - - void FlushProfileAndReset(Aws::String& line, size_t openPos, size_t closePos) - { - if(!m_currentWorkingProfile.empty() && !m_profileKeyValuePairs.empty()) - { - Profile profile; - profile.SetName(m_currentWorkingProfile); - - auto regionIter = m_profileKeyValuePairs.find(REGION_KEY); - if (regionIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found region " << regionIter->second); - profile.SetRegion(regionIter->second); - } - - auto accessKeyIdIter = m_profileKeyValuePairs.find(ACCESS_KEY_ID_KEY); - Aws::String accessKey, secretKey, sessionToken; - if (accessKeyIdIter != m_profileKeyValuePairs.end()) - { - accessKey = accessKeyIdIter->second; - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found access key " << accessKey); - - auto secretAccessKeyIter = m_profileKeyValuePairs.find(SECRET_KEY_KEY); - auto sessionTokenIter = m_profileKeyValuePairs.find(SESSION_TOKEN_KEY); - if (secretAccessKeyIter != m_profileKeyValuePairs.end()) - { - secretKey = secretAccessKeyIter->second; - } - else - { - AWS_LOGSTREAM_ERROR(PARSER_TAG, "No secret access key found even though an access key was specified. This will cause all signed AWS calls to fail."); - } - - if (sessionTokenIter != m_profileKeyValuePairs.end()) - { - sessionToken = sessionTokenIter->second; - } - - profile.SetCredentials(Aws::Auth::AWSCredentials(accessKey, secretKey, sessionToken)); - } - - auto ssoStartUrlIter = m_profileKeyValuePairs.find(SSO_START_URL_KEY); - auto ssoRegionIter = m_profileKeyValuePairs.find(SSO_REGION_KEY); - auto ssoRoleNameIter = m_profileKeyValuePairs.find(SSO_ROLE_NAME_KEY); - auto ssoAccountIdIter = m_profileKeyValuePairs.find(SSO_ACCOUNT_ID_KEY); - if (ssoStartUrlIter != m_profileKeyValuePairs.end() - || ssoRegionIter != m_profileKeyValuePairs.end() - || ssoRoleNameIter != m_profileKeyValuePairs.end() - || ssoAccountIdIter != m_profileKeyValuePairs.end()) - { - if (ssoStartUrlIter != m_profileKeyValuePairs.end() - && ssoRegionIter != m_profileKeyValuePairs.end() - && ssoRoleNameIter != m_profileKeyValuePairs.end() - && ssoAccountIdIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_start_url " << ssoStartUrlIter->second); - profile.SetSsoStartUrl(ssoStartUrlIter->second); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_region " << ssoRegionIter->second); - profile.SetSsoRegion(ssoRegionIter->second); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_account_id " << ssoAccountIdIter->second); - profile.SetSsoAccountId(ssoAccountIdIter->second); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_role_name " << ssoRoleNameIter->second); - profile.SetSsoRoleName(ssoRoleNameIter->second); - } else { - AWS_LOGSTREAM_ERROR(PARSER_TAG, "invalid configuration for sso profile " << profile.GetName()); - } - } - - auto assumeRoleArnIter = m_profileKeyValuePairs.find(ROLE_ARN_KEY); - if (assumeRoleArnIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found role arn " << assumeRoleArnIter->second); - profile.SetRoleArn(assumeRoleArnIter->second); - } - - auto externalIdIter = m_profileKeyValuePairs.find(EXTERNAL_ID_KEY); - if (externalIdIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found external id " << externalIdIter->second); - profile.SetExternalId(externalIdIter->second); - } - - auto sourceProfileIter = m_profileKeyValuePairs.find(SOURCE_PROFILE_KEY); - if (sourceProfileIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found source profile " << sourceProfileIter->second); - profile.SetSourceProfile(sourceProfileIter->second); - } - - auto credentialProcessIter = m_profileKeyValuePairs.find(CREDENTIAL_PROCESS_COMMAND); - if (credentialProcessIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found credential process " << credentialProcessIter->second); - profile.SetCredentialProcess(credentialProcessIter->second); - } - profile.SetAllKeyValPairs(m_profileKeyValuePairs); - - m_foundProfiles[profile.GetName()] = std::move(profile); - m_currentWorkingProfile.clear(); - m_profileKeyValuePairs.clear(); - } - - if(!line.empty() && openPos != std::string::npos && closePos != std::string::npos) - { - m_currentWorkingProfile = StringUtils::Trim(line.substr(openPos + 1, closePos - openPos - 1).c_str()); - StringUtils::Replace(m_currentWorkingProfile, PROFILE_PREFIX, ""); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found profile " << m_currentWorkingProfile); - } - } - - enum State - { - START = 0, - PROFILE_FOUND, - PROFILE_KEY_VALUE_FOUND, - FAILURE - }; - - Aws::String m_currentWorkingProfile; - Aws::Map<String, String> m_profileKeyValuePairs; - State m_parserState; - Aws::Map<String, Profile> m_foundProfiles; - }; - - static const char* const CONFIG_FILE_LOADER = "Aws::Config::AWSConfigFileProfileConfigLoader"; - - AWSConfigFileProfileConfigLoader::AWSConfigFileProfileConfigLoader(const Aws::String& fileName, bool useProfilePrefix) : - m_fileName(fileName), m_useProfilePrefix(useProfilePrefix) - { - AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Initializing config loader against fileName " - << fileName << " and using profilePrefix = " << useProfilePrefix); - } - - bool AWSConfigFileProfileConfigLoader::LoadInternal() - { - m_profiles.clear(); - - Aws::IFStream inputFile(m_fileName.c_str()); - if(inputFile) - { - ConfigFileProfileFSM parser; - parser.ParseStream(inputFile); - m_profiles = parser.GetProfiles(); - return m_profiles.size() > 0; - } - - AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for reading."); - - return false; - } - - bool AWSConfigFileProfileConfigLoader::PersistInternal(const Aws::Map<Aws::String, Profile>& profiles) - { - Aws::OFStream outputFile(m_fileName.c_str(), std::ios_base::out | std::ios_base::trunc); - if(outputFile) - { - for(auto& profile : profiles) - { - Aws::String prefix = m_useProfilePrefix ? PROFILE_PREFIX : ""; - - AWS_LOGSTREAM_DEBUG(CONFIG_FILE_LOADER, "Writing profile " << profile.first << " to disk."); - - outputFile << LEFT_BRACKET << prefix << profile.second.GetName() << RIGHT_BRACKET << std::endl; - const Aws::Auth::AWSCredentials& credentials = profile.second.GetCredentials(); - outputFile << ACCESS_KEY_ID_KEY << EQ << credentials.GetAWSAccessKeyId() << std::endl; - outputFile << SECRET_KEY_KEY << EQ << credentials.GetAWSSecretKey() << std::endl; - - if(!credentials.GetSessionToken().empty()) - { - outputFile << SESSION_TOKEN_KEY << EQ << credentials.GetSessionToken() << std::endl; - } - - if(!profile.second.GetRegion().empty()) - { - outputFile << REGION_KEY << EQ << profile.second.GetRegion() << std::endl; - } - - if(!profile.second.GetRoleArn().empty()) - { - outputFile << ROLE_ARN_KEY << EQ << profile.second.GetRoleArn() << std::endl; - } - - if(!profile.second.GetSourceProfile().empty()) - { - outputFile << SOURCE_PROFILE_KEY << EQ << profile.second.GetSourceProfile() << std::endl; - } - - outputFile << std::endl; - } - - AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Profiles written to config file " << m_fileName); - - return true; - } - - AWS_LOGSTREAM_WARN(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for writing."); - - return false; - } - - static const char* const EC2_INSTANCE_PROFILE_LOG_TAG = "Aws::Config::EC2InstanceProfileConfigLoader"; - - EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& client) - : m_ec2metadataClient(client == nullptr ? Aws::MakeShared<Aws::Internal::EC2MetadataClient>(EC2_INSTANCE_PROFILE_LOG_TAG) : client) - { - } - - bool EC2InstanceProfileConfigLoader::LoadInternal() - { - auto credentialsStr = m_ec2metadataClient->GetDefaultCredentialsSecurely(); - if(credentialsStr.empty()) return false; - - Json::JsonValue credentialsDoc(credentialsStr); - if (!credentialsDoc.WasParseSuccessful()) - { - AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, - "Failed to parse output from EC2MetadataService."); - return false; - } - const char* accessKeyId = "AccessKeyId"; - const char* secretAccessKey = "SecretAccessKey"; - Aws::String accessKey, secretKey, token; - - auto credentialsView = credentialsDoc.View(); - accessKey = credentialsView.GetString(accessKeyId); - AWS_LOGSTREAM_INFO(EC2_INSTANCE_PROFILE_LOG_TAG, - "Successfully pulled credentials from metadata service with access key " << accessKey); - - secretKey = credentialsView.GetString(secretAccessKey); - token = credentialsView.GetString("Token"); - - auto region = m_ec2metadataClient->GetCurrentRegion(); - - Profile profile; - profile.SetCredentials(AWSCredentials(accessKey, secretKey, token)); - profile.SetRegion(region); - profile.SetName(INSTANCE_PROFILE_KEY); - - m_profiles[INSTANCE_PROFILE_KEY] = profile; - - return true; - } - - ConfigAndCredentialsCacheManager::ConfigAndCredentialsCacheManager() : - m_credentialsFileLoader(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()), - m_configFileLoader(Aws::Auth::GetConfigProfileFilename(), true/*use profile prefix*/) - { - ReloadCredentialsFile(); - ReloadConfigFile(); - } - - void ConfigAndCredentialsCacheManager::ReloadConfigFile() - { - Aws::Utils::Threading::WriterLockGuard guard(m_configLock); - m_configFileLoader.SetFileName(Aws::Auth::GetConfigProfileFilename()); - m_configFileLoader.Load(); - } - - void ConfigAndCredentialsCacheManager::ReloadCredentialsFile() - { - Aws::Utils::Threading::WriterLockGuard guard(m_credentialsLock); - m_credentialsFileLoader.SetFileName(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()); - m_credentialsFileLoader.Load(); - } - - bool ConfigAndCredentialsCacheManager::HasConfigProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - return (m_configFileLoader.GetProfiles().count(profileName) == 1); - } - - Aws::Config::Profile ConfigAndCredentialsCacheManager::GetConfigProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - const auto& profiles = m_configFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second; - } - - Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetConfigProfiles() const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - return m_configFileLoader.GetProfiles(); - } - - Aws::String ConfigAndCredentialsCacheManager::GetConfig(const Aws::String& profileName, const Aws::String& key) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - const auto& profiles = m_configFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second.GetValue(key); - } - - bool ConfigAndCredentialsCacheManager::HasCredentialsProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - return (m_credentialsFileLoader.GetProfiles().count(profileName) == 1); - } - - Aws::Config::Profile ConfigAndCredentialsCacheManager::GetCredentialsProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - const auto &profiles = m_credentialsFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second; - } - - Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetCredentialsProfiles() const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - return m_credentialsFileLoader.GetProfiles(); - } - - Aws::Auth::AWSCredentials ConfigAndCredentialsCacheManager::GetCredentials(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - const auto& profiles = m_credentialsFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second.GetCredentials(); - } - - void InitConfigAndCredentialsCacheManager() - { - if (s_configManager) - { - return; - } - s_configManager = Aws::MakeUnique<ConfigAndCredentialsCacheManager>(CONFIG_CREDENTIALS_CACHE_MANAGER_TAG); - } - - void CleanupConfigAndCredentialsCacheManager() - { - if (!s_configManager) - { - return; - } - s_configManager = nullptr; - } - - void ReloadCachedConfigFile() - { - assert(s_configManager); - s_configManager->ReloadConfigFile(); - } - - void ReloadCachedCredentialsFile() - { - assert(s_configManager); - s_configManager->ReloadCredentialsFile(); - } - - bool HasCachedConfigProfile(const Aws::String& profileName) - { - assert(s_configManager); - return s_configManager->HasConfigProfile(profileName); - } - - Aws::Config::Profile GetCachedConfigProfile(const Aws::String& profileName) - { - assert(s_configManager); - return s_configManager->GetConfigProfile(profileName); - } - - Aws::Map<Aws::String, Aws::Config::Profile> GetCachedConfigProfiles() - { - assert(s_configManager); - return s_configManager->GetConfigProfiles(); - } - - Aws::String GetCachedConfigValue(const Aws::String &profileName, const Aws::String &key) - { - assert(s_configManager); - return s_configManager->GetConfig(profileName, key); - } - - Aws::String GetCachedConfigValue(const Aws::String &key) - { - assert(s_configManager); - return s_configManager->GetConfig(Aws::Auth::GetConfigProfileName(), key); - } - - bool HasCachedCredentialsProfile(const Aws::String& profileName) - { - assert(s_configManager); - return s_configManager->HasCredentialsProfile(profileName); - } - - Aws::Config::Profile GetCachedCredentialsProfile(const Aws::String &profileName) - { - assert(s_configManager); - return s_configManager->GetCredentialsProfile(profileName); - } - - Aws::Map<Aws::String, Aws::Config::Profile> GetCachedCredentialsProfiles() - { - assert(s_configManager); - return s_configManager->GetCredentialsProfiles(); - } - - Aws::Auth::AWSCredentials GetCachedCredentials(const Aws::String &profileName) - { - assert(s_configManager); - return s_configManager->GetCredentials(profileName); - } - } // Config namespace -} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoaderBase.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoaderBase.cpp new file mode 100644 index 0000000000..cb7b19d0ce --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoaderBase.cpp @@ -0,0 +1,50 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/AWSProfileConfigLoaderBase.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <fstream> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + static const char* const CONFIG_LOADER_BASE_TAG = "Aws::Config::AWSProfileConfigLoaderBase"; + + bool AWSProfileConfigLoader::Load() + { + if(LoadInternal()) + { + AWS_LOGSTREAM_INFO(CONFIG_LOADER_BASE_TAG, "Successfully reloaded configuration."); + m_lastLoadTime = DateTime::Now(); + AWS_LOGSTREAM_TRACE(CONFIG_LOADER_BASE_TAG, "reloaded config at " + << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); + return true; + } + + AWS_LOGSTREAM_INFO(CONFIG_LOADER_BASE_TAG, "Failed to reload configuration."); + return false; + } + + bool AWSProfileConfigLoader::PersistProfiles(const Aws::Map<Aws::String, Profile>& profiles) + { + if(PersistInternal(profiles)) + { + AWS_LOGSTREAM_INFO(CONFIG_LOADER_BASE_TAG, "Successfully persisted configuration."); + m_profiles = profiles; + m_lastLoadTime = DateTime::Now(); + AWS_LOGSTREAM_TRACE(CONFIG_LOADER_BASE_TAG, "persisted config at " + << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); + return true; + } + + AWS_LOGSTREAM_WARN(CONFIG_LOADER_BASE_TAG, "Failed to persist configuration."); + return false; + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/ConfigAndCredentialsCacheManager.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/ConfigAndCredentialsCacheManager.cpp new file mode 100644 index 0000000000..b47fe72a0a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/ConfigAndCredentialsCacheManager.cpp @@ -0,0 +1,206 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/ConfigAndCredentialsCacheManager.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/utils/memory/stl/AWSList.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <fstream> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + #ifdef _MSC_VER + // VS2015 compiler's bug, warning s_CoreErrorsMapper: symbol will be dynamically initialized (implementation limitation) + AWS_SUPPRESS_WARNING(4592, + static ConfigAndCredentialsCacheManager* s_configManager(nullptr); + ) + #else + static ConfigAndCredentialsCacheManager* s_configManager(nullptr); + #endif + + static const char CONFIG_CREDENTIALS_CACHE_MANAGER_TAG[] = "ConfigAndCredentialsCacheManager"; + + + ConfigAndCredentialsCacheManager::ConfigAndCredentialsCacheManager() : + m_credentialsFileLoader(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()), + m_configFileLoader(Aws::Auth::GetConfigProfileFilename(), true/*use profile prefix*/) + { + ReloadCredentialsFile(); + ReloadConfigFile(); + } + + void ConfigAndCredentialsCacheManager::ReloadConfigFile() + { + Aws::Utils::Threading::WriterLockGuard guard(m_configLock); + m_configFileLoader.SetFileName(Aws::Auth::GetConfigProfileFilename()); + m_configFileLoader.Load(); + } + + void ConfigAndCredentialsCacheManager::ReloadCredentialsFile() + { + Aws::Utils::Threading::WriterLockGuard guard(m_credentialsLock); + m_credentialsFileLoader.SetFileName(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()); + m_credentialsFileLoader.Load(); + } + + bool ConfigAndCredentialsCacheManager::HasConfigProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + return (m_configFileLoader.GetProfiles().count(profileName) == 1); + } + + Aws::Config::Profile ConfigAndCredentialsCacheManager::GetConfigProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + const auto& profiles = m_configFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second; + } + + Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetConfigProfiles() const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + return m_configFileLoader.GetProfiles(); + } + + Aws::String ConfigAndCredentialsCacheManager::GetConfig(const Aws::String& profileName, const Aws::String& key) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + const auto& profiles = m_configFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second.GetValue(key); + } + + bool ConfigAndCredentialsCacheManager::HasCredentialsProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + return (m_credentialsFileLoader.GetProfiles().count(profileName) == 1); + } + + Aws::Config::Profile ConfigAndCredentialsCacheManager::GetCredentialsProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + const auto &profiles = m_credentialsFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second; + } + + Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetCredentialsProfiles() const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + return m_credentialsFileLoader.GetProfiles(); + } + + Aws::Auth::AWSCredentials ConfigAndCredentialsCacheManager::GetCredentials(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + const auto& profiles = m_credentialsFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second.GetCredentials(); + } + + void InitConfigAndCredentialsCacheManager() + { + if (s_configManager) + { + return; + } + s_configManager = Aws::New<ConfigAndCredentialsCacheManager>(CONFIG_CREDENTIALS_CACHE_MANAGER_TAG); + } + + void CleanupConfigAndCredentialsCacheManager() + { + Aws::Delete(s_configManager); + s_configManager = nullptr; + } + + void ReloadCachedConfigFile() + { + assert(s_configManager); + s_configManager->ReloadConfigFile(); + } + + void ReloadCachedCredentialsFile() + { + assert(s_configManager); + s_configManager->ReloadCredentialsFile(); + } + + bool HasCachedConfigProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->HasConfigProfile(profileName); + } + + Aws::Config::Profile GetCachedConfigProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->GetConfigProfile(profileName); + } + + Aws::Map<Aws::String, Aws::Config::Profile> GetCachedConfigProfiles() + { + assert(s_configManager); + return s_configManager->GetConfigProfiles(); + } + + Aws::String GetCachedConfigValue(const Aws::String &profileName, const Aws::String &key) + { + assert(s_configManager); + return s_configManager->GetConfig(profileName, key); + } + + Aws::String GetCachedConfigValue(const Aws::String &key) + { + assert(s_configManager); + return s_configManager->GetConfig(Aws::Auth::GetConfigProfileName(), key); + } + + bool HasCachedCredentialsProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->HasCredentialsProfile(profileName); + } + + Aws::Config::Profile GetCachedCredentialsProfile(const Aws::String &profileName) + { + assert(s_configManager); + return s_configManager->GetCredentialsProfile(profileName); + } + + Aws::Map<Aws::String, Aws::Config::Profile> GetCachedCredentialsProfiles() + { + assert(s_configManager); + return s_configManager->GetCredentialsProfiles(); + } + + Aws::Auth::AWSCredentials GetCachedCredentials(const Aws::String &profileName) + { + assert(s_configManager); + return s_configManager->GetCredentials(profileName); + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp new file mode 100644 index 0000000000..0b505b2c00 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp @@ -0,0 +1,112 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/utils/memory/stl/AWSList.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <fstream> +#include <random> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + static const char* const INTERNAL_EXCEPTION_PHRASE = "InternalServiceException"; + static const int64_t FIVE_MINUTE_MILLIS = 60000 * 5; + static const int64_t TEN_MINUTE_MILLIS = 60000 * 10; + + static const char* const EC2_INSTANCE_PROFILE_LOG_TAG = "Aws::Config::EC2InstanceProfileConfigLoader"; + + EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& client) + { + if(client == nullptr) + { + Aws::Internal::InitEC2MetadataClient(); + m_ec2metadataClient = Aws::Internal::GetEC2MetadataClient(); + } + else + { + m_ec2metadataClient = client; + } + } + + bool EC2InstanceProfileConfigLoader::LoadInternal() + { + // re-use old credentials until we need to call IMDS again. + if (DateTime::Now().Millis() < this->credentialsValidUntilMillis) { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "Skipping IMDS call until " << this->credentialsValidUntilMillis); + return true; + } + this->credentialsValidUntilMillis = DateTime::Now().Millis(); + + if (!m_ec2metadataClient) { + AWS_LOGSTREAM_FATAL(EC2_INSTANCE_PROFILE_LOG_TAG, "EC2MetadataClient is a nullptr!") + return false; + } + auto credentialsStr = m_ec2metadataClient->GetDefaultCredentialsSecurely(); + if(credentialsStr.empty()) return false; + + Json::JsonValue credentialsDoc(credentialsStr); + if (!credentialsDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "Failed to parse output from EC2MetadataService."); + return false; + } + + const char* accessKeyId = "AccessKeyId"; + const char* secretAccessKey = "SecretAccessKey"; + const char* expiration = "Expiration"; + const char* code = "Code"; + Aws::String accessKey, secretKey, token; + + auto credentialsView = credentialsDoc.View(); + DateTime expirationTime(credentialsView.GetString(expiration), Aws::Utils::DateFormat::ISO_8601); + // re-use old credentials and not block if the IMDS call failed or if the latest credential is in the past + if (expirationTime.WasParseSuccessful() && DateTime::Now() > expirationTime) { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "Expiration Time of Credentials in the past, refusing to update credentials"); + this->credentialsValidUntilMillis = DateTime::Now().Millis() + calculateRetryTime(); + return true; + } else if (credentialsView.GetString(code) == INTERNAL_EXCEPTION_PHRASE) { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "IMDS call failed, refusing to update credentials"); + this->credentialsValidUntilMillis = DateTime::Now().Millis() + calculateRetryTime(); + return true; + } + accessKey = credentialsView.GetString(accessKeyId); + AWS_LOGSTREAM_INFO(EC2_INSTANCE_PROFILE_LOG_TAG, + "Successfully pulled credentials from metadata service with access key " << accessKey); + + secretKey = credentialsView.GetString(secretAccessKey); + token = credentialsView.GetString("Token"); + + auto region = m_ec2metadataClient->GetCurrentRegion(); + + Profile profile; + profile.SetCredentials(AWSCredentials(accessKey, secretKey, token)); + profile.SetRegion(region); + profile.SetName(INSTANCE_PROFILE_KEY); + + m_profiles[INSTANCE_PROFILE_KEY] = profile; + + return true; + } + + int64_t EC2InstanceProfileConfigLoader::calculateRetryTime() const { + std::random_device rd; + std::mt19937_64 gen(rd()); + std::uniform_int_distribution<int64_t> dist(FIVE_MINUTE_MILLIS, TEN_MINUTE_MILLIS); + return dist(gen); + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/defaults/ClientConfigurationDefaults.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/defaults/ClientConfigurationDefaults.cpp new file mode 100644 index 0000000000..7b54066fb3 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/defaults/ClientConfigurationDefaults.cpp @@ -0,0 +1,197 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +/** + * Please note that this file is autogenerated. + * The backwards compatibility of the default values provided by new client configuration defaults is not guaranteed; + * the values might change over time. + */ + +#include <aws/common/platform.h> // for AWS_OS_IOS macro +#include <aws/core/config/defaults/ClientConfigurationDefaults.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> + +namespace Aws +{ + namespace Config + { + namespace Defaults + { + static const char* CLIENT_CONFIG_DEFAULTS_TAG = "ClientConfigurationDefaults"; + + void SetSmartDefaultsConfigurationParameters(Aws::Client::ClientConfiguration& clientConfig, + const Aws::String& defaultMode, + bool hasEc2MetadataRegion, + const Aws::String& ec2MetadataRegion) + { + const Aws::String caseInsensitiveMode = ResolveDefaultModeName(clientConfig, + defaultMode, + Aws::Config::GetCachedConfigValue("defaults_mode"), + hasEc2MetadataRegion, + ec2MetadataRegion); + + if(caseInsensitiveMode == "legacy") + { + return SetLegacyClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "standard") + { + return SetStandardClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "in-region") + { + return SetInRegionClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "cross-region") + { + return SetCrossRegionClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "mobile") + { + return SetMobileClientConfiguration(clientConfig); + } + return SetLegacyClientConfiguration(clientConfig); + } + + bool isMobile() + { +#if defined(AWS_OS_IOS) || defined (__ANDROID__) + return true; +#else + return false; +#endif + } + + const char* ResolveAutoClientConfiguration(const Aws::Client::ClientConfiguration& clientConfig, + const Aws::String& ec2MetadataRegion) + { + // Check if we're on mobile, CPP SDK is statically built, so we can check how we were built + if(isMobile()) + { + return "mobile"; + } + // We're not on mobile (best we can tell). See if we can determine whether we're an in-region or + // cross-region client. + Aws::String current_region; + Aws::String env_region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); + if(!Aws::Environment::GetEnv("AWS_EXECUTION_ENV").empty()) + { + // We're running in an AWS service environment, so we can trust the region environment variables + // to be the current region, if they're set + current_region = Aws::Environment::GetEnv("AWS_REGION"); + if(current_region.empty()) + { + current_region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); + } + } + if(current_region.empty()) + { + current_region = ec2MetadataRegion; + } + if(!current_region.empty() && !clientConfig.region.empty()) + { + if(current_region == clientConfig.region) + { + return "in-region"; + } + else + { + return "cross-region"; + } + } + // We don't seem to be mobile, and we couldn't determine whether we're running within an AWS region. + // Fall back to standard. + return "standard"; + } + + void SetLegacyClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("default"); + } + + void SetStandardClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 3100; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + void SetInRegionClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 1100; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + void SetCrossRegionClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 3100; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + void SetMobileClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 30000; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + Aws::String ResolveDefaultModeName(const Aws::Client::ClientConfiguration& clientConfig, + Aws::String requestedDefaultMode, + const Aws::String& configFileDefaultMode, + bool hasEc2MetadataRegion, + Aws::String ec2MetadataRegion) + { + if (requestedDefaultMode.empty()) + { + requestedDefaultMode = Aws::Environment::GetEnv("AWS_DEFAULTS_MODE"); + } + if (requestedDefaultMode.empty()) + { + requestedDefaultMode = configFileDefaultMode; + } + if (Aws::Utils::StringUtils::ToLower(requestedDefaultMode.c_str()) == "auto") + { + if (!hasEc2MetadataRegion && + Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true") + { + auto client = Aws::Internal::GetEC2MetadataClient(); + if (client) + { + ec2MetadataRegion = client->GetCurrentRegion(); + } + } + requestedDefaultMode = ResolveAutoClientConfiguration(clientConfig, ec2MetadataRegion); + return requestedDefaultMode; + } + if (requestedDefaultMode.empty()) + { + requestedDefaultMode = "legacy"; + return requestedDefaultMode; + } + + requestedDefaultMode = Aws::Utils::StringUtils::ToLower(requestedDefaultMode.c_str()); + if (requestedDefaultMode != "legacy" && + requestedDefaultMode != "standard" && + requestedDefaultMode != "in-region" && + requestedDefaultMode != "cross-region" && + requestedDefaultMode != "mobile") + { + AWS_LOGSTREAM_WARN(CLIENT_CONFIG_DEFAULTS_TAG, "User specified client configuration: [" + << requestedDefaultMode + << "] is not found, will use the SDK default legacy one."); + requestedDefaultMode = "legacy"; + } + return requestedDefaultMode; + } + } //namespace Defaults + } //namespace Config +} //namespace Aws |