Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / settings / device_oauth2_token_service_unittest.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "base/prefs/testing_pref_service.h"
9 #include "base/run_loop.h"
10 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
11 #include "chrome/browser/chromeos/settings/cros_settings.h"
12 #include "chrome/browser/chromeos/settings/device_settings_service.h"
13 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
14 #include "chrome/browser/chromeos/settings/token_encryptor.h"
15 #include "chrome/common/pref_names.h"
16 #include "chrome/test/base/scoped_testing_local_state.h"
17 #include "chrome/test/base/testing_browser_process.h"
18 #include "chromeos/cryptohome/system_salt_getter.h"
19 #include "chromeos/dbus/fake_cryptohome_client.h"
20 #include "chromeos/dbus/fake_dbus_thread_manager.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/test/test_browser_thread.h"
23 #include "google_apis/gaia/gaia_oauth_client.h"
24 #include "google_apis/gaia/oauth2_token_service_test_util.h"
25 #include "net/http/http_status_code.h"
26 #include "net/url_request/test_url_fetcher_factory.h"
27 #include "net/url_request/url_fetcher_delegate.h"
28 #include "net/url_request/url_request_test_util.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 namespace chromeos {
32
33 static const int kOAuthTokenServiceUrlFetcherId = 0;
34 static const int kValidatorUrlFetcherId = gaia::GaiaOAuthClient::kUrlFetcherId;
35
36 class DeviceOAuth2TokenServiceTest : public testing::Test {
37  public:
38   DeviceOAuth2TokenServiceTest()
39       : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
40         request_context_getter_(new net::TestURLRequestContextGetter(
41             message_loop_.message_loop_proxy())) {}
42   virtual ~DeviceOAuth2TokenServiceTest() {}
43
44   // Most tests just want a noop crypto impl with a dummy refresh token value in
45   // Local State (if the value is an empty string, it will be ignored).
46   void SetUpDefaultValues() {
47     SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
48     SetRobotAccountId("service_acct@g.com");
49     CreateService();
50     AssertConsumerTokensAndErrors(0, 0);
51
52     base::RunLoop().RunUntilIdle();
53   }
54
55   void SetUpWithPendingSalt() {
56     fake_cryptohome_client_->set_system_salt(std::vector<uint8>());
57     fake_cryptohome_client_->SetServiceIsAvailable(false);
58     SetUpDefaultValues();
59   }
60
61   void SetRobotAccountId(const std::string& account_id) {
62     device_policy_.policy_data().set_service_account_identity(account_id);
63     device_policy_.Build();
64     device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
65     DeviceSettingsService::Get()->Load();
66     device_settings_test_helper_.Flush();
67   }
68
69   scoped_ptr<OAuth2TokenService::Request> StartTokenRequest() {
70     return oauth2_service_->StartRequest(oauth2_service_->GetRobotAccountId(),
71                                          std::set<std::string>(),
72                                          &consumer_);
73   }
74
75   virtual void SetUp() OVERRIDE {
76     scoped_ptr<FakeDBusThreadManager> fake_dbus_thread_manager(
77         new FakeDBusThreadManager);
78     fake_cryptohome_client_ = new FakeCryptohomeClient;
79     fake_cryptohome_client_->SetServiceIsAvailable(true);
80     fake_cryptohome_client_->set_system_salt(
81         FakeCryptohomeClient::GetStubSystemSalt());
82     fake_dbus_thread_manager->SetCryptohomeClient(
83         scoped_ptr<CryptohomeClient>(fake_cryptohome_client_));
84
85     DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager.release());
86
87     SystemSaltGetter::Initialize();
88
89     DeviceSettingsService::Initialize();
90     scoped_refptr<MockOwnerKeyUtil> owner_key_util_(new MockOwnerKeyUtil());
91     owner_key_util_->SetPublicKeyFromPrivateKey(
92         *device_policy_.GetSigningKey());
93     DeviceSettingsService::Get()->SetSessionManager(
94         &device_settings_test_helper_, owner_key_util_);
95
96     CrosSettings::Initialize();
97   }
98
99   virtual void TearDown() OVERRIDE {
100     CrosSettings::Shutdown();
101     TestingBrowserProcess::GetGlobal()->SetBrowserPolicyConnector(NULL);
102     DeviceSettingsService::Get()->UnsetSessionManager();
103     DeviceSettingsService::Shutdown();
104     SystemSaltGetter::Shutdown();
105     DBusThreadManager::Shutdown();
106     base::RunLoop().RunUntilIdle();
107   }
108
109   void CreateService() {
110     oauth2_service_.reset(new DeviceOAuth2TokenService(
111         request_context_getter_.get(), scoped_testing_local_state_.Get()));
112     oauth2_service_->max_refresh_token_validation_retries_ = 0;
113     oauth2_service_->set_max_authorization_token_fetch_retries_for_testing(0);
114   }
115
116   // Utility method to set a value in Local State for the device refresh token
117   // (it must have a non-empty value or it won't be used).
118   void SetDeviceRefreshTokenInLocalState(const std::string& refresh_token) {
119     scoped_testing_local_state_.Get()->SetUserPref(
120         prefs::kDeviceRobotAnyApiRefreshToken,
121         new base::StringValue(refresh_token));
122   }
123
124   std::string GetValidTokenInfoResponse(const std::string email) {
125     return "{ \"email\": \"" + email + "\","
126            "  \"user_id\": \"1234567890\" }";
127   }
128
129   bool RefreshTokenIsAvailable() {
130     return oauth2_service_->RefreshTokenIsAvailable(
131         oauth2_service_->GetRobotAccountId());
132   }
133
134   std::string GetRefreshToken() {
135     if (!RefreshTokenIsAvailable())
136       return std::string();
137
138     return oauth2_service_->GetRefreshToken(
139         oauth2_service_->GetRobotAccountId());
140   }
141
142   // A utility method to return fake URL results, for testing the refresh token
143   // validation logic.  For a successful validation attempt, this method will be
144   // called three times for the steps listed below (steps 1 and 2 happen in
145   // parallel).
146   //
147   // Step 1a: fetch the access token for the tokeninfo API.
148   // Step 1b: call the tokeninfo API.
149   // Step 2:  Fetch the access token for the requested scope
150   //          (in this case, cloudprint).
151   void ReturnOAuthUrlFetchResults(int fetcher_id,
152                                   net::HttpStatusCode response_code,
153                                   const std::string&  response_string);
154
155   // Generates URL fetch replies with the specified results for requests
156   // generated by the token service.
157   void PerformURLFetchesWithResults(
158       net::HttpStatusCode tokeninfo_access_token_status,
159       const std::string& tokeninfo_access_token_response,
160       net::HttpStatusCode tokeninfo_fetch_status,
161       const std::string& tokeninfo_fetch_response,
162       net::HttpStatusCode service_access_token_status,
163       const std::string& service_access_token_response);
164
165   // Generates URL fetch replies for the success path.
166   void PerformURLFetches();
167
168   void AssertConsumerTokensAndErrors(int num_tokens, int num_errors);
169
170  protected:
171   // This is here because DeviceOAuth2TokenService's destructor is private;
172   // base::DefaultDeleter therefore doesn't work. However, the test class is
173   // declared friend in DeviceOAuth2TokenService, so this deleter works.
174   struct TokenServiceDeleter {
175     inline void operator()(DeviceOAuth2TokenService* ptr) const {
176       delete ptr;
177     }
178   };
179
180   base::MessageLoop message_loop_;
181   ScopedTestingLocalState scoped_testing_local_state_;
182   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
183   net::TestURLFetcherFactory factory_;
184   FakeCryptohomeClient* fake_cryptohome_client_;
185   DeviceSettingsTestHelper device_settings_test_helper_;
186   policy::DevicePolicyBuilder device_policy_;
187   scoped_ptr<DeviceOAuth2TokenService, TokenServiceDeleter> oauth2_service_;
188   TestingOAuth2TokenServiceConsumer consumer_;
189 };
190
191 void DeviceOAuth2TokenServiceTest::ReturnOAuthUrlFetchResults(
192     int fetcher_id,
193     net::HttpStatusCode response_code,
194     const std::string& response_string) {
195   net::TestURLFetcher* fetcher = factory_.GetFetcherByID(fetcher_id);
196   if (fetcher) {
197     factory_.RemoveFetcherFromMap(fetcher_id);
198     fetcher->set_response_code(response_code);
199     fetcher->SetResponseString(response_string);
200     fetcher->delegate()->OnURLFetchComplete(fetcher);
201     base::RunLoop().RunUntilIdle();
202   }
203 }
204
205 void DeviceOAuth2TokenServiceTest::PerformURLFetchesWithResults(
206     net::HttpStatusCode tokeninfo_access_token_status,
207     const std::string& tokeninfo_access_token_response,
208     net::HttpStatusCode tokeninfo_fetch_status,
209     const std::string& tokeninfo_fetch_response,
210     net::HttpStatusCode service_access_token_status,
211     const std::string& service_access_token_response) {
212   ReturnOAuthUrlFetchResults(
213       kValidatorUrlFetcherId,
214       tokeninfo_access_token_status,
215       tokeninfo_access_token_response);
216
217   ReturnOAuthUrlFetchResults(
218       kValidatorUrlFetcherId,
219       tokeninfo_fetch_status,
220       tokeninfo_fetch_response);
221
222   ReturnOAuthUrlFetchResults(
223       kOAuthTokenServiceUrlFetcherId,
224       service_access_token_status,
225       service_access_token_response);
226 }
227
228 void DeviceOAuth2TokenServiceTest::PerformURLFetches() {
229   PerformURLFetchesWithResults(
230       net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
231       net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
232       net::HTTP_OK, GetValidTokenResponse("scoped_access_token", 3600));
233 }
234
235 void DeviceOAuth2TokenServiceTest::AssertConsumerTokensAndErrors(
236     int num_tokens,
237     int num_errors) {
238   EXPECT_EQ(num_tokens, consumer_.number_of_successful_tokens_);
239   EXPECT_EQ(num_errors, consumer_.number_of_errors_);
240 }
241
242 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) {
243   CreateService();
244
245   oauth2_service_->SetAndSaveRefreshToken(
246       "test-token", DeviceOAuth2TokenService::StatusCallback());
247   EXPECT_EQ("test-token", GetRefreshToken());
248 }
249
250 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedTokenEarly) {
251   // Set a new refresh token without the system salt available.
252   SetUpWithPendingSalt();
253
254   oauth2_service_->SetAndSaveRefreshToken(
255       "test-token", DeviceOAuth2TokenService::StatusCallback());
256   EXPECT_EQ("test-token", GetRefreshToken());
257
258   // Make the system salt available.
259   fake_cryptohome_client_->set_system_salt(
260       FakeCryptohomeClient::GetStubSystemSalt());
261   fake_cryptohome_client_->SetServiceIsAvailable(true);
262   base::RunLoop().RunUntilIdle();
263
264   // The original token should still be present.
265   EXPECT_EQ("test-token", GetRefreshToken());
266
267   // Reloading shouldn't change the token either.
268   CreateService();
269   base::RunLoop().RunUntilIdle();
270   EXPECT_EQ("test-token", GetRefreshToken());
271 }
272
273 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Success) {
274   SetUpDefaultValues();
275   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
276
277   PerformURLFetches();
278   AssertConsumerTokensAndErrors(1, 0);
279
280   EXPECT_EQ("scoped_access_token", consumer_.last_token_);
281 }
282
283 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_SuccessAsyncLoad) {
284   SetUpWithPendingSalt();
285
286   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
287   PerformURLFetches();
288   AssertConsumerTokensAndErrors(0, 0);
289
290   fake_cryptohome_client_->set_system_salt(
291       FakeCryptohomeClient::GetStubSystemSalt());
292   fake_cryptohome_client_->SetServiceIsAvailable(true);
293   base::RunLoop().RunUntilIdle();
294
295   PerformURLFetches();
296   AssertConsumerTokensAndErrors(1, 0);
297
298   EXPECT_EQ("scoped_access_token", consumer_.last_token_);
299 }
300
301 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Cancel) {
302   SetUpDefaultValues();
303   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
304   request.reset();
305
306   PerformURLFetches();
307
308   // Test succeeds if this line is reached without a crash.
309 }
310
311 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_NoSalt) {
312   fake_cryptohome_client_->set_system_salt(std::vector<uint8>());
313   fake_cryptohome_client_->SetServiceIsAvailable(true);
314   SetUpDefaultValues();
315
316   EXPECT_FALSE(RefreshTokenIsAvailable());
317
318   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
319   base::RunLoop().RunUntilIdle();
320
321   AssertConsumerTokensAndErrors(0, 1);
322 }
323
324 TEST_F(DeviceOAuth2TokenServiceTest,
325        RefreshTokenValidation_Failure_TokenInfoAccessTokenHttpError) {
326   SetUpDefaultValues();
327   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
328
329   PerformURLFetchesWithResults(
330       net::HTTP_UNAUTHORIZED, "",
331       net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
332       net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
333
334   AssertConsumerTokensAndErrors(0, 1);
335 }
336
337 TEST_F(DeviceOAuth2TokenServiceTest,
338        RefreshTokenValidation_Failure_TokenInfoAccessTokenInvalidResponse) {
339   SetUpDefaultValues();
340   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
341
342   PerformURLFetchesWithResults(
343       net::HTTP_OK, "invalid response",
344       net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
345       net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
346
347   AssertConsumerTokensAndErrors(0, 1);
348 }
349
350 TEST_F(DeviceOAuth2TokenServiceTest,
351        RefreshTokenValidation_Failure_TokenInfoApiCallHttpError) {
352   SetUpDefaultValues();
353   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
354
355   PerformURLFetchesWithResults(
356       net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
357       net::HTTP_INTERNAL_SERVER_ERROR, "",
358       net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
359
360   AssertConsumerTokensAndErrors(0, 1);
361 }
362
363 TEST_F(DeviceOAuth2TokenServiceTest,
364        RefreshTokenValidation_Failure_TokenInfoApiCallInvalidResponse) {
365   SetUpDefaultValues();
366   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
367
368   PerformURLFetchesWithResults(
369       net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
370       net::HTTP_OK, "invalid response",
371       net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
372
373   AssertConsumerTokensAndErrors(0, 1);
374 }
375
376 TEST_F(DeviceOAuth2TokenServiceTest,
377        RefreshTokenValidation_Failure_CloudPrintAccessTokenHttpError) {
378   SetUpDefaultValues();
379   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
380
381   PerformURLFetchesWithResults(
382       net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
383       net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
384       net::HTTP_BAD_REQUEST, "");
385
386   AssertConsumerTokensAndErrors(0, 1);
387 }
388
389 TEST_F(DeviceOAuth2TokenServiceTest,
390        RefreshTokenValidation_Failure_CloudPrintAccessTokenInvalidResponse) {
391   SetUpDefaultValues();
392   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
393
394   PerformURLFetchesWithResults(
395       net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
396       net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
397       net::HTTP_OK, "invalid request");
398
399   AssertConsumerTokensAndErrors(0, 1);
400 }
401
402 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Failure_BadOwner) {
403   SetUpDefaultValues();
404   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
405
406   SetRobotAccountId("WRONG_service_acct@g.com");
407
408   PerformURLFetchesWithResults(
409       net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
410       net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
411       net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
412
413   AssertConsumerTokensAndErrors(0, 1);
414 }
415
416 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Retry) {
417   SetUpDefaultValues();
418   scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
419
420   PerformURLFetchesWithResults(
421       net::HTTP_INTERNAL_SERVER_ERROR, "",
422       net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
423       net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
424
425   AssertConsumerTokensAndErrors(0, 1);
426
427   // Retry should succeed.
428   request = StartTokenRequest();
429   PerformURLFetches();
430   AssertConsumerTokensAndErrors(1, 1);
431 }
432
433 }  // namespace chromeos