aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp
diff options
context:
space:
mode:
authordakovalkov <dakovalkov@yandex-team.com>2023-12-03 13:33:55 +0300
committerdakovalkov <dakovalkov@yandex-team.com>2023-12-03 14:04:39 +0300
commit2a718325637e5302334b6d0a6430f63168f8dbb3 (patch)
tree64be81080b7df9ec1d86d053a0c394ae53fcf1fe /contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp
parente0d94a470142d95c3007e9c5d80380994940664a (diff)
downloadydb-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.cpp629
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