Skip to content

Commit

Permalink
Add support for AssumeRole in shared configuration
Browse files Browse the repository at this point in the history
Add support for STS AssumeRole which:
a) Works with the credential process as the credential source
b) Supports sourcing another profile (i.e. works like the aws cli)
  • Loading branch information
marcomagdy committed Aug 30, 2019
1 parent d77abf6 commit 3dce455
Show file tree
Hide file tree
Showing 10 changed files with 1,259 additions and 53 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.build
.idea
*.d
compile_commands.json
Debug
Release
*~
Expand Down Expand Up @@ -83,4 +84,4 @@ aws-cpp-sdk-core/include/aws/core/SDKConfig.h

#Aws common runtime libs
.aws-common-runtime-libs-build/
.aws-common-runtime-libs-install/
.aws-common-runtime-libs-install/
39 changes: 37 additions & 2 deletions aws-cpp-sdk-core-tests/aws/auth/AWSCredentialsProviderTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ TEST_F(ProcessCredentialsProviderTest, TestProcessCredentialsProviderExpiredThen

ProcessCredentialsProvider provider;
Aws::Auth::AWSCredentials credsOne = provider.GetAWSCredentials();
EXPECT_TRUE(credsOne.IsEmpty());
EXPECT_TRUE(credsOne.IsExpired());

Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc);
configFileNew << "[default]" << std::endl;
Expand Down Expand Up @@ -840,4 +840,39 @@ TEST_F(STSAssumeRoleWithWebIdentityCredentialsProviderTest, TestInitializeFromEn

Aws::FileSystem::RemoveFileIfExists(tokenFileName.c_str());
Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str());
}
}

TEST(AWSCredentialsTest, TestDefaultState)
{
AWSCredentials credentials;
ASSERT_TRUE(credentials.IsEmpty());
ASSERT_FALSE(credentials.IsExpired());
ASSERT_TRUE(credentials.IsExpiredOrEmpty());
}

TEST(AWSCredentialsTest, TestValidState)
{
AWSCredentials credentials;
credentials.SetAWSAccessKeyId("a");
credentials.SetAWSSecretKey("b");
ASSERT_FALSE(credentials.IsEmpty());
ASSERT_FALSE(credentials.IsExpired());
ASSERT_FALSE(credentials.IsExpiredOrEmpty());
}

TEST(AWSCredentialsTest, TestExpiredState)
{
AWSCredentials credentials;
credentials.SetExpiration(DateTime::Now() - std::chrono::minutes(1));

ASSERT_TRUE(credentials.IsEmpty());
ASSERT_TRUE(credentials.IsExpired());
ASSERT_TRUE(credentials.IsExpiredOrEmpty());

credentials.SetAWSAccessKeyId("a");
credentials.SetAWSSecretKey("b");

ASSERT_FALSE(credentials.IsEmpty());
ASSERT_TRUE(credentials.IsExpired());
ASSERT_TRUE(credentials.IsExpiredOrEmpty());
}
71 changes: 65 additions & 6 deletions aws-cpp-sdk-core/include/aws/core/auth/AWSCredentials.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <aws/core/Core_EXPORTS.h>
#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/core/utils/DateTime.h>
namespace Aws
{
namespace Auth
Expand All @@ -27,24 +28,65 @@ namespace Aws
class AWS_CORE_API AWSCredentials
{
public:
AWSCredentials() {}
/**
* Initializes an empty credentials set.
* Empty credentials are not expired by default.
* Credentials expire only if an expiration date is explicitly set on them.
*/
AWSCredentials() : m_expiration(std::chrono::time_point<std::chrono::system_clock>::max())
{
}

/**
* Initializes object with accessKeyId, secretKey, and sessionToken. Session token defaults to empty.
* Initializes object with accessKeyId, secretKey.
* SessionToken defaults to empty string.
* Expiration date is set to "never expire".
*/
AWSCredentials(const Aws::String& accessKeyId, const Aws::String& secretKey, const Aws::String& sessionToken = "") :
m_accessKeyId(accessKeyId), m_secretKey(secretKey), m_sessionToken(sessionToken)
AWSCredentials(const Aws::String& accessKeyId, const Aws::String& secretKey) :
m_accessKeyId(accessKeyId), m_secretKey(secretKey), m_expiration(std::chrono::time_point<std::chrono::system_clock>::max())
{
}

bool operator == (const AWSCredentials& other) const { return m_accessKeyId == other.m_accessKeyId && m_secretKey == other.m_secretKey && m_sessionToken == other.m_sessionToken; };
bool operator != (const AWSCredentials& other) const { return m_accessKeyId != other.m_accessKeyId || m_secretKey != other.m_secretKey || m_sessionToken != other.m_sessionToken; };
/**
* Initializes object with accessKeyId, secretKey, and sessionToken.
* Expiration date is set to "never expire".
*/
AWSCredentials(const Aws::String& accessKeyId, const Aws::String& secretKey, const Aws::String& sessionToken) :
m_accessKeyId(accessKeyId), m_secretKey(secretKey), m_sessionToken(sessionToken), m_expiration(std::chrono::time_point<std::chrono::system_clock>::max())
{
}

/**
* Initializes object with accessKeyId, secretKey, sessionToken and expiration date.
*/
AWSCredentials(const Aws::String& accessKeyId, const Aws::String& secretKey, const Aws::String& sessionToken, Aws::Utils::DateTime expiration) :
m_accessKeyId(accessKeyId), m_secretKey(secretKey), m_sessionToken(sessionToken), m_expiration(expiration)
{
}

bool operator == (const AWSCredentials& other) const
{
return m_accessKeyId == other.m_accessKeyId
&& m_secretKey == other.m_secretKey
&& m_sessionToken == other.m_sessionToken
&& m_expiration == other.m_expiration;
}

bool operator != (const AWSCredentials& other) const
{
return !(other == *this);
}

/**
* If credentials haven't been initialized or been initialized to emtpy values.
* Expiration date does not affect the result of this function.
*/
inline bool IsEmpty() const { return m_accessKeyId.empty() && m_secretKey.empty(); }

inline bool IsExpired() const { return m_expiration <= Aws::Utils::DateTime::Now(); }

inline bool IsExpiredOrEmpty() const { return IsEmpty() || IsExpired(); }

/**
* Gets the underlying access key credential
*/
Expand All @@ -69,6 +111,14 @@ namespace Aws
return m_sessionToken;
}

/**
* Gets the expiration date of the credential
*/
inline Aws::Utils::DateTime GetExpiration() const
{
return m_expiration;
}

/**
* Sets the underlying access key credential. Copies from parameter accessKeyId.
*/
Expand Down Expand Up @@ -117,10 +167,19 @@ namespace Aws
m_sessionToken = sessionToken;
}

/**
* Sets the expiration date of the credential
*/
inline void SetExpiration(Aws::Utils::DateTime expiration)
{
m_expiration = expiration;
}

private:
Aws::String m_accessKeyId;
Aws::String m_secretKey;
Aws::String m_sessionToken;
Aws::Utils::DateTime m_expiration;
};
}
}
30 changes: 21 additions & 9 deletions aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,27 @@ namespace Aws
{
namespace Auth
{
static int REFRESH_THRESHOLD = 1000 * 60 * 5;
constexpr int REFRESH_THRESHOLD = 1000 * 60 * 5;

/**
* Returns the full path of the config file.
*/
AWS_CORE_API Aws::String GetConfigProfileFilename(); //defaults to "config"

/**
* Returns the default profile name.
* The value is the first non-empty value of the following:
* 1. AWS_PROFILE environment variable
* 2. AWS_DEFAULT_PROFILE environment variable
* 3. The literal name "default"
*/
AWS_CORE_API Aws::String GetConfigProfileName(); //defaults to "default"

/*
* Fetches credentials by executing the process in the parameter
*/
AWS_CORE_API AWSCredentials GetCredentialsFromProcess(const Aws::String& process);

/**
* Abstract class for retrieving AWS credentials. Create a derived class from this to allow
* various methods of storing and retrieving credentials. Examples would be cognito-identity, some encrypted store etc...
Expand Down Expand Up @@ -96,29 +112,26 @@ namespace Aws
* Initializes object from awsAccessKeyId, awsSecretAccessKey, and sessionToken parameters. sessionToken parameter is defaulted to empty.
*/
inline SimpleAWSCredentialsProvider(const Aws::String& awsAccessKeyId, const Aws::String& awsSecretAccessKey, const Aws::String& sessionToken = "")
: m_accessKeyId(awsAccessKeyId), m_secretAccessKey(awsSecretAccessKey), m_sessionToken(sessionToken)
: m_credentials(awsAccessKeyId, awsSecretAccessKey, sessionToken)
{ }

/**
* Initializes object from credentials object. everything is copied.
*/
inline SimpleAWSCredentialsProvider(const AWSCredentials& credentials)
: m_accessKeyId(credentials.GetAWSAccessKeyId()), m_secretAccessKey(credentials.GetAWSSecretKey()),
m_sessionToken(credentials.GetSessionToken())
: m_credentials(credentials)
{ }

/**
* Returns the credentials this object was initialized with as an AWSCredentials object.
*/
inline AWSCredentials GetAWSCredentials() override
{
return AWSCredentials(m_accessKeyId, m_secretAccessKey, m_sessionToken);
return m_credentials;
}

private:
Aws::String m_accessKeyId;
Aws::String m_secretAccessKey;
Aws::String m_sessionToken;
AWSCredentials m_credentials;
};

/**
Expand Down Expand Up @@ -310,7 +323,6 @@ namespace Aws
Aws::String m_profileToUse;
Aws::Config::AWSConfigFileProfileConfigLoader m_configFileLoader;
Aws::Auth::AWSCredentials m_credentials;
Aws::Utils::DateTime m_expire;
};
} // namespace Auth
} // namespace Aws
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ namespace Aws
*/
inline const Aws::Utils::DateTime& LastLoadTime() const { return m_lastLoadTime; }

using ProfilesContainer = Aws::Map<Aws::String, Aws::Config::Profile>;

protected:
/**
* Subclasses override this method to implement fetching the profiles.
Expand All @@ -107,7 +109,7 @@ namespace Aws
*/
virtual bool PersistInternal(const Aws::Map<Aws::String, Aws::Config::Profile>&) { return false; }

Aws::Map<Aws::String, Aws::Config::Profile> m_profiles;
ProfilesContainer m_profiles;
Aws::Utils::DateTime m_lastLoadTime;
};

Expand Down
Loading

0 comments on commit 3dce455

Please sign in to comment.