#include "extensions/common/aws/credentials_provider_impl.h" #include "test/extensions/common/aws/mocks.h" #include "test/mocks/api/mocks.h" #include "test/mocks/event/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/simulated_time_system.h" using testing::_; using testing::InSequence; using testing::NiceMock; using testing::Ref; using testing::Return; namespace Envoy { namespace Extensions { namespace Common { namespace Aws { class EvironmentCredentialsProviderTest : public testing::Test { public: ~EvironmentCredentialsProviderTest() override { TestEnvironment::unsetEnvVar("AWS_ACCESS_KEY_ID"); TestEnvironment::unsetEnvVar("AWS_SECRET_ACCESS_KEY"); TestEnvironment::unsetEnvVar("AWS_SESSION_TOKEN"); } EnvironmentCredentialsProvider provider_; }; TEST_F(EvironmentCredentialsProviderTest, AllEnvironmentVars) { TestEnvironment::setEnvVar("AWS_ACCESS_KEY_ID", "akid", 1); TestEnvironment::setEnvVar("AWS_SECRET_ACCESS_KEY", "secret", 1); TestEnvironment::setEnvVar("AWS_SESSION_TOKEN", "token", 1); const auto credentials = provider_.getCredentials(); EXPECT_EQ("akid", credentials.accessKeyId().value()); EXPECT_EQ("secret", credentials.secretAccessKey().value()); EXPECT_EQ("token", credentials.sessionToken().value()); } TEST_F(EvironmentCredentialsProviderTest, NoEnvironmentVars) { const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(EvironmentCredentialsProviderTest, MissingAccessKeyId) { TestEnvironment::setEnvVar("AWS_SECRET_ACCESS_KEY", "secret", 1); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(EvironmentCredentialsProviderTest, NoSessionToken) { TestEnvironment::setEnvVar("AWS_ACCESS_KEY_ID", "akid", 1); TestEnvironment::setEnvVar("AWS_SECRET_ACCESS_KEY", "secret", 1); const auto credentials = provider_.getCredentials(); EXPECT_EQ("akid", credentials.accessKeyId().value()); EXPECT_EQ("secret", credentials.secretAccessKey().value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } class InstanceProfileCredentialsProviderTest : public testing::Test { public: InstanceProfileCredentialsProviderTest() : api_(Api::createApiForTest(time_system_)), provider_(*api_, [this](const std::string& host, const std::string& path, const std::string& auth_token) -> absl::optional { return this->fetcher_.fetch(host, path, auth_token); }) {} void expectCredentialListing(const absl::optional& listing) { EXPECT_CALL(fetcher_, fetch("169.254.169.254:80", "/latest/meta-data/iam/security-credentials", _)) .WillOnce(Return(listing)); } void expectDocument(const absl::optional& document) { EXPECT_CALL(fetcher_, fetch("169.254.169.254:80", "/latest/meta-data/iam/security-credentials/doc1", _)) .WillOnce(Return(document)); } Event::SimulatedTimeSystem time_system_; Api::ApiPtr api_; NiceMock fetcher_; InstanceProfileCredentialsProvider provider_; }; TEST_F(InstanceProfileCredentialsProviderTest, FailedCredentailListing) { expectCredentialListing(absl::optional()); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(InstanceProfileCredentialsProviderTest, EmptyCredentialListing) { expectCredentialListing(""); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(InstanceProfileCredentialsProviderTest, MissingDocument) { expectCredentialListing("doc1\ndoc2\ndoc3"); expectDocument(absl::optional()); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(InstanceProfileCredentialsProviderTest, MalformedDocumenet) { expectCredentialListing("doc1"); expectDocument(R"EOF( not json )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(InstanceProfileCredentialsProviderTest, EmptyValues) { expectCredentialListing("doc1"); expectDocument(R"EOF( { "AccessKeyId": "", "SecretAccessKey": "", "Token": "" } )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(InstanceProfileCredentialsProviderTest, FullCachedCredentials) { expectCredentialListing("doc1"); expectDocument(R"EOF( { "AccessKeyId": "akid", "SecretAccessKey": "secret", "Token": "token" } )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_EQ("akid", credentials.accessKeyId().value()); EXPECT_EQ("secret", credentials.secretAccessKey().value()); EXPECT_EQ("token", credentials.sessionToken().value()); const auto cached_credentials = provider_.getCredentials(); EXPECT_EQ("akid", cached_credentials.accessKeyId().value()); EXPECT_EQ("secret", cached_credentials.secretAccessKey().value()); EXPECT_EQ("token", cached_credentials.sessionToken().value()); } TEST_F(InstanceProfileCredentialsProviderTest, CredentialExpiration) { InSequence sequence; expectCredentialListing("doc1"); expectDocument(R"EOF( { "AccessKeyId": "akid", "SecretAccessKey": "secret", "Token": "token" } )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_EQ("akid", credentials.accessKeyId().value()); EXPECT_EQ("secret", credentials.secretAccessKey().value()); EXPECT_EQ("token", credentials.sessionToken().value()); time_system_.advanceTimeWait(std::chrono::hours(2)); expectCredentialListing("doc1"); expectDocument(R"EOF( { "AccessKeyId": "new_akid", "SecretAccessKey": "new_secret", "Token": "new_token" } )EOF"); const auto new_credentials = provider_.getCredentials(); EXPECT_EQ("new_akid", new_credentials.accessKeyId().value()); EXPECT_EQ("new_secret", new_credentials.secretAccessKey().value()); EXPECT_EQ("new_token", new_credentials.sessionToken().value()); } class TaskRoleCredentialsProviderTest : public testing::Test { public: TaskRoleCredentialsProviderTest() : api_(Api::createApiForTest(time_system_)), provider_( *api_, [this](const std::string& host, const std::string& path, const absl::optional& auth_token) -> absl::optional { return this->fetcher_.fetch(host, path, auth_token); }, "169.254.170.2:80/path/to/doc", "auth_token") { // Tue Jan 2 03:04:05 UTC 2018 time_system_.setSystemTime(std::chrono::milliseconds(1514862245000)); } void expectDocument(const absl::optional& document) { EXPECT_CALL(fetcher_, fetch("169.254.170.2:80", "/path/to/doc", _)).WillOnce(Return(document)); } Event::SimulatedTimeSystem time_system_; Api::ApiPtr api_; NiceMock fetcher_; TaskRoleCredentialsProvider provider_; }; TEST_F(TaskRoleCredentialsProviderTest, FailedFetchingDocument) { expectDocument(absl::optional()); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(TaskRoleCredentialsProviderTest, MalformedDocumenet) { expectDocument(R"EOF( not json )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(TaskRoleCredentialsProviderTest, EmptyValues) { expectDocument(R"EOF( { "AccessKeyId": "", "SecretAccessKey": "", "Token": "", "Expiration": "" } )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_FALSE(credentials.accessKeyId().has_value()); EXPECT_FALSE(credentials.secretAccessKey().has_value()); EXPECT_FALSE(credentials.sessionToken().has_value()); } TEST_F(TaskRoleCredentialsProviderTest, FullCachedCredentials) { expectDocument(R"EOF( { "AccessKeyId": "akid", "SecretAccessKey": "secret", "Token": "token", "Expiration": "20180102T030500Z" } )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_EQ("akid", credentials.accessKeyId().value()); EXPECT_EQ("secret", credentials.secretAccessKey().value()); EXPECT_EQ("token", credentials.sessionToken().value()); const auto cached_credentials = provider_.getCredentials(); EXPECT_EQ("akid", cached_credentials.accessKeyId().value()); EXPECT_EQ("secret", cached_credentials.secretAccessKey().value()); EXPECT_EQ("token", cached_credentials.sessionToken().value()); } TEST_F(TaskRoleCredentialsProviderTest, NormalCredentialExpiration) { InSequence sequence; expectDocument(R"EOF( { "AccessKeyId": "akid", "SecretAccessKey": "secret", "Token": "token", "Expiration": "20190102T030405Z" } )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_EQ("akid", credentials.accessKeyId().value()); EXPECT_EQ("secret", credentials.secretAccessKey().value()); EXPECT_EQ("token", credentials.sessionToken().value()); time_system_.advanceTimeWait(std::chrono::hours(2)); expectDocument(R"EOF( { "AccessKeyId": "new_akid", "SecretAccessKey": "new_secret", "Token": "new_token", "Expiration": "20190102T030405Z" } )EOF"); const auto cached_credentials = provider_.getCredentials(); EXPECT_EQ("new_akid", cached_credentials.accessKeyId().value()); EXPECT_EQ("new_secret", cached_credentials.secretAccessKey().value()); EXPECT_EQ("new_token", cached_credentials.sessionToken().value()); } TEST_F(TaskRoleCredentialsProviderTest, TimestampCredentialExpiration) { InSequence sequence; expectDocument(R"EOF( { "AccessKeyId": "akid", "SecretAccessKey": "secret", "Token": "token", "Expiration": "20180102T030405Z" } )EOF"); const auto credentials = provider_.getCredentials(); EXPECT_EQ("akid", credentials.accessKeyId().value()); EXPECT_EQ("secret", credentials.secretAccessKey().value()); EXPECT_EQ("token", credentials.sessionToken().value()); expectDocument(R"EOF( { "AccessKeyId": "new_akid", "SecretAccessKey": "new_secret", "Token": "new_token", "Expiration": "20190102T030405Z" } )EOF"); const auto cached_credentials = provider_.getCredentials(); EXPECT_EQ("new_akid", cached_credentials.accessKeyId().value()); EXPECT_EQ("new_secret", cached_credentials.secretAccessKey().value()); EXPECT_EQ("new_token", cached_credentials.sessionToken().value()); } class DefaultCredentialsProviderChainTest : public testing::Test { public: DefaultCredentialsProviderChainTest() : api_(Api::createApiForTest(time_system_)) { EXPECT_CALL(factories_, createEnvironmentCredentialsProvider()); } ~DefaultCredentialsProviderChainTest() override { TestEnvironment::unsetEnvVar("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); TestEnvironment::unsetEnvVar("AWS_CONTAINER_CREDENTIALS_FULL_URI"); TestEnvironment::unsetEnvVar("AWS_CONTAINER_AUTHORIZATION_TOKEN"); TestEnvironment::unsetEnvVar("AWS_EC2_METADATA_DISABLED"); } class MockCredentialsProviderChainFactories : public CredentialsProviderChainFactories { public: MOCK_METHOD(CredentialsProviderSharedPtr, createEnvironmentCredentialsProvider, (), (const)); MOCK_METHOD(CredentialsProviderSharedPtr, createTaskRoleCredentialsProvider, (Api::Api&, const MetadataCredentialsProviderBase::MetadataFetcher&, absl::string_view, absl::string_view), (const)); MOCK_METHOD(CredentialsProviderSharedPtr, createInstanceProfileCredentialsProvider, (Api::Api&, const MetadataCredentialsProviderBase::MetadataFetcher& fetcher), (const)); }; Event::SimulatedTimeSystem time_system_; Api::ApiPtr api_; NiceMock factories_; }; TEST_F(DefaultCredentialsProviderChainTest, NoEnvironmentVars) { EXPECT_CALL(factories_, createInstanceProfileCredentialsProvider(Ref(*api_), _)); DefaultCredentialsProviderChain chain(*api_, DummyMetadataFetcher(), factories_); } TEST_F(DefaultCredentialsProviderChainTest, MetadataDisabled) { TestEnvironment::setEnvVar("AWS_EC2_METADATA_DISABLED", "true", 1); EXPECT_CALL(factories_, createInstanceProfileCredentialsProvider(Ref(*api_), _)).Times(0); DefaultCredentialsProviderChain chain(*api_, DummyMetadataFetcher(), factories_); } TEST_F(DefaultCredentialsProviderChainTest, MetadataNotDisabled) { TestEnvironment::setEnvVar("AWS_EC2_METADATA_DISABLED", "false", 1); EXPECT_CALL(factories_, createInstanceProfileCredentialsProvider(Ref(*api_), _)); DefaultCredentialsProviderChain chain(*api_, DummyMetadataFetcher(), factories_); } TEST_F(DefaultCredentialsProviderChainTest, RelativeUri) { TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/path/to/creds", 1); EXPECT_CALL(factories_, createTaskRoleCredentialsProvider(Ref(*api_), _, "169.254.170.2:80/path/to/creds", "")); DefaultCredentialsProviderChain chain(*api_, DummyMetadataFetcher(), factories_); } TEST_F(DefaultCredentialsProviderChainTest, FullUriNoAuthorizationToken) { TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_FULL_URI", "http://host/path/to/creds", 1); EXPECT_CALL(factories_, createTaskRoleCredentialsProvider(Ref(*api_), _, "http://host/path/to/creds", "")); DefaultCredentialsProviderChain chain(*api_, DummyMetadataFetcher(), factories_); } TEST_F(DefaultCredentialsProviderChainTest, FullUriWithAuthorizationToken) { TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_FULL_URI", "http://host/path/to/creds", 1); TestEnvironment::setEnvVar("AWS_CONTAINER_AUTHORIZATION_TOKEN", "auth_token", 1); EXPECT_CALL(factories_, createTaskRoleCredentialsProvider( Ref(*api_), _, "http://host/path/to/creds", "auth_token")); DefaultCredentialsProviderChain chain(*api_, DummyMetadataFetcher(), factories_); } TEST(CredentialsProviderChainTest, getCredentials_noCredentials) { auto mock_provider1 = std::make_shared(); auto mock_provider2 = std::make_shared(); EXPECT_CALL(*mock_provider1, getCredentials()).Times(1); EXPECT_CALL(*mock_provider2, getCredentials()).Times(1); CredentialsProviderChain chain; chain.add(mock_provider1); chain.add(mock_provider2); const Credentials creds = chain.getCredentials(); EXPECT_EQ(Credentials(), creds); } TEST(CredentialsProviderChainTest, getCredentials_firstProviderReturns) { auto mock_provider1 = std::make_shared(); auto mock_provider2 = std::make_shared(); const Credentials creds("access_key", "secret_key"); EXPECT_CALL(*mock_provider1, getCredentials()).WillOnce(Return(creds)); EXPECT_CALL(*mock_provider2, getCredentials()).Times(0); CredentialsProviderChain chain; chain.add(mock_provider1); chain.add(mock_provider2); const Credentials ret_creds = chain.getCredentials(); EXPECT_EQ(creds, ret_creds); } TEST(CredentialsProviderChainTest, getCredentials_secondProviderReturns) { auto mock_provider1 = std::make_shared(); auto mock_provider2 = std::make_shared(); const Credentials creds("access_key", "secret_key"); EXPECT_CALL(*mock_provider1, getCredentials()).Times(1); EXPECT_CALL(*mock_provider2, getCredentials()).WillOnce(Return(creds)); CredentialsProviderChain chain; chain.add(mock_provider1); chain.add(mock_provider2); const Credentials ret_creds = chain.getCredentials(); EXPECT_EQ(creds, ret_creds); } } // namespace Aws } // namespace Common } // namespace Extensions } // namespace Envoy