123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 |
- /**
- * 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
|