Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/aws-cpp-sdk-core/include/aws/core/config/AWSProfileConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/core/utils/memory/stl/AWSMap.h>
#include <aws/core/auth/AWSCredentials.h>
#include <aws/crt/Optional.h>

namespace Aws
{
Expand All @@ -19,6 +20,24 @@ namespace Aws
class Profile
{
public:
/*
* Data container for service endpoints.
*/
class Services
{
public:
Services() = default;
Services(Aws::Map<Aws::String, Aws::String>&& endpoints, Aws::String name)
: m_endpoints(std::move(endpoints)), m_name(std::move(name)) {}

inline Aws::Map<Aws::String, Aws::String> GetEndpoints() const { return m_endpoints; }
inline Aws::String GetServiceBlockName() const { return m_name; }
inline bool IsSet() const { return !m_name.empty(); }
private:
Aws::Map<Aws::String, Aws::String> m_endpoints;
Aws::String m_name;
};

/*
* Data container for a sso-session config entry.
* This is independent of the general profile configuration and used by a bearer auth token provider.
Expand Down Expand Up @@ -84,6 +103,10 @@ namespace Aws
inline void SetSourceProfile(const Aws::String& value ) { m_sourceProfile = value; }
inline const Aws::String& GetCredentialProcess() const { return m_credentialProcess; }
inline void SetCredentialProcess(const Aws::String& value ) { m_credentialProcess = value; }
inline const Aws::String& GetGlobalEndpointUrl() const { return m_endpointUrl; }
inline void SetGlobalEndpointUrl(const Aws::String& value) { m_endpointUrl = value; }
inline Services GetServices() const { return m_services; }
inline void SetServices(Services&& services) { m_services = std::move(services); }
inline void SetAllKeyValPairs(const Aws::Map<Aws::String, Aws::String>& map) { m_allKeyValPairs = map; }
inline void SetAllKeyValPairs(Aws::Map<Aws::String, Aws::String>&& map) { m_allKeyValPairs = std::move(map); }
inline const Aws::String GetValue(const Aws::String& key) const
Expand Down Expand Up @@ -111,7 +134,9 @@ namespace Aws
Aws::String m_ssoAccountId;
Aws::String m_ssoRoleName;
Aws::String m_defaultsMode;
Aws::String m_endpointUrl;
Aws::Map<Aws::String, Aws::String> m_allKeyValPairs;
Services m_services;

bool m_ssoSessionSet = false;
SsoSession m_ssoSession;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ namespace Aws
static const char PROFILE_SECTION[] = "profile";
static const char DEFAULT[] = "default";
static const char SSO_SESSION_SECTION[] = "sso-session";
static const char SERVICES_SECTION[] = "services";
static const char ENDPOINT_URL_KEY[] = "endpoint_url";
static const char IGNORE_CONFIGURED_ENDPOINT_URLS_KEY[] = "ignore_configured_endpoint_urls";
static const char DEFAULTS_MODE_KEY[] = "defaults_mode";
static const char EQ = '=';
static const char LEFT_BRACKET = '[';
Expand Down Expand Up @@ -74,7 +77,8 @@ namespace Aws
{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}};
{DEFAULTS_MODE_KEY, &Profile::SetDefaultsMode, &Profile::GetDefaultsMode},
{ENDPOINT_URL_KEY, &Profile::SetGlobalEndpointUrl, &Profile::GetGlobalEndpointUrl}};

template<typename EntryT, size_t N>
const EntryT* FindInStaticArray(const EntryT (&array)[N], const Aws::String& searchKey)
Expand Down Expand Up @@ -119,6 +123,7 @@ namespace Aws
static const size_t ASSUME_EMPTY_LEN = 3;
State currentState = START;
Aws::String currentSectionName;
Aws::String activeServiceId;
Aws::Map<Aws::String, Aws::String> currentKeyValues;

Aws::String rawLine;
Expand All @@ -142,6 +147,7 @@ namespace Aws
{
FlushSection(currentState, currentSectionName, currentKeyValues);
currentKeyValues.clear();
activeServiceId.clear();
ParseSectionDeclaration(line, currentSectionName, currentState);
continue;
}
Expand All @@ -158,6 +164,36 @@ namespace Aws
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we not handling global endpoint URL's for all services?
Ex.

[profile dev-global]
endpoint_url = https://play.min.io:9000

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global endpoint URL is handled by the FlushSection, and added directly to the profile

}

if(SERVICES_FOUND == currentState)
{
auto equalsPos = line.find(EQ);
if (equalsPos == std::string::npos) {
continue; // ignore garbage/blank in services section
}

auto left = StringUtils::Trim(line.substr(0, equalsPos).c_str());
auto right = StringUtils::Trim(line.substr(equalsPos + 1).c_str());

// New service block: "s3 =" (right hand side empty)
if (!left.empty() && right.empty()) {
activeServiceId = StringUtils::ToUpper(left.c_str());
StringUtils::Replace(activeServiceId, " ", "_");
continue;
}

// Ignore global endpoint_url in [services name] section
if (activeServiceId.empty() && StringUtils::CaselessCompare(left.c_str(), ENDPOINT_URL_KEY) == 0) {
AWS_LOGSTREAM_DEBUG(PARSER_TAG, "Ignoring global endpoint_url in [services " << currentSectionName << "]");
continue;
}

// Property inside an active block: "endpoint_url = http://..."
if (!activeServiceId.empty() && left == ENDPOINT_URL_KEY) {
m_services[currentSectionName][activeServiceId] = right;
continue;
}
}

if(UNKNOWN_SECTION_FOUND == currentState)
{
// skip any unknown sections
Expand All @@ -171,6 +207,22 @@ namespace Aws

FlushSection(currentState, currentSectionName, currentKeyValues);

// Resolve service endpoints
for (auto& profilePair : m_foundProfiles)
{
Profile& profile = profilePair.second;
const Aws::String& servicesRef = profile.GetValue("services");
if (!servicesRef.empty())
{
auto servicesBlk = m_services.find(servicesRef);
Aws::Map<Aws::String, Aws::String> endpoints;
if (servicesBlk != m_services.end()) {
endpoints = servicesBlk->second;
}
profile.SetServices(Profile::Services(std::move(endpoints), servicesRef));
}
}

// Put sso-sessions into profiles
for(auto& profile : m_foundProfiles)
{
Expand Down Expand Up @@ -222,6 +274,7 @@ namespace Aws
START = 0,
PROFILE_FOUND,
SSO_SESSION_FOUND,
SERVICES_FOUND,
UNKNOWN_SECTION_FOUND,
FAILURE
};
Expand Down Expand Up @@ -271,8 +324,9 @@ namespace Aws

/**
* A helper function to parse config section declaration line
* @param line, an input line, e.g. "[profile default]"
* @param line, an input line, e.g. "[profile default]" or "[services s3]"
* @param ioSectionName, a return argument representing parsed section Identifier, e.g. "default"
* @param ioServiceId, a return argument representing parsed service ID for services sections
* @param ioState, a return argument representing parser state, e.g. PROFILE_FOUND
*/
void ParseSectionDeclaration(const Aws::String& line,
Expand Down Expand Up @@ -331,21 +385,21 @@ namespace Aws

if(defaultProfileOrSsoSectionRequired)
{
if (sectionIdentifier != DEFAULT && sectionIdentifier != SSO_SESSION_SECTION)
if (sectionIdentifier != DEFAULT && sectionIdentifier != SSO_SESSION_SECTION && sectionIdentifier != SERVICES_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)
if (sectionIdentifier != SSO_SESSION_SECTION && sectionIdentifier != SERVICES_SECTION)
{
// profile found, still pending check for closing bracket
ioState = PROFILE_FOUND;
ioSectionName = sectionIdentifier;
}
}

if(!m_useProfilePrefix || sectionIdentifier != SSO_SESSION_SECTION)
if(!m_useProfilePrefix || (sectionIdentifier != SSO_SESSION_SECTION && sectionIdentifier != SERVICES_SECTION))
{
// profile found, still pending check for closing bracket
ioState = PROFILE_FOUND;
Expand Down Expand Up @@ -374,6 +428,32 @@ namespace Aws
ioSectionName = sectionIdentifier;
}

if(sectionIdentifier == SERVICES_SECTION)
{
// Check if this is [services] or [services name]
pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos);
if(pos == Aws::String::npos || line[pos] == RIGHT_BRACKET)
{
// This is just [services] section
AWS_LOGSTREAM_ERROR(PARSER_TAG, "[services] section without name is not supported: " << line);
break;
}
else
{
// This is [services name] section
sectionIdentifier = ParseIdentifier(line, pos, errorMsg);
if (!errorMsg.empty())
{
AWS_LOGSTREAM_ERROR(PARSER_TAG, "Failed to parse services definition name: " << errorMsg << " " << line);
break;
}
pos += sectionIdentifier.length();
// services definition found, still pending check for closing bracket
ioState = SERVICES_FOUND;
ioSectionName = sectionIdentifier;
}
}

pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos);
if(pos == Aws::String::npos)
{
Expand All @@ -394,7 +474,7 @@ namespace Aws
break;
}
// the rest is a comment, and we don't care about it.
if ((ioState != SSO_SESSION_FOUND && ioState != PROFILE_FOUND) || ioSectionName.empty())
if ((ioState != SSO_SESSION_FOUND && ioState != PROFILE_FOUND && ioState != SERVICES_FOUND) || ioSectionName.empty())
{
AWS_LOGSTREAM_FATAL(PARSER_TAG, "Unexpected parser state after attempting to parse section " << line);
break;
Expand All @@ -412,6 +492,7 @@ namespace Aws
* (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 currentServiceId, a current service identifier for services sections
* @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)
Expand Down Expand Up @@ -529,6 +610,10 @@ namespace Aws
ssoSession.SetName(currentSectionName);
ssoSession.SetAllKeyValPairs(std::move(currentKeyValues));
}
else if (SERVICES_FOUND == currentState) {
// Handle [services name] section - service endpoints are parsed inline during stream processing
AWS_LOGSTREAM_DEBUG(PARSER_TAG, "Processed [services " << currentSectionName << "] section");
}
else
{
AWS_LOGSTREAM_FATAL(PARSER_TAG, "Unknown parser error: unexpected state " << currentState);
Expand Down Expand Up @@ -557,6 +642,7 @@ namespace Aws

Aws::Map<String, Profile> m_foundProfiles;
Aws::Map<String, Profile::SsoSession> m_foundSsoSessions;
Aws::Map<String, Aws::Map<String, String>> m_services;
};

static const char* const CONFIG_FILE_LOADER = "Aws::Config::AWSConfigFileProfileConfigLoader";
Expand Down
Loading
Loading