Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ namespace Aws
* Optionally a user can specify the profile and it will override the environment variable
* and defaults. To alter the file this pulls from, then the user should alter the AWS_SHARED_CREDENTIALS_FILE variable.
*/
// class AWS_DEPRECATED("This class is in the maintenance mode, no new updates will be released, use S3EncryptionClientV3. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information.") AWS_CORE_API ProfileConfigFileAWSCredentialsProvider : public AWSCredentialsProvider
class AWS_CORE_API ProfileConfigFileAWSCredentialsProvider : public AWSCredentialsProvider
{
public:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

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

namespace Aws {
namespace Auth {
/**
* CRT-based credentials provider that sources credentials from config files with full SEP compliance.
* Supports assume role, credential_source, role chaining, and all SEP scenarios.
*/
class AWS_CORE_API ProfileCredentialsProvider : public AWSCredentialsProvider {
public:
/**
* Initializes with refreshRateMs as the frequency at which the file is reparsed in milliseconds. Defaults to 5 minutes.
*/
ProfileCredentialsProvider(long refreshRateMs = REFRESH_THRESHOLD);

/**
* Initializes with a profile override and
* refreshRateMs as the frequency at which the file is reparsed in milliseconds. Defaults to 5 minutes.
*/
ProfileCredentialsProvider(const char* profile, long refreshRateMs = REFRESH_THRESHOLD);

/**
* Retrieves the credentials if found, otherwise returns empty credential set.
*/
AWSCredentials GetAWSCredentials() override;

/**
* Returns the fullpath of the calculated credentials profile file
*/
static Aws::String GetCredentialsProfileFilename();

/**
* Returns the directory storing the profile file.
*/
static Aws::String GetProfileDirectory();

protected:
void Reload() override;

private:
class ProfileCredentialsProviderImp;
std::shared_ptr<ProfileCredentialsProviderImp> m_impl;
};
} // namespace Auth
} // namespace Aws
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/auth/ProfileCredentialsProvider.h>

using namespace Aws::Auth;
using namespace Aws::Utils::Threading;
Expand Down Expand Up @@ -45,7 +46,7 @@ AWSCredentials AWSCredentialsProviderChain::GetAWSCredentials()
DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCredentialsProviderChain()
{
AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<ProfileConfigFileAWSCredentialsProvider>(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 @@ -90,7 +91,7 @@ DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCr
DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& config) : AWSCredentialsProviderChain()
{
AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<ProfileConfigFileAWSCredentialsProvider>(DefaultCredentialsProviderChainTag,config.profile.c_str()));
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));
Expand Down
109 changes: 109 additions & 0 deletions src/aws-cpp-sdk-core/source/auth/ProfileCredentialsProvider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include <aws/core/auth/AWSCredentialsProvider.h>

#include <aws/core/config/AWSProfileConfigLoader.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>

using namespace Aws::Auth;
using namespace Aws::Utils::Threading;

class ProfileCredentialsProvider::ProfileCredentialsProviderImp : public AWSCredentialsProvider {
public:
ProfileCredentialsProviderImp(long refreshRateMs)
: m_profileToUse(Aws::Auth::GetConfigProfileName()),
m_credentialsFileLoader(GetCredentialsProfileFilename()),
m_loadFrequencyMs(refreshRateMs) {
AWS_LOGSTREAM_INFO(PROFILE_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_LOG_TAG, "Setting provider to read credentials from "
<< GetCredentialsProfileFilename() << " for credentials file"
<< " and " << GetConfigProfileFilename() << " for the config file "
<< ", for use with profile " << m_profileToUse);
}

static Aws::String GetCredentialsProfileFilename() {
auto credentialsFileNameFromVar = Aws::Environment::GetEnv(AWS_CREDENTIALS_FILE);

if (credentialsFileNameFromVar.empty()) {
return Aws::FileSystem::GetHomeDirectory() + PROFILE_DIRECTORY + PATH_DELIM + DEFAULT_CREDENTIALS_FILE;
}
return credentialsFileNameFromVar;
}

static Aws::String GetProfileDirectory() {
Aws::String credentialsFileName = GetCredentialsProfileFilename();
auto lastSeparator = credentialsFileName.find_last_of(PATH_DELIM);
if (lastSeparator != std::string::npos) {
return credentialsFileName.substr(0, lastSeparator);
} else {
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(const char* profile, long refreshRateMs)
: m_impl(std::make_shared<ProfileCredentialsProviderImp>(profile, refreshRateMs)) {}

Aws::String ProfileCredentialsProvider::GetCredentialsProfileFilename() {
return ProfileCredentialsProviderImp::GetCredentialsProfileFilename();
}

Aws::String ProfileCredentialsProvider::GetProfileDirectory() { return ProfileCredentialsProviderImp::GetProfileDirectory(); }

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

void ProfileCredentialsProvider::Reload() { m_impl->Reload(); }
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ void SSOCredentialsProvider::Reload()
return token.GetToken();
}
Aws::String hashedStartUrl = Aws::Utils::HashingUtils::HexEncode(Aws::Utils::HashingUtils::CalculateSHA1(profile.GetSsoStartUrl()));
auto profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory();
auto profileDirectory = ProfileCredentialsProvider::GetProfileDirectory();
Aws::StringStream ssToken;
ssToken << profileDirectory;
ssToken << PATH_DELIM << "sso" << PATH_DELIM << "cache" << PATH_DELIM << hashedStartUrl << ".json";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ SSOBearerTokenProvider::CachedSsoToken SSOBearerTokenProvider::LoadAccessTokenFi
}

Aws::String hashedStartUrl = Aws::Utils::HashingUtils::HexEncode(Aws::Utils::HashingUtils::CalculateSHA1(profile.GetSsoSession().GetName()));
Aws::String profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory();
Aws::String profileDirectory = ProfileCredentialsProvider::GetProfileDirectory();
Aws::StringStream ssToken;
ssToken << profileDirectory;
ssToken << Aws::FileSystem::PATH_DELIM << "sso" << Aws::FileSystem::PATH_DELIM << "cache" << Aws::FileSystem::PATH_DELIM << hashedStartUrl << ".json";
Expand Down Expand Up @@ -195,7 +195,7 @@ bool SSOBearerTokenProvider::WriteAccessTokenFile(const CachedSsoToken& token) c
}

Aws::String hashedStartUrl = Aws::Utils::HashingUtils::HexEncode(Aws::Utils::HashingUtils::CalculateSHA1(profile.GetSsoSession().GetName()));
Aws::String profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory();
Aws::String profileDirectory = ProfileCredentialsProvider::GetProfileDirectory();
Aws::StringStream ssToken;
ssToken << profileDirectory;
ssToken << Aws::FileSystem::PATH_DELIM << "sso" << Aws::FileSystem::PATH_DELIM << "cache" << Aws::FileSystem::PATH_DELIM << hashedStartUrl << ".json";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <aws/core/config/ConfigAndCredentialsCacheManager.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/auth/ProfileCredentialsProvider.h>
#include <aws/core/utils/memory/stl/AWSList.h>
#include <aws/core/utils/json/JsonSerializer.h>
#include <fstream>
Expand All @@ -29,7 +30,7 @@ namespace Aws


ConfigAndCredentialsCacheManager::ConfigAndCredentialsCacheManager() :
m_credentialsFileLoader(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()),
m_credentialsFileLoader(Aws::Auth::ProfileCredentialsProvider::GetCredentialsProfileFilename()),
m_configFileLoader(Aws::Auth::GetConfigProfileFilename(), true/*use profile prefix*/)
{
ReloadCredentialsFile();
Expand All @@ -46,7 +47,7 @@ namespace Aws
void ConfigAndCredentialsCacheManager::ReloadCredentialsFile()
{
Aws::Utils::Threading::WriterLockGuard guard(m_credentialsLock);
m_credentialsFileLoader.SetFileName(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename());
m_credentialsFileLoader.SetFileName(Aws::Auth::ProfileCredentialsProvider::GetCredentialsProfileFilename());
m_credentialsFileLoader.Load();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <aws/testing/mocks/aws/auth/MockAWSHttpResourceClient.h>
#include <aws/testing/platform/PlatformTesting.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/auth/ProfileCredentialsProvider.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/core/auth/GeneralHTTPCredentialsProvider.h>
#include <aws/core/client/AWSClient.h>
Expand Down Expand Up @@ -178,7 +179,7 @@ TEST_F(CredentialTrackingTest, TestProfileCredentialsTracking)
}};
Aws::Config::ReloadCachedCredentialsFile();

auto credsProvider = Aws::MakeShared<Aws::Auth::ProfileConfigFileAWSCredentialsProvider>(TEST_LOG_TAG);
auto credsProvider = Aws::MakeShared<Aws::Auth::ProfileCredentialsProvider>(TEST_LOG_TAG);
RunTestWithCredentialsProvider(std::move(credsProvider), "n");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include <aws/core/auth/ProfileCredentialsProvider.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/platform/FileSystem.h>
#include <aws/core/utils/FileSystemUtils.h>
#include <aws/testing/AwsCppSdkGTestSuite.h>

#include <fstream>

using namespace Aws::Auth;

class ProfileCredentialsProviderTests : public Aws::Testing::AwsCppSdkGTestSuite {
protected:
void SetUp() override {
SaveEnv("AWS_CONFIG_FILE");
SaveEnv("AWS_SHARED_CREDENTIALS_FILE");
SaveEnv("AWS_PROFILE");

Aws::FileSystem::CreateDirectoryIfNotExists(GetTestDir().c_str());
m_configFile = GetTestDir() + "/config";
m_credsFile = GetTestDir() + "/credentials";

Aws::Environment::SetEnv("AWS_CONFIG_FILE", m_configFile.c_str(), 1);
Aws::Environment::SetEnv("AWS_SHARED_CREDENTIALS_FILE", m_credsFile.c_str(), 1);
}

void TearDown() override {
Aws::FileSystem::RemoveFileIfExists(m_configFile.c_str());
Aws::FileSystem::RemoveFileIfExists(m_credsFile.c_str());
RestoreEnv();
}

void SaveEnv(const char* name) { m_savedEnv.emplace_back(name, Aws::Environment::GetEnv(name)); }

void RestoreEnv() {
for (const auto& pair : m_savedEnv) {
if (pair.second.empty()) {
Aws::Environment::UnSetEnv(pair.first);
} else {
Aws::Environment::SetEnv(pair.first, pair.second.c_str(), 1);
}
}
}

Aws::String GetTestDir() {
return Aws::FileSystem::GetHomeDirectory() + "/.aws_test_" + Aws::Utils::StringUtils::to_string(std::this_thread::get_id());
}

Aws::String m_configFile;
Aws::String m_credsFile;
Aws::Vector<std::pair<const char*, Aws::String>> m_savedEnv;
};

TEST_F(ProfileCredentialsProviderTests, LoadStaticCredentials) {
std::ofstream creds(m_credsFile.c_str());
creds << "[default]\n";
creds << "aws_access_key_id = AKIATEST123\n";
creds << "aws_secret_access_key = SecretKey456\n";
creds.close();

ProfileCredentialsProvider provider;
auto credentials = provider.GetAWSCredentials();

EXPECT_STREQ("AKIATEST123", credentials.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("SecretKey456", credentials.GetAWSSecretKey().c_str());
}

TEST_F(ProfileCredentialsProviderTests, LoadNamedProfile) {
std::ofstream creds(m_credsFile.c_str());
creds << "[default]\n";
creds << "aws_access_key_id = DefaultKey\n";
creds << "aws_secret_access_key = DefaultSecret\n";
creds << "\n";
creds << "[test-profile]\n";
creds << "aws_access_key_id = TestKey\n";
creds << "aws_secret_access_key = TestSecret\n";
creds.close();

ProfileCredentialsProvider provider("test-profile");
auto credentials = provider.GetAWSCredentials();

EXPECT_STREQ("TestKey", credentials.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("TestSecret", credentials.GetAWSSecretKey().c_str());
}

TEST_F(ProfileCredentialsProviderTests, LoadWithSessionToken) {
std::ofstream creds(m_credsFile.c_str());
creds << "[default]\n";
creds << "aws_access_key_id = AKIATEST\n";
creds << "aws_secret_access_key = SecretKey\n";
creds << "aws_session_token = SessionToken123\n";
creds.close();

ProfileCredentialsProvider provider;
auto credentials = provider.GetAWSCredentials();

EXPECT_STREQ("AKIATEST", credentials.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("SecretKey", credentials.GetAWSSecretKey().c_str());
EXPECT_STREQ("SessionToken123", credentials.GetSessionToken().c_str());
}

TEST_F(ProfileCredentialsProviderTests, MissingProfileReturnsEmpty) {
std::ofstream creds(m_credsFile.c_str());
creds << "[default]\n";
creds << "aws_access_key_id = DefaultKey\n";
creds << "aws_secret_access_key = DefaultSecret\n";
creds.close();

ProfileCredentialsProvider provider("nonexistent");
auto credentials = provider.GetAWSCredentials();

EXPECT_TRUE(credentials.IsEmpty());
}

TEST_F(ProfileCredentialsProviderTests, DISABLED_ProcessCredentials) {
std::ofstream config(m_configFile.c_str());
config << "[default]\n";
config << "credential_process = echo '{\"Version\": 1, \"AccessKeyId\": \"ProcessKey\", \"SecretAccessKey\": \"ProcessSecret\"}'\n";
config.close();

ProfileCredentialsProvider provider;
auto credentials = provider.GetAWSCredentials();

EXPECT_STREQ("ProcessKey", credentials.GetAWSAccessKeyId().c_str());
EXPECT_STREQ("ProcessSecret", credentials.GetAWSSecretKey().c_str());
}
Loading
Loading