Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / chromeos / settings / device_oauth2_token_service_unittest.cc
blob78328ff0f90b9a592cfd9a4de41ee382ebfc87ed
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.
5 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/prefs/testing_pref_service.h"
9 #include "base/run_loop.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
12 #include "chrome/browser/chromeos/settings/cros_settings.h"
13 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h"
14 #include "chrome/browser/chromeos/settings/device_settings_service.h"
15 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
16 #include "chrome/browser/chromeos/settings/token_encryptor.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/test/base/scoped_testing_local_state.h"
19 #include "chrome/test/base/testing_browser_process.h"
20 #include "chromeos/cryptohome/system_salt_getter.h"
21 #include "chromeos/dbus/dbus_thread_manager.h"
22 #include "chromeos/dbus/fake_cryptohome_client.h"
23 #include "components/ownership/mock_owner_key_util.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/test/test_browser_thread.h"
26 #include "google_apis/gaia/gaia_oauth_client.h"
27 #include "google_apis/gaia/oauth2_token_service_test_util.h"
28 #include "net/http/http_status_code.h"
29 #include "net/url_request/test_url_fetcher_factory.h"
30 #include "net/url_request/url_fetcher_delegate.h"
31 #include "net/url_request/url_request_test_util.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
35 namespace chromeos {
37 namespace {
39 class MockOAuth2TokenServiceObserver : public OAuth2TokenService::Observer {
40 public:
41 MockOAuth2TokenServiceObserver();
42 ~MockOAuth2TokenServiceObserver() override;
44 MOCK_METHOD1(OnRefreshTokenAvailable, void(const std::string&));
47 MockOAuth2TokenServiceObserver::MockOAuth2TokenServiceObserver() {
50 MockOAuth2TokenServiceObserver::~MockOAuth2TokenServiceObserver() {
53 } // namespace
55 static const int kOAuthTokenServiceUrlFetcherId = 0;
56 static const int kValidatorUrlFetcherId = gaia::GaiaOAuthClient::kUrlFetcherId;
58 class DeviceOAuth2TokenServiceTest : public testing::Test {
59 public:
60 DeviceOAuth2TokenServiceTest()
61 : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
62 request_context_getter_(
63 new net::TestURLRequestContextGetter(message_loop_.task_runner())) {
65 ~DeviceOAuth2TokenServiceTest() override {}
67 // Most tests just want a noop crypto impl with a dummy refresh token value in
68 // Local State (if the value is an empty string, it will be ignored).
69 void SetUpDefaultValues() {
70 SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
71 SetRobotAccountId("service_acct@g.com");
72 CreateService();
73 AssertConsumerTokensAndErrors(0, 0);
75 base::RunLoop().RunUntilIdle();
78 void SetUpWithPendingSalt() {
79 fake_cryptohome_client_->set_system_salt(std::vector<uint8>());
80 fake_cryptohome_client_->SetServiceIsAvailable(false);
81 SetUpDefaultValues();
84 void SetRobotAccountId(const std::string& account_id) {
85 device_policy_.policy_data().set_service_account_identity(account_id);
86 device_policy_.Build();
87 device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
88 DeviceSettingsService::Get()->Load();
89 device_settings_test_helper_.Flush();
92 scoped_ptr<OAuth2TokenService::Request> StartTokenRequest() {
93 return oauth2_service_->StartRequest(oauth2_service_->GetRobotAccountId(),
94 std::set<std::string>(),
95 &consumer_);
98 void SetUp() override {
99 fake_cryptohome_client_ = new FakeCryptohomeClient;
100 fake_cryptohome_client_->SetServiceIsAvailable(true);
101 fake_cryptohome_client_->set_system_salt(
102 FakeCryptohomeClient::GetStubSystemSalt());
103 chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
104 scoped_ptr<CryptohomeClient>(fake_cryptohome_client_));
106 SystemSaltGetter::Initialize();
108 DeviceSettingsService::Initialize();
109 scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_(
110 new ownership::MockOwnerKeyUtil());
111 owner_key_util_->SetPublicKeyFromPrivateKey(
112 *device_policy_.GetSigningKey());
113 DeviceSettingsService::Get()->SetSessionManager(
114 &device_settings_test_helper_, owner_key_util_);
116 CrosSettings::Initialize();
119 void TearDown() override {
120 oauth2_service_.reset();
121 CrosSettings::Shutdown();
122 TestingBrowserProcess::GetGlobal()->SetBrowserPolicyConnector(NULL);
123 content::BrowserThread::GetBlockingPool()->FlushForTesting();
124 DeviceSettingsService::Get()->UnsetSessionManager();
125 DeviceSettingsService::Shutdown();
126 SystemSaltGetter::Shutdown();
127 DBusThreadManager::Shutdown();
128 base::RunLoop().RunUntilIdle();
131 void CreateService() {
132 DeviceOAuth2TokenServiceDelegate* delegate =
133 new DeviceOAuth2TokenServiceDelegate(request_context_getter_.get(),
134 scoped_testing_local_state_.Get());
135 delegate->max_refresh_token_validation_retries_ = 0;
136 oauth2_service_.reset(new DeviceOAuth2TokenService(delegate));
137 oauth2_service_->set_max_authorization_token_fetch_retries_for_testing(0);
140 // Utility method to set a value in Local State for the device refresh token
141 // (it must have a non-empty value or it won't be used).
142 void SetDeviceRefreshTokenInLocalState(const std::string& refresh_token) {
143 scoped_testing_local_state_.Get()->SetUserPref(
144 prefs::kDeviceRobotAnyApiRefreshToken,
145 new base::StringValue(refresh_token));
148 std::string GetValidTokenInfoResponse(const std::string email) {
149 return "{ \"email\": \"" + email + "\","
150 " \"user_id\": \"1234567890\" }";
153 bool RefreshTokenIsAvailable() {
154 return oauth2_service_->RefreshTokenIsAvailable(
155 oauth2_service_->GetRobotAccountId());
158 std::string GetRefreshToken() {
159 if (!RefreshTokenIsAvailable())
160 return std::string();
162 return static_cast<DeviceOAuth2TokenServiceDelegate*>(
163 oauth2_service_->GetDelegate())
164 ->GetRefreshToken(oauth2_service_->GetRobotAccountId());
167 // A utility method to return fake URL results, for testing the refresh token
168 // validation logic. For a successful validation attempt, this method will be
169 // called three times for the steps listed below (steps 1 and 2 happen in
170 // parallel).
172 // Step 1a: fetch the access token for the tokeninfo API.
173 // Step 1b: call the tokeninfo API.
174 // Step 2: Fetch the access token for the requested scope
175 // (in this case, cloudprint).
176 void ReturnOAuthUrlFetchResults(int fetcher_id,
177 net::HttpStatusCode response_code,
178 const std::string& response_string);
180 // Generates URL fetch replies with the specified results for requests
181 // generated by the token service.
182 void PerformURLFetchesWithResults(
183 net::HttpStatusCode tokeninfo_access_token_status,
184 const std::string& tokeninfo_access_token_response,
185 net::HttpStatusCode tokeninfo_fetch_status,
186 const std::string& tokeninfo_fetch_response,
187 net::HttpStatusCode service_access_token_status,
188 const std::string& service_access_token_response);
190 // Generates URL fetch replies for the success path.
191 void PerformURLFetches();
193 void AssertConsumerTokensAndErrors(int num_tokens, int num_errors);
195 protected:
196 // This is here because DeviceOAuth2TokenService's destructor is private;
197 // base::DefaultDeleter therefore doesn't work. However, the test class is
198 // declared friend in DeviceOAuth2TokenService, so this deleter works.
199 struct TokenServiceDeleter {
200 inline void operator()(DeviceOAuth2TokenService* ptr) const {
201 delete ptr;
205 base::MessageLoop message_loop_;
206 ScopedTestingLocalState scoped_testing_local_state_;
207 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
208 net::TestURLFetcherFactory factory_;
209 FakeCryptohomeClient* fake_cryptohome_client_;
210 DeviceSettingsTestHelper device_settings_test_helper_;
211 policy::DevicePolicyBuilder device_policy_;
212 scoped_ptr<DeviceOAuth2TokenService, TokenServiceDeleter> oauth2_service_;
213 TestingOAuth2TokenServiceConsumer consumer_;
216 void DeviceOAuth2TokenServiceTest::ReturnOAuthUrlFetchResults(
217 int fetcher_id,
218 net::HttpStatusCode response_code,
219 const std::string& response_string) {
220 net::TestURLFetcher* fetcher = factory_.GetFetcherByID(fetcher_id);
221 if (fetcher) {
222 factory_.RemoveFetcherFromMap(fetcher_id);
223 fetcher->set_response_code(response_code);
224 fetcher->SetResponseString(response_string);
225 fetcher->delegate()->OnURLFetchComplete(fetcher);
226 base::RunLoop().RunUntilIdle();
230 void DeviceOAuth2TokenServiceTest::PerformURLFetchesWithResults(
231 net::HttpStatusCode tokeninfo_access_token_status,
232 const std::string& tokeninfo_access_token_response,
233 net::HttpStatusCode tokeninfo_fetch_status,
234 const std::string& tokeninfo_fetch_response,
235 net::HttpStatusCode service_access_token_status,
236 const std::string& service_access_token_response) {
237 ReturnOAuthUrlFetchResults(
238 kValidatorUrlFetcherId,
239 tokeninfo_access_token_status,
240 tokeninfo_access_token_response);
242 ReturnOAuthUrlFetchResults(
243 kValidatorUrlFetcherId,
244 tokeninfo_fetch_status,
245 tokeninfo_fetch_response);
247 ReturnOAuthUrlFetchResults(
248 kOAuthTokenServiceUrlFetcherId,
249 service_access_token_status,
250 service_access_token_response);
253 void DeviceOAuth2TokenServiceTest::PerformURLFetches() {
254 PerformURLFetchesWithResults(
255 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
256 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
257 net::HTTP_OK, GetValidTokenResponse("scoped_access_token", 3600));
260 void DeviceOAuth2TokenServiceTest::AssertConsumerTokensAndErrors(
261 int num_tokens,
262 int num_errors) {
263 EXPECT_EQ(num_tokens, consumer_.number_of_successful_tokens_);
264 EXPECT_EQ(num_errors, consumer_.number_of_errors_);
267 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) {
268 CreateService();
270 oauth2_service_->SetAndSaveRefreshToken(
271 "test-token", DeviceOAuth2TokenService::StatusCallback());
272 EXPECT_EQ("test-token", GetRefreshToken());
275 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedTokenEarly) {
276 // Set a new refresh token without the system salt available.
277 SetUpWithPendingSalt();
279 oauth2_service_->SetAndSaveRefreshToken(
280 "test-token", DeviceOAuth2TokenService::StatusCallback());
281 EXPECT_EQ("test-token", GetRefreshToken());
283 // Make the system salt available.
284 fake_cryptohome_client_->set_system_salt(
285 FakeCryptohomeClient::GetStubSystemSalt());
286 fake_cryptohome_client_->SetServiceIsAvailable(true);
287 base::RunLoop().RunUntilIdle();
289 // The original token should still be present.
290 EXPECT_EQ("test-token", GetRefreshToken());
292 // Reloading shouldn't change the token either.
293 CreateService();
294 base::RunLoop().RunUntilIdle();
295 EXPECT_EQ("test-token", GetRefreshToken());
298 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Success) {
299 SetUpDefaultValues();
300 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
302 PerformURLFetches();
303 AssertConsumerTokensAndErrors(1, 0);
305 EXPECT_EQ("scoped_access_token", consumer_.last_token_);
308 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_SuccessAsyncLoad) {
309 SetUpWithPendingSalt();
311 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
312 PerformURLFetches();
313 AssertConsumerTokensAndErrors(0, 0);
315 fake_cryptohome_client_->set_system_salt(
316 FakeCryptohomeClient::GetStubSystemSalt());
317 fake_cryptohome_client_->SetServiceIsAvailable(true);
318 base::RunLoop().RunUntilIdle();
320 PerformURLFetches();
321 AssertConsumerTokensAndErrors(1, 0);
323 EXPECT_EQ("scoped_access_token", consumer_.last_token_);
326 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Cancel) {
327 SetUpDefaultValues();
328 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
329 request.reset();
331 PerformURLFetches();
333 // Test succeeds if this line is reached without a crash.
336 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_NoSalt) {
337 fake_cryptohome_client_->set_system_salt(std::vector<uint8>());
338 fake_cryptohome_client_->SetServiceIsAvailable(true);
339 SetUpDefaultValues();
341 EXPECT_FALSE(RefreshTokenIsAvailable());
343 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
344 base::RunLoop().RunUntilIdle();
346 AssertConsumerTokensAndErrors(0, 1);
349 TEST_F(DeviceOAuth2TokenServiceTest,
350 RefreshTokenValidation_Failure_TokenInfoAccessTokenHttpError) {
351 SetUpDefaultValues();
352 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
354 PerformURLFetchesWithResults(
355 net::HTTP_UNAUTHORIZED, "",
356 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
357 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
359 AssertConsumerTokensAndErrors(0, 1);
362 TEST_F(DeviceOAuth2TokenServiceTest,
363 RefreshTokenValidation_Failure_TokenInfoAccessTokenInvalidResponse) {
364 SetUpDefaultValues();
365 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
367 PerformURLFetchesWithResults(
368 net::HTTP_OK, "invalid response",
369 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
370 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
372 AssertConsumerTokensAndErrors(0, 1);
375 TEST_F(DeviceOAuth2TokenServiceTest,
376 RefreshTokenValidation_Failure_TokenInfoApiCallHttpError) {
377 SetUpDefaultValues();
378 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
380 PerformURLFetchesWithResults(
381 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
382 net::HTTP_INTERNAL_SERVER_ERROR, "",
383 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
385 AssertConsumerTokensAndErrors(0, 1);
388 TEST_F(DeviceOAuth2TokenServiceTest,
389 RefreshTokenValidation_Failure_TokenInfoApiCallInvalidResponse) {
390 SetUpDefaultValues();
391 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
393 PerformURLFetchesWithResults(
394 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
395 net::HTTP_OK, "invalid response",
396 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
398 AssertConsumerTokensAndErrors(0, 1);
401 TEST_F(DeviceOAuth2TokenServiceTest,
402 RefreshTokenValidation_Failure_CloudPrintAccessTokenHttpError) {
403 SetUpDefaultValues();
404 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
406 PerformURLFetchesWithResults(
407 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
408 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
409 net::HTTP_BAD_REQUEST, "");
411 AssertConsumerTokensAndErrors(0, 1);
414 TEST_F(DeviceOAuth2TokenServiceTest,
415 RefreshTokenValidation_Failure_CloudPrintAccessTokenInvalidResponse) {
416 SetUpDefaultValues();
417 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
419 PerformURLFetchesWithResults(
420 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
421 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
422 net::HTTP_OK, "invalid request");
424 AssertConsumerTokensAndErrors(0, 1);
427 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Failure_BadOwner) {
428 SetUpDefaultValues();
429 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
431 SetRobotAccountId("WRONG_service_acct@g.com");
433 PerformURLFetchesWithResults(
434 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
435 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
436 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
438 AssertConsumerTokensAndErrors(0, 1);
441 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Retry) {
442 SetUpDefaultValues();
443 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
445 PerformURLFetchesWithResults(
446 net::HTTP_INTERNAL_SERVER_ERROR, "",
447 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
448 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
450 AssertConsumerTokensAndErrors(0, 1);
452 // Retry should succeed.
453 request = StartTokenRequest();
454 PerformURLFetches();
455 AssertConsumerTokensAndErrors(1, 1);
458 TEST_F(DeviceOAuth2TokenServiceTest, DoNotAnnounceTokenWithoutAccountID) {
459 CreateService();
461 testing::StrictMock<MockOAuth2TokenServiceObserver> observer;
462 oauth2_service_->AddObserver(&observer);
464 // Make a token available during enrollment. Verify that the token is not
465 // announced yet.
466 oauth2_service_->SetAndSaveRefreshToken(
467 "test-token", DeviceOAuth2TokenService::StatusCallback());
468 testing::Mock::VerifyAndClearExpectations(&observer);
470 // Also make the robot account ID available. Verify that the token is
471 // announced now.
472 EXPECT_CALL(observer, OnRefreshTokenAvailable("robot@example.com"));
473 SetRobotAccountId("robot@example.com");
474 testing::Mock::VerifyAndClearExpectations(&observer);
476 oauth2_service_->RemoveObserver(&observer);
479 } // namespace chromeos