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/AWSConfigFileProfileConfigLoader.cpp | |
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/AWSConfigFileProfileConfigLoader.cpp')
-rw-r--r-- | contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp | 629 |
1 files changed, 629 insertions, 0 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 |