@@ -73,6 +73,18 @@ static T LoadEnumFromString(const std::array<std::pair<const char*, T>, N>& mapp
7373 return mapping->second ;
7474}
7575
76+ // Helper to load raw values without lowercasing (for file paths, ARNs, etc.)
77+ static Aws::String LoadRawFromEnvOrProfile (const Aws::String& envKey,
78+ const Aws::String& profile,
79+ const Aws::String& profileProperty,
80+ const Aws::String& defaultValue) {
81+ Aws::String option = Aws::Environment::GetEnv (envKey.c_str ());
82+ if (option.empty ()) {
83+ option = Aws::Config::GetCachedConfigValue (profile, profileProperty);
84+ }
85+ return option.empty () ? defaultValue : Aws::Utils::StringUtils::Trim (option.c_str ());
86+ }
87+
7688ClientConfiguration::ProviderFactories ClientConfiguration::ProviderFactories::defaultFactories = []()
7789{
7890 ProviderFactories factories;
@@ -327,23 +339,25 @@ void setConfigFromEnvOrProfile(ClientConfiguration &config)
327339 // Uses default retry mode with the specified max attempts from metadata_service_num_attempts
328340 config.credentialProviderConfig .imdsConfig .imdsRetryStrategy = InitRetryStrategy (attempts, " " );
329341
330- config.credentialProviderConfig .stsCredentialsProviderConfig .roleArn = ClientConfiguration::LoadConfigFromEnvOrProfile (AWS_IAM_ROLE_ARN_ENV_VAR,
331- config.profileName ,
332- AWS_IAM_ROLE_ARN_CONFIG_FILE_OPTION,
333- {}, /* allowed values */
334- " " /* default value */ );
335-
336- config.credentialProviderConfig .stsCredentialsProviderConfig .sessionName = ClientConfiguration::LoadConfigFromEnvOrProfile (AWS_IAM_ROLE_SESSION_NAME_ENV_VAR,
337- config.profileName ,
338- AWS_IAM_ROLE_SESSION_NAME_CONFIG_FILE_OPTION,
339- {}, /* allowed values */
340- " " /* default value */ );
341-
342- config.credentialProviderConfig .stsCredentialsProviderConfig .tokenFilePath = ClientConfiguration::LoadConfigFromEnvOrProfile (AWS_WEB_IDENTITY_TOKEN_FILE_ENV_VAR,
343- config.profileName ,
344- AWS_WEB_IDENTITY_TOKEN_FILE_CONFIG_FILE_OPTION,
345- {}, /* allowed values */
346- " " /* default value */ );
342+ auto roleArnSrc = ClientConfiguration::LoadConfigFromEnvOrProfileWithSource (
343+ AWS_IAM_ROLE_ARN_ENV_VAR, config.profileName , AWS_IAM_ROLE_ARN_CONFIG_FILE_OPTION, {}, " " );
344+ config.credentialProviderConfig .stsCredentialsProviderConfig .roleArn = roleArnSrc.value ;
345+
346+ config.credentialProviderConfig .stsCredentialsProviderConfig .sessionName = LoadRawFromEnvOrProfile (
347+ AWS_IAM_ROLE_SESSION_NAME_ENV_VAR, config.profileName , AWS_IAM_ROLE_SESSION_NAME_CONFIG_FILE_OPTION, " " );
348+
349+ auto tokenFileSrc = ClientConfiguration::LoadConfigFromEnvOrProfileWithSource (
350+ AWS_WEB_IDENTITY_TOKEN_FILE_ENV_VAR, config.profileName , AWS_WEB_IDENTITY_TOKEN_FILE_CONFIG_FILE_OPTION, {}, " " );
351+ config.credentialProviderConfig .stsCredentialsProviderConfig .tokenFilePath = tokenFileSrc.value ;
352+
353+ if (!roleArnSrc.value .empty () && !tokenFileSrc.value .empty ()) {
354+ using Src = ClientConfiguration::ConfigSourceType;
355+ const bool fromEnv = (roleArnSrc.source == Src::ENVIRONMENT) || (tokenFileSrc.source == Src::ENVIRONMENT);
356+ config.credentialProviderConfig .stsCredentialsProviderConfig .credentialSource =
357+ fromEnv ? " env_web_identity" : " web_identity" ;
358+ } else {
359+ config.credentialProviderConfig .stsCredentialsProviderConfig .credentialSource .clear ();
360+ }
347361}
348362
349363ClientConfiguration::ClientConfiguration ()
@@ -552,35 +566,79 @@ std::shared_ptr<RetryStrategy> InitRetryStrategy(Aws::String retryMode)
552566 return InitRetryStrategy (maxAttempts, retryMode);
553567}
554568
555- Aws::String ClientConfiguration::LoadConfigFromEnvOrProfile (const Aws::String& envKey,
556- const Aws::String& profile,
557- const Aws::String& profileProperty,
558- const Aws::Vector<Aws::String>& allowedValues,
559- const Aws::String& defaultValue)
569+ ClientConfiguration::ConfigSource ClientConfiguration::LoadConfigFromEnvOrProfileWithSource (const Aws::String& envKey,
570+ const Aws::String& profile,
571+ const Aws::String& profileProperty,
572+ const Aws::Vector<Aws::String>& allowedValues,
573+ const Aws::String& defaultValue)
560574{
561- Aws::String option = Aws::Environment::GetEnv (envKey.c_str ());
562- if (option.empty ()) {
575+ Aws::String option;
576+ ConfigSourceType sourceType = ConfigSourceType::DEFAULT_VALUE;
577+
578+ if (!envKey.empty ()) {
579+ option = Aws::Environment::GetEnv (envKey.c_str ());
580+ if (!option.empty ()) {
581+ sourceType = ConfigSourceType::ENVIRONMENT;
582+ }
583+ }
584+
585+ if (option.empty () && !profileProperty.empty ()) {
563586 option = Aws::Config::GetCachedConfigValue (profile, profileProperty);
587+ if (!option.empty ()) {
588+ sourceType = ConfigSourceType::PROFILE;
589+ }
564590 }
565- option = Aws::Utils::StringUtils::ToLower (option.c_str ());
591+
592+ option = Aws::Utils::StringUtils::Trim (option.c_str ());
593+
566594 if (option.empty ()) {
567- return defaultValue;
595+ return ConfigSource ( defaultValue, ConfigSourceType::DEFAULT_VALUE) ;
568596 }
569597
570- if (!allowedValues.empty () && std::find (allowedValues.cbegin (), allowedValues.cend (), option) == allowedValues.cend ()) {
571- Aws::OStringStream expectedStr;
572- expectedStr << " [" ;
573- for (const auto & allowed : allowedValues) {
574- expectedStr << allowed << " ;" ;
598+ // Validate only if we have an allowed list (enum-like). Do NOT mutate case of the returned value.
599+ if (!allowedValues.empty ()) {
600+ const Aws::String optionLower = Aws::Utils::StringUtils::ToLower (option.c_str ());
601+
602+ // Build a lowercased view of the allowed set once
603+ bool allowed = std::any_of (allowedValues.cbegin (), allowedValues.cend (),
604+ [&](const Aws::String& v){ return optionLower == Aws::Utils::StringUtils::ToLower (v.c_str ()); });
605+
606+ if (!allowed) {
607+ Aws::OStringStream expectedStr;
608+ expectedStr << " [" ;
609+ for (size_t i = 0 ; i < allowedValues.size (); ++i) {
610+ expectedStr << allowedValues[i];
611+ if ( i + 1 < allowedValues.size () ) expectedStr << " ;" ;
612+ }
613+ expectedStr << " ]" ;
614+
615+ const char * src = (sourceType == ConfigSourceType::ENVIRONMENT) ? " environment" :
616+ (sourceType == ConfigSourceType::PROFILE) ? " profile" : " default" ;
617+
618+ AWS_LOGSTREAM_WARN (
619+ CLIENT_CONFIG_TAG,
620+ " Unrecognized value from " << src
621+ << (sourceType == ConfigSourceType::ENVIRONMENT ? (Aws::String (" (" ) + envKey + " )" ) :
622+ sourceType == ConfigSourceType::PROFILE ? (Aws::String (" (" ) + profile + " :" + profileProperty + " )" ) : " " )
623+ << " : \" " << option << " \" . Using default: \" " << defaultValue
624+ << " \" . Expected one of: " << expectedStr.str ()
625+ );
626+
627+ return ConfigSource (defaultValue, ConfigSourceType::DEFAULT_VALUE);
575628 }
576- expectedStr << " ]" ;
577-
578- AWS_LOGSTREAM_WARN (CLIENT_CONFIG_TAG, " Unrecognised value for " << envKey << " : " << option <<
579- " . Using default instead: " << defaultValue <<
580- " . Expected empty or one of: " << expectedStr.str ());
581- option = defaultValue;
582629 }
583- return option;
630+
631+ // Return original (un-lowercased) token and the actual source
632+ return ConfigSource (option, sourceType);
633+ }
634+
635+ Aws::String ClientConfiguration::LoadConfigFromEnvOrProfile (const Aws::String& envKey,
636+ const Aws::String& profile,
637+ const Aws::String& profileProperty,
638+ const Aws::Vector<Aws::String>& allowedValues,
639+ const Aws::String& defaultValue)
640+ {
641+ return LoadConfigFromEnvOrProfileWithSource (envKey, profile, profileProperty, allowedValues, defaultValue).value ;
584642}
585643
586644} // namespace Client
0 commit comments