1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "google/cloud/storage/client.h"
16 #include "google/cloud/storage/testing/storage_integration_test.h"
17 #include "google/cloud/internal/getenv.h"
18 #include "google/cloud/testing_util/assert_ok.h"
19 #include <gmock/gmock.h>
20 
21 namespace google {
22 namespace cloud {
23 namespace storage {
24 inline namespace STORAGE_CLIENT_NS {
25 namespace {
26 
27 class ServiceAccountIntegrationTest
28     : public google::cloud::storage::testing::StorageIntegrationTest {
29  protected:
SetUp()30   void SetUp() override {
31     project_id_ =
32         google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT").value_or("");
33     ASSERT_FALSE(project_id_.empty());
34     service_account_ = google::cloud::internal::GetEnv(
35                            "GOOGLE_CLOUD_CPP_STORAGE_TEST_HMAC_SERVICE_ACCOUNT")
36                            .value_or("");
37     ASSERT_FALSE(service_account_.empty());
38   }
39 
40   std::string project_id_;
41   std::string service_account_;
42 };
43 
TEST_F(ServiceAccountIntegrationTest,Get)44 TEST_F(ServiceAccountIntegrationTest, Get) {
45   StatusOr<Client> client = MakeIntegrationTestClient();
46   ASSERT_STATUS_OK(client);
47 
48   StatusOr<ServiceAccount> a1 =
49       client->GetServiceAccountForProject(project_id_);
50   ASSERT_STATUS_OK(a1);
51   EXPECT_FALSE(a1->email_address().empty());
52 
53   auto client_options = ClientOptions::CreateDefaultClientOptions();
54   ASSERT_STATUS_OK(client_options);
55   Client client_with_default(client_options->set_project_id(project_id_));
56   StatusOr<ServiceAccount> a2 = client_with_default.GetServiceAccount();
57   ASSERT_STATUS_OK(a2);
58   EXPECT_FALSE(a2->email_address().empty());
59 
60   EXPECT_EQ(*a1, *a2);
61 }
62 
TEST_F(ServiceAccountIntegrationTest,CreateHmacKeyForProject)63 TEST_F(ServiceAccountIntegrationTest, CreateHmacKeyForProject) {
64   auto client_options = ClientOptions::CreateDefaultClientOptions();
65   ASSERT_STATUS_OK(client_options);
66 
67   Client client(client_options->set_project_id(project_id_));
68 
69   StatusOr<std::pair<HmacKeyMetadata, std::string>> key = client.CreateHmacKey(
70       service_account_, OverrideDefaultProject(project_id_));
71   ASSERT_STATUS_OK(key);
72 
73   EXPECT_FALSE(key->second.empty());
74 
75   StatusOr<HmacKeyMetadata> update_details = client.UpdateHmacKey(
76       key->first.access_id(), HmacKeyMetadata().set_state("INACTIVE"));
77   ASSERT_STATUS_OK(update_details);
78   EXPECT_EQ("INACTIVE", update_details->state());
79 
80   Status deleted_key = client.DeleteHmacKey(key->first.access_id());
81   ASSERT_STATUS_OK(deleted_key);
82 }
83 
TEST_F(ServiceAccountIntegrationTest,HmacKeyCRUD)84 TEST_F(ServiceAccountIntegrationTest, HmacKeyCRUD) {
85   auto client_options = ClientOptions::CreateDefaultClientOptions();
86   ASSERT_STATUS_OK(client_options);
87 
88   Client client(client_options->set_project_id(project_id_));
89 
90   auto get_current_access_ids = [&client, this]() {
91     std::vector<std::string> access_ids;
92     auto range = client.ListHmacKeys(OverrideDefaultProject(project_id_),
93                                      ServiceAccountFilter(service_account_));
94     std::transform(
95         range.begin(), range.end(), std::back_inserter(access_ids),
96         [](StatusOr<HmacKeyMetadata> x) { return x.value().access_id(); });
97     return access_ids;
98   };
99 
100   auto initial_access_ids = get_current_access_ids();
101 
102   StatusOr<std::pair<HmacKeyMetadata, std::string>> key =
103       client.CreateHmacKey(service_account_);
104   ASSERT_STATUS_OK(key);
105 
106   EXPECT_FALSE(key->second.empty());
107   auto access_id = key->first.access_id();
108 
109   using ::testing::Contains;
110   using ::testing::Not;
111   EXPECT_THAT(initial_access_ids, Not(Contains(access_id)));
112 
113   auto post_create_access_ids = get_current_access_ids();
114   EXPECT_THAT(post_create_access_ids, Contains(access_id));
115 
116   StatusOr<HmacKeyMetadata> get_details = client.GetHmacKey(access_id);
117   ASSERT_STATUS_OK(get_details);
118 
119   EXPECT_EQ(access_id, get_details->access_id());
120   HmacKeyMetadata original = key->first;
121   // TODO(#3806) - remove this workaround: the etag may have changed since the
122   // key was created.
123   original.set_etag(get_details->etag());
124   EXPECT_EQ(original, *get_details);
125 
126   StatusOr<HmacKeyMetadata> update_details =
127       client.UpdateHmacKey(access_id, HmacKeyMetadata().set_state("INACTIVE"));
128   ASSERT_STATUS_OK(update_details);
129   EXPECT_EQ("INACTIVE", update_details->state());
130 
131   Status deleted_key = client.DeleteHmacKey(key->first.access_id());
132   ASSERT_STATUS_OK(deleted_key);
133 
134   auto post_delete_access_ids = get_current_access_ids();
135   EXPECT_THAT(post_delete_access_ids, Not(Contains(access_id)));
136 }
137 
TEST_F(ServiceAccountIntegrationTest,HmacKeyCRUDFailures)138 TEST_F(ServiceAccountIntegrationTest, HmacKeyCRUDFailures) {
139   auto client_options = ClientOptions::CreateDefaultClientOptions();
140   ASSERT_STATUS_OK(client_options);
141 
142   Client client(client_options->set_project_id(project_id_));
143 
144   // Test failures in the HmacKey operations by using an invalid project id:
145   auto create_status = client.CreateHmacKey("invalid-service-account",
146                                             OverrideDefaultProject(""));
147   EXPECT_FALSE(create_status) << "value=" << create_status->first;
148 
149   Status deleted_status =
150       client.DeleteHmacKey("invalid-access-id", OverrideDefaultProject(""));
151   EXPECT_FALSE(deleted_status.ok());
152 
153   StatusOr<HmacKeyMetadata> get_status =
154       client.GetHmacKey("invalid-access-id", OverrideDefaultProject(""));
155   EXPECT_FALSE(get_status) << "value=" << *get_status;
156 
157   StatusOr<HmacKeyMetadata> update_status = client.UpdateHmacKey(
158       "invalid-access-id", HmacKeyMetadata(), OverrideDefaultProject(""));
159   EXPECT_FALSE(update_status) << "value=" << *update_status;
160 
161   auto range = client.ListHmacKeys(OverrideDefaultProject(""));
162   auto begin = range.begin();
163   EXPECT_NE(begin, range.end());
164   EXPECT_FALSE(*begin) << "value=" << **begin;
165 }
166 
167 }  // namespace
168 }  // namespace STORAGE_CLIENT_NS
169 }  // namespace storage
170 }  // namespace cloud
171 }  // namespace google
172