Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c14eda9
Adding CRTProfileCredentialsProvider for CRT-based profile credential
pulimsr Feb 3, 2026
3dcacf1
Merge branch 'main' of https://github.com/aws/aws-sdk-cpp into crt-pr…
pulimsr Feb 3, 2026
288b730
Merge branch 'main' of https://github.com/aws/aws-sdk-cpp into crt-pr…
pulimsr Feb 4, 2026
3a600b2
implementing the currently existing profile provider to add CRT profi…
pulimsr Feb 4, 2026
0d459ee
merging from main
pulimsr Feb 5, 2026
5eb8769
Merge branch 'main' of https://github.com/aws/aws-sdk-cpp into crt-pr…
pulimsr Feb 5, 2026
444c9d8
changing names and moving functions to the pointer class
pulimsr Feb 6, 2026
2f38818
Merge branch 'main' into crt-profile-credentials-provider
pulimsr Feb 9, 2026
da5b2f0
Deprecate ProfileConfigFileAWSCredentialsProvider and migrate callers…
pulimsr Feb 9, 2026
65e5eb9
Merge branch 'main' into crt-profile-credentials-provider
pulimsr Feb 10, 2026
621afbf
using the new profile credential provider class
pulimsr Feb 10, 2026
00e8616
removing AWS_DEPRECATED for now
pulimsr Feb 10, 2026
69959c7
Merge branch 'main' into crt-profile-credentials-provider
pulimsr Feb 10, 2026
233c9c0
Merge branch 'main' into crt-profile-credentials-provider
pulimsr Feb 11, 2026
d2bca9f
adding missing headers
pulimsr Feb 11, 2026
ed61b12
Adding missing Aws::Client namespace for UserAgentFeature
pulimsr Feb 11, 2026
575f570
adding namespaces
pulimsr Feb 11, 2026
8a7967c
fixing missing constant declarations in ProfileCredentialsProvider
pulimsr Feb 11, 2026
29b61af
fixing missing constant declarations in ProfileCredentialsProvider
pulimsr Feb 11, 2026
dd2dc8e
adding namespace
pulimsr Feb 11, 2026
1b0c159
extern variables
pulimsr Feb 12, 2026
01057cd
Merge branch 'main' into crt-profile-credentials-provider
pulimsr Feb 12, 2026
bb2223e
symbol collision in ProfileCredentialsProvider
pulimsr Feb 12, 2026
7fcc13a
Merge branch 'main' of https://github.com/aws/aws-sdk-cpp into crt-pr…
pulimsr Feb 12, 2026
da860d4
implementing the CRT's profile provider and removing the process prov…
pulimsr Feb 12, 2026
6b650e4
Merge branch 'main' into crt-profile-credentials-provider
pulimsr Feb 12, 2026
56af23d
Adding ProfileCredentialsProvider refresh parameter and comprehensive…
pulimsr Feb 13, 2026
a85bead
Merge branch 'crt-profile-credentials-provider' of https://github.com…
pulimsr Feb 13, 2026
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#pragma once

#include <aws/core/Core_EXPORTS.h>
#include <aws/core/utils/memory/stl/AWSString.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: no actual change in file so lets from it from the PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

alright

#include <aws/core/auth/AWSCredentials.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/utils/memory/stl/AWSString.h>

#include <memory>

namespace Aws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCr
{
AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<ProfileCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<ProcessCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<STSAssumeRoleWebIdentityCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<SSOCredentialsProvider>(DefaultCredentialsProviderChainTag));

Expand Down Expand Up @@ -92,7 +91,6 @@ DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain(const Aws
{
AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<ProfileCredentialsProvider>(DefaultCredentialsProviderChainTag,config.profile.c_str()));
AddProvider(Aws::MakeShared<ProcessCredentialsProvider>(DefaultCredentialsProviderChainTag,config.profile));
AddProvider(Aws::MakeShared<STSAssumeRoleWebIdentityCredentialsProvider>(DefaultCredentialsProviderChainTag, config));
AddProvider(Aws::MakeShared<SSOCredentialsProvider>(DefaultCredentialsProviderChainTag,config.profile));
AddProvider(Aws::MakeShared<LoginCredentialsProvider>(DefaultCredentialsProviderChainTag, config));
Expand Down
107 changes: 33 additions & 74 deletions src/aws-cpp-sdk-core/source/auth/ProfileCredentialsProvider.cpp
Original file line number Diff line number Diff line change
@@ -1,43 +1,41 @@
#include <aws/core/auth/AWSCredentialsProvider.h>

#include <aws/core/config/AWSProfileConfigLoader.h>
#include <aws/core/auth/CrtCredentialsProvider.h>
#include <aws/core/auth/ProfileCredentialsProvider.h>
#include <aws/core/client/UserAgent.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/platform/FileSystem.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/client/UserAgent.h>
#include <aws/core/auth/ProfileCredentialsProvider.h>
#include <aws/crt/auth/Credentials.h>

using namespace Aws::Auth;
using namespace Aws::Client;
using namespace Aws::FileSystem;
using namespace Aws::Utils::Threading;
using namespace Aws::Crt::Auth;

namespace {
const char PROFILE_PROVIDER_LOG_TAG[] = "ProfileCredentialsProvider";
const char PROFILE_AWS_CREDENTIALS_FILE[] = "AWS_SHARED_CREDENTIALS_FILE";
const char PROFILE_DEFAULT_CREDENTIALS_FILE[] = "credentials";
const char PROFILE_PROFILE_DIRECTORY[] = ".aws";
}
const long DEFAULT_REFRESH_RATE_MS = 50000;
} // namespace

class ProfileCredentialsProvider::ProfileCredentialsProviderImp : public AWSCredentialsProvider {
class ProfileCredentialsProvider::ProfileCredentialsProviderImp : public CrtCredentialsProvider {
Copy link
Contributor

Choose a reason for hiding this comment

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

public CrtCredentialsProvider

chefs kiss

public:
ProfileCredentialsProviderImp(long refreshRateMs)
: m_profileToUse(Aws::Auth::GetConfigProfileName()),
m_credentialsFileLoader(GetCredentialsProfileFilename()),
m_loadFrequencyMs(refreshRateMs) {
AWS_LOGSTREAM_INFO(PROFILE_PROVIDER_LOG_TAG, "Setting provider to read credentials from "
<< GetCredentialsProfileFilename() << " for credentials file"
<< " and " << GetConfigProfileFilename() << " for the config file "
<< ", for use with profile " << m_profileToUse);
}

ProfileCredentialsProviderImp(const char* profile, long refreshRateMs)
: m_profileToUse(profile), m_credentialsFileLoader(GetCredentialsProfileFilename()), m_loadFrequencyMs(refreshRateMs) {
AWS_LOGSTREAM_INFO(PROFILE_PROVIDER_LOG_TAG, "Setting provider to read credentials from "
<< GetCredentialsProfileFilename() << " for credentials file"
<< " and " << GetConfigProfileFilename() << " for the config file "
<< ", for use with profile " << m_profileToUse);
}
ProfileCredentialsProviderImp()
: CrtCredentialsProvider(
[]() -> std::shared_ptr<ICredentialsProvider> {
CredentialsProviderProfileConfig config;
return CredentialsProvider::CreateCredentialsProviderProfile(config);
},
std::chrono::milliseconds(DEFAULT_REFRESH_RATE_MS), UserAgentFeature::CREDENTIALS_PROFILE, "ProfileCredentialsProvider") {}

ProfileCredentialsProviderImp(const char* profile)
: CrtCredentialsProvider(
[profile]() -> std::shared_ptr<ICredentialsProvider> {
CredentialsProviderProfileConfig config;
config.ProfileNameOverride = Aws::Crt::ByteCursorFromCString(profile);
return CredentialsProvider::CreateCredentialsProviderProfile(config);
},
std::chrono::milliseconds(DEFAULT_REFRESH_RATE_MS), Aws::Client::UserAgentFeature::CREDENTIALS_PROFILE,
"ProfileCredentialsProvider") {}

static Aws::String GetCredentialsProfileFilename() {
auto credentialsFileNameFromVar = Aws::Environment::GetEnv(PROFILE_AWS_CREDENTIALS_FILE);
Expand All @@ -57,55 +55,18 @@ class ProfileCredentialsProvider::ProfileCredentialsProviderImp : public AWSCred
return {};
}
}

AWSCredentials GetAWSCredentials() override {
RefreshIfExpired();
ReaderLockGuard guard(m_reloadLock);
const Aws::Map<Aws::String, Aws::Config::Profile>& profiles = m_credentialsFileLoader.GetProfiles();
auto credsFileProfileIter = profiles.find(m_profileToUse);

if (credsFileProfileIter != profiles.end()) {
AWSCredentials credentials = credsFileProfileIter->second.GetCredentials();
if (!credentials.IsEmpty()) {
credentials.AddUserAgentFeature(UserAgentFeature::CREDENTIALS_PROFILE);
}
return credentials;
}

return AWSCredentials();
}

void Reload() override {
m_credentialsFileLoader.Load();
AWSCredentialsProvider::Reload();
}

private:
Aws::String m_profileToUse;
Aws::Config::AWSConfigFileProfileConfigLoader m_credentialsFileLoader;
long m_loadFrequencyMs;

void RefreshIfExpired() {
ReaderLockGuard guard(m_reloadLock);
if (!IsTimeToRefresh(m_loadFrequencyMs)) {
return;
}

guard.UpgradeToWriterLock();
if (!IsTimeToRefresh(m_loadFrequencyMs)) // double-checked lock to avoid refreshing twice
{
return;
}

Reload();
}
};

ProfileCredentialsProvider::ProfileCredentialsProvider(long refreshRateMs)
: m_impl(std::make_shared<ProfileCredentialsProviderImp>(refreshRateMs)) {}
ProfileCredentialsProvider::ProfileCredentialsProvider(long refreshRateMs) : m_impl(std::make_shared<ProfileCredentialsProviderImp>()) {
(void)refreshRateMs;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit use the macro AWS_UNREFERENCED_PARAM instead of void cast because its more accurate

}

ProfileCredentialsProvider::ProfileCredentialsProvider(const char* profile, long refreshRateMs)
: m_impl(std::make_shared<ProfileCredentialsProviderImp>(profile, refreshRateMs)) {}
: m_impl(std::make_shared<ProfileCredentialsProviderImp>(profile)) {
(void)refreshRateMs;
}

void ProfileCredentialsProvider::Reload() {}

Aws::String ProfileCredentialsProvider::GetCredentialsProfileFilename() {
return ProfileCredentialsProviderImp::GetCredentialsProfileFilename();
Expand All @@ -114,5 +75,3 @@ Aws::String ProfileCredentialsProvider::GetCredentialsProfileFilename() {
Aws::String ProfileCredentialsProvider::GetProfileDirectory() { return ProfileCredentialsProviderImp::GetProfileDirectory(); }

AWSCredentials ProfileCredentialsProvider::GetAWSCredentials() { return m_impl->GetAWSCredentials(); }

void ProfileCredentialsProvider::Reload() { m_impl->Reload(); }
4 changes: 2 additions & 2 deletions tests/aws-cpp-sdk-core-integration-tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ endif()
enable_testing()

if(PLATFORM_ANDROID AND BUILD_SHARED_LIBS)
add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/STSWebIdentityProviderIntegrationTest.cpp)
add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/STSWebIdentityProviderIntegrationTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DefaultCredentialsProviderChainIntegrationTest.cpp)
else()
add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/STSWebIdentityProviderIntegrationTest.cpp)
add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/STSWebIdentityProviderIntegrationTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DefaultCredentialsProviderChainIntegrationTest.cpp)
endif()

set_compiler_flags(${PROJECT_NAME})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

#include <aws/core/Aws.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/utils/FileSystemUtils.h>
#include <aws/testing/AwsTestHelpers.h>
#include <aws/testing/platform/PlatformTesting.h>
#include <gtest/gtest.h>

using namespace Aws;
using namespace Aws::Auth;
using namespace Aws::Environment;
using namespace Aws::Utils;

/**
* Integration tests for DefaultAWSCredentialsProviderChain
* These tests use real credentials from the environment (e.g., via ada)
*/
class DefaultCredentialsProviderChainIntegrationTest : public testing::Test
{
protected:
DefaultCredentialsProviderChainIntegrationTest()
{
m_options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug;
Copy link
Contributor

Choose a reason for hiding this comment

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

we really aught to make this a official construct, i write this code at least times a week. not here for this PR, but something we should about. might help people use the SDK correctly better

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🫡

InitAPI(m_options);
}

~DefaultCredentialsProviderChainIntegrationTest()
{
ShutdownAPI(m_options);
}

SDKOptions m_options;
};

TEST_F(DefaultCredentialsProviderChainIntegrationTest, ChainResolvesCredentialsFromEnvironment)
{
// This test assumes AWS credentials are set via environment (e.g., ada)
DefaultAWSCredentialsProviderChain chain;
auto creds = chain.GetAWSCredentials();

// Should get valid credentials from environment
EXPECT_FALSE(creds.IsEmpty());
EXPECT_FALSE(creds.GetAWSAccessKeyId().empty());
EXPECT_FALSE(creds.GetAWSSecretKey().empty());
}

TEST_F(DefaultCredentialsProviderChainIntegrationTest, ChainCachesCredentials)
{
DefaultAWSCredentialsProviderChain chain;

// First call
auto creds1 = chain.GetAWSCredentials();
EXPECT_FALSE(creds1.IsEmpty());

// Second call should return same cached credentials
auto creds2 = chain.GetAWSCredentials();
EXPECT_FALSE(creds2.IsEmpty());
EXPECT_EQ(creds1.GetAWSAccessKeyId(), creds2.GetAWSAccessKeyId());
EXPECT_EQ(creds1.GetAWSSecretKey(), creds2.GetAWSSecretKey());
}

TEST_F(DefaultCredentialsProviderChainIntegrationTest, ChainWithCustomProfile)
{
// Create temporary credentials file with custom profile
TempFile credsFile{std::ios_base::out | std::ios_base::trunc};
credsFile << "[custom-test-profile]\n";
credsFile << "aws_access_key_id = AKIAIOSFODNN7EXAMPLE\n";
credsFile << "aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n";
credsFile.close();

// Create temporary config file
TempFile configFile{std::ios_base::out | std::ios_base::trunc};
configFile << "[profile custom-test-profile]\n";
configFile << "region = us-west-2\n";
configFile.close();

const EnvironmentRAII environmentRAII{{
{"AWS_SHARED_CREDENTIALS_FILE", credsFile.GetFileName()},
{"AWS_CONFIG_FILE", configFile.GetFileName()},
{"AWS_ACCESS_KEY_ID", ""},
{"AWS_SECRET_ACCESS_KEY", ""},
}};

Aws::Config::ReloadCachedConfigFile();

Client::ClientConfiguration::CredentialProviderConfiguration config;
config.profile = "custom-test-profile";
DefaultAWSCredentialsProviderChain chain(config);

auto creds = chain.GetAWSCredentials();

EXPECT_STREQ("AKIAIOSFODNN7EXAMPLE", creds.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", creds.GetAWSSecretKey().c_str());
}

TEST_F(DefaultCredentialsProviderChainIntegrationTest, ChainWithProcessCredentials)
{
// Create temporary config file with credential_process
TempFile configFile{std::ios_base::out | std::ios_base::trunc};
configFile << "[default]\n";
configFile << "credential_process = echo '{\"Version\": 1, \"AccessKeyId\": \"AKIAPROCESSEXAMPLE\", \"SecretAccessKey\": \"ProcessSecretKeyExample\"}'\n";
configFile.close();

// Create empty credentials file to override ~/.aws/credentials
TempFile credsFile{std::ios_base::out | std::ios_base::trunc};
credsFile << "[default]\n";
credsFile.close();

const EnvironmentRAII environmentRAII{{
{"AWS_CONFIG_FILE", configFile.GetFileName()},
{"AWS_SHARED_CREDENTIALS_FILE", credsFile.GetFileName()},
{"AWS_ACCESS_KEY_ID", ""},
{"AWS_SECRET_ACCESS_KEY", ""},
{"AWS_SESSION_TOKEN", ""},
{"AWS_EC2_METADATA_DISABLED", "true"},
}};

Aws::Config::ReloadCachedConfigFile();

DefaultAWSCredentialsProviderChain chain;
auto creds = chain.GetAWSCredentials();

EXPECT_STREQ("AKIAPROCESSEXAMPLE", creds.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("ProcessSecretKeyExample", creds.GetAWSSecretKey().c_str());
}

TEST_F(DefaultCredentialsProviderChainIntegrationTest, ChainPrecedenceEnvironmentOverProfile)
{
// Create temporary credentials file
TempFile credsFile{std::ios_base::out | std::ios_base::trunc};
credsFile << "[default]\n";
credsFile << "aws_access_key_id = AKIAPROFILEEXAMPLE\n";
credsFile << "aws_secret_access_key = ProfileSecretKeyExample\n";
credsFile.close();

const EnvironmentRAII environmentRAII{{
{"AWS_SHARED_CREDENTIALS_FILE", credsFile.GetFileName()},
{"AWS_ACCESS_KEY_ID", "AKIAENVEXAMPLE"},
{"AWS_SECRET_ACCESS_KEY", "EnvSecretKeyExample"},
}};

Aws::Config::ReloadCachedConfigFile();

DefaultAWSCredentialsProviderChain chain;
auto creds = chain.GetAWSCredentials();

// Environment should take precedence
EXPECT_STREQ("AKIAENVEXAMPLE", creds.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("EnvSecretKeyExample", creds.GetAWSSecretKey().c_str());
}

TEST_F(DefaultCredentialsProviderChainIntegrationTest, ChainHandlesSessionToken)
{
// Create temporary credentials file with session token
TempFile credsFile{std::ios_base::out | std::ios_base::trunc};
credsFile << "[default]\n";
credsFile << "aws_access_key_id = ASIATEMPORARYEXAMPLE\n";
credsFile << "aws_secret_access_key = TempSecretKeyExample\n";
credsFile << "aws_session_token = TempSessionTokenExample123\n";
credsFile.close();

const EnvironmentRAII environmentRAII{{
{"AWS_SHARED_CREDENTIALS_FILE", credsFile.GetFileName()},
{"AWS_ACCESS_KEY_ID", ""},
{"AWS_SECRET_ACCESS_KEY", ""},
{"AWS_EC2_METADATA_DISABLED", "true"},
}};

Aws::Config::ReloadCachedConfigFile();

DefaultAWSCredentialsProviderChain chain;
auto creds = chain.GetAWSCredentials();

EXPECT_STREQ("ASIATEMPORARYEXAMPLE", creds.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("TempSecretKeyExample", creds.GetAWSSecretKey().c_str());
EXPECT_STREQ("TempSessionTokenExample123", creds.GetSessionToken().c_str());
}

TEST_F(DefaultCredentialsProviderChainIntegrationTest, ChainReturnsEmptyWhenNoCredentialsAvailable)
{
const EnvironmentRAII environmentRAII{{
{"AWS_ACCESS_KEY_ID", ""},
{"AWS_SECRET_ACCESS_KEY", ""},
{"AWS_SHARED_CREDENTIALS_FILE", "/nonexistent/credentials"},
{"AWS_CONFIG_FILE", "/nonexistent/config"},
{"AWS_EC2_METADATA_DISABLED", "true"},
}};

Aws::Config::ReloadCachedConfigFile();

DefaultAWSCredentialsProviderChain chain;
auto creds = chain.GetAWSCredentials();

EXPECT_TRUE(creds.IsEmpty());
}
Loading
Loading