Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / chromeos / settings / device_oauth2_token_service_unittest.cc
blobe499498ff375b88ac8310911b9dae83e3cac2bac
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_settings_service.h"
14 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
15 #include "chrome/browser/chromeos/settings/token_encryptor.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/scoped_testing_local_state.h"
18 #include "chrome/test/base/testing_browser_process.h"
19 #include "chromeos/cryptohome/system_salt_getter.h"
20 #include "chromeos/dbus/dbus_thread_manager.h"
21 #include "chromeos/dbus/fake_cryptohome_client.h"
22 #include "components/ownership/mock_owner_key_util.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/test/test_browser_thread.h"
25 #include "google_apis/gaia/gaia_oauth_client.h"
26 #include "google_apis/gaia/oauth2_token_service_test_util.h"
27 #include "net/http/http_status_code.h"
28 #include "net/url_request/test_url_fetcher_factory.h"
29 #include "net/url_request/url_fetcher_delegate.h"
30 #include "net/url_request/url_request_test_util.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
34 namespace chromeos {
36 namespace {
38 class MockOAuth2TokenServiceObserver : public OAuth2TokenService::Observer {
39 public:
40 MockOAuth2TokenServiceObserver();
41 ~MockOAuth2TokenServiceObserver() override;
43 MOCK_METHOD1(OnRefreshTokenAvailable, void(const std::string&));
46 MockOAuth2TokenServiceObserver::MockOAuth2TokenServiceObserver() {
49 MockOAuth2TokenServiceObserver::~MockOAuth2TokenServiceObserver() {
52 } // namespace
54 static const int kOAuthTokenServiceUrlFetcherId = 0;
55 static const int kValidatorUrlFetcherId = gaia::GaiaOAuthClient::kUrlFetcherId;
57 class DeviceOAuth2TokenServiceTest : public testing::Test {
58 public:
59 DeviceOAuth2TokenServiceTest()
60 : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
61 request_context_getter_(new net::TestURLRequestContextGetter(
62 message_loop_.message_loop_proxy())) {}
63 ~DeviceOAuth2TokenServiceTest() override {}
65 // Most tests just want a noop crypto impl with a dummy refresh token value in
66 // Local State (if the value is an empty string, it will be ignored).
67 void SetUpDefaultValues() {
68 SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
69 SetRobotAccountId("service_acct@g.com");
70 CreateService();
71 AssertConsumerTokensAndErrors(0, 0);
73 base::RunLoop().RunUntilIdle();
76 void SetUpWithPendingSalt() {
77 fake_cryptohome_client_->set_system_salt(std::vector<uint8>());
78 fake_cryptohome_client_->SetServiceIsAvailable(false);
79 SetUpDefaultValues();
82 void SetRobotAccountId(const std::string& account_id) {
83 device_policy_.policy_data().set_service_account_identity(account_id);
84 device_policy_.Build();
85 device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
86 DeviceSettingsService::Get()->Load();
87 device_settings_test_helper_.Flush();
90 scoped_ptr<OAuth2TokenService::Request> StartTokenRequest() {
91 return oauth2_service_->StartRequest(oauth2_service_->GetRobotAccountId(),
92 std::set<std::string>(),
93 &consumer_);
96 void SetUp() override {
97 fake_cryptohome_client_ = new FakeCryptohomeClient;
98 fake_cryptohome_client_->SetServiceIsAvailable(true);
99 fake_cryptohome_client_->set_system_salt(
100 FakeCryptohomeClient::GetStubSystemSalt());
101 chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
102 scoped_ptr<CryptohomeClient>(fake_cryptohome_client_));
104 SystemSaltGetter::Initialize();
106 DeviceSettingsService::Initialize();
107 scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_(
108 new ownership::MockOwnerKeyUtil());
109 owner_key_util_->SetPublicKeyFromPrivateKey(
110 *device_policy_.GetSigningKey());
111 DeviceSettingsService::Get()->SetSessionManager(
112 &device_settings_test_helper_, owner_key_util_);
114 CrosSettings::Initialize();
117 void TearDown() override {
118 oauth2_service_.reset();
119 CrosSettings::Shutdown();
120 TestingBrowserProcess::GetGlobal()->SetBrowserPolicyConnector(NULL);
121 content::BrowserThread::GetBlockingPool()->FlushForTesting();
122 DeviceSettingsService::Get()->UnsetSessionManager();
123 DeviceSettingsService::Shutdown();
124 SystemSaltGetter::Shutdown();
125 DBusThreadManager::Shutdown();
126 base::RunLoop().RunUntilIdle();
129 void CreateService() {
130 oauth2_service_.reset(new DeviceOAuth2TokenService(
131 request_context_getter_.get(), scoped_testing_local_state_.Get()));
132 oauth2_service_->max_refresh_token_validation_retries_ = 0;
133 oauth2_service_->set_max_authorization_token_fetch_retries_for_testing(0);
136 // Utility method to set a value in Local State for the device refresh token
137 // (it must have a non-empty value or it won't be used).
138 void SetDeviceRefreshTokenInLocalState(const std::string& refresh_token) {
139 scoped_testing_local_state_.Get()->SetUserPref(
140 prefs::kDeviceRobotAnyApiRefreshToken,
141 new base::StringValue(refresh_token));
144 std::string GetValidTokenInfoResponse(const std::string email) {
145 return "{ \"email\": \"" + email + "\","
146 " \"user_id\": \"1234567890\" }";
149 bool RefreshTokenIsAvailable() {
150 return oauth2_service_->RefreshTokenIsAvailable(
151 oauth2_service_->GetRobotAccountId());
154 std::string GetRefreshToken() {
155 if (!RefreshTokenIsAvailable())
156 return std::string();
158 return oauth2_service_->GetRefreshToken(
159 oauth2_service_->GetRobotAccountId());
162 // A utility method to return fake URL results, for testing the refresh token
163 // validation logic. For a successful validation attempt, this method will be
164 // called three times for the steps listed below (steps 1 and 2 happen in
165 // parallel).
167 // Step 1a: fetch the access token for the tokeninfo API.
168 // Step 1b: call the tokeninfo API.
169 // Step 2: Fetch the access token for the requested scope
170 // (in this case, cloudprint).
171 void ReturnOAuthUrlFetchResults(int fetcher_id,
172 net::HttpStatusCode response_code,
173 const std::string& response_string);
175 // Generates URL fetch replies with the specified results for requests
176 // generated by the token service.
177 void PerformURLFetchesWithResults(
178 net::HttpStatusCode tokeninfo_access_token_status,
179 const std::string& tokeninfo_access_token_response,
180 net::HttpStatusCode tokeninfo_fetch_status,
181 const std::string& tokeninfo_fetch_response,
182 net::HttpStatusCode service_access_token_status,
183 const std::string& service_access_token_response);
185 // Generates URL fetch replies for the success path.
186 void PerformURLFetches();
188 void AssertConsumerTokensAndErrors(int num_tokens, int num_errors);
190 protected:
191 // This is here because DeviceOAuth2TokenService's destructor is private;
192 // base::DefaultDeleter therefore doesn't work. However, the test class is
193 // declared friend in DeviceOAuth2TokenService, so this deleter works.
194 struct TokenServiceDeleter {
195 inline void operator()(DeviceOAuth2TokenService* ptr) const {
196 delete ptr;
200 base::MessageLoop message_loop_;
201 ScopedTestingLocalState scoped_testing_local_state_;
202 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
203 net::TestURLFetcherFactory factory_;
204 FakeCryptohomeClient* fake_cryptohome_client_;
205 DeviceSettingsTestHelper device_settings_test_helper_;
206 policy::DevicePolicyBuilder device_policy_;
207 scoped_ptr<DeviceOAuth2TokenService, TokenServiceDeleter> oauth2_service_;
208 TestingOAuth2TokenServiceConsumer consumer_;
211 void DeviceOAuth2TokenServiceTest::ReturnOAuthUrlFetchResults(
212 int fetcher_id,
213 net::HttpStatusCode response_code,
214 const std::string& response_string) {
215 net::TestURLFetcher* fetcher = factory_.GetFetcherByID(fetcher_id);
216 if (fetcher) {
217 factory_.RemoveFetcherFromMap(fetcher_id);
218 fetcher->set_response_code(response_code);
219 fetcher->SetResponseString(response_string);
220 fetcher->delegate()->OnURLFetchComplete(fetcher);
221 base::RunLoop().RunUntilIdle();
225 void DeviceOAuth2TokenServiceTest::PerformURLFetchesWithResults(
226 net::HttpStatusCode tokeninfo_access_token_status,
227 const std::string& tokeninfo_access_token_response,
228 net::HttpStatusCode tokeninfo_fetch_status,
229 const std::string& tokeninfo_fetch_response,
230 net::HttpStatusCode service_access_token_status,
231 const std::string& service_access_token_response) {
232 ReturnOAuthUrlFetchResults(
233 kValidatorUrlFetcherId,
234 tokeninfo_access_token_status,
235 tokeninfo_access_token_response);
237 ReturnOAuthUrlFetchResults(
238 kValidatorUrlFetcherId,
239 tokeninfo_fetch_status,
240 tokeninfo_fetch_response);
242 ReturnOAuthUrlFetchResults(
243 kOAuthTokenServiceUrlFetcherId,
244 service_access_token_status,
245 service_access_token_response);
248 void DeviceOAuth2TokenServiceTest::PerformURLFetches() {
249 PerformURLFetchesWithResults(
250 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
251 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
252 net::HTTP_OK, GetValidTokenResponse("scoped_access_token", 3600));
255 void DeviceOAuth2TokenServiceTest::AssertConsumerTokensAndErrors(
256 int num_tokens,
257 int num_errors) {
258 EXPECT_EQ(num_tokens, consumer_.number_of_successful_tokens_);
259 EXPECT_EQ(num_errors, consumer_.number_of_errors_);
262 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) {
263 CreateService();
265 oauth2_service_->SetAndSaveRefreshToken(
266 "test-token", DeviceOAuth2TokenService::StatusCallback());
267 EXPECT_EQ("test-token", GetRefreshToken());
270 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedTokenEarly) {
271 // Set a new refresh token without the system salt available.
272 SetUpWithPendingSalt();
274 oauth2_service_->SetAndSaveRefreshToken(
275 "test-token", DeviceOAuth2TokenService::StatusCallback());
276 EXPECT_EQ("test-token", GetRefreshToken());
278 // Make the system salt available.
279 fake_cryptohome_client_->set_system_salt(
280 FakeCryptohomeClient::GetStubSystemSalt());
281 fake_cryptohome_client_->SetServiceIsAvailable(true);
282 base::RunLoop().RunUntilIdle();
284 // The original token should still be present.
285 EXPECT_EQ("test-token", GetRefreshToken());
287 // Reloading shouldn't change the token either.
288 CreateService();
289 base::RunLoop().RunUntilIdle();
290 EXPECT_EQ("test-token", GetRefreshToken());
293 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Success) {
294 SetUpDefaultValues();
295 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
297 PerformURLFetches();
298 AssertConsumerTokensAndErrors(1, 0);
300 EXPECT_EQ("scoped_access_token", consumer_.last_token_);
303 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_SuccessAsyncLoad) {
304 SetUpWithPendingSalt();
306 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
307 PerformURLFetches();
308 AssertConsumerTokensAndErrors(0, 0);
310 fake_cryptohome_client_->set_system_salt(
311 FakeCryptohomeClient::GetStubSystemSalt());
312 fake_cryptohome_client_->SetServiceIsAvailable(true);
313 base::RunLoop().RunUntilIdle();
315 PerformURLFetches();
316 AssertConsumerTokensAndErrors(1, 0);
318 EXPECT_EQ("scoped_access_token", consumer_.last_token_);
321 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Cancel) {
322 SetUpDefaultValues();
323 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
324 request.reset();
326 PerformURLFetches();
328 // Test succeeds if this line is reached without a crash.
331 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_NoSalt) {
332 fake_cryptohome_client_->set_system_salt(std::vector<uint8>());
333 fake_cryptohome_client_->SetServiceIsAvailable(true);
334 SetUpDefaultValues();
336 EXPECT_FALSE(RefreshTokenIsAvailable());
338 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
339 base::RunLoop().RunUntilIdle();
341 AssertConsumerTokensAndErrors(0, 1);
344 TEST_F(DeviceOAuth2TokenServiceTest,
345 RefreshTokenValidation_Failure_TokenInfoAccessTokenHttpError) {
346 SetUpDefaultValues();
347 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
349 PerformURLFetchesWithResults(
350 net::HTTP_UNAUTHORIZED, "",
351 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
352 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
354 AssertConsumerTokensAndErrors(0, 1);
357 TEST_F(DeviceOAuth2TokenServiceTest,
358 RefreshTokenValidation_Failure_TokenInfoAccessTokenInvalidResponse) {
359 SetUpDefaultValues();
360 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
362 PerformURLFetchesWithResults(
363 net::HTTP_OK, "invalid response",
364 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
365 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
367 AssertConsumerTokensAndErrors(0, 1);
370 TEST_F(DeviceOAuth2TokenServiceTest,
371 RefreshTokenValidation_Failure_TokenInfoApiCallHttpError) {
372 SetUpDefaultValues();
373 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
375 PerformURLFetchesWithResults(
376 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
377 net::HTTP_INTERNAL_SERVER_ERROR, "",
378 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
380 AssertConsumerTokensAndErrors(0, 1);
383 TEST_F(DeviceOAuth2TokenServiceTest,
384 RefreshTokenValidation_Failure_TokenInfoApiCallInvalidResponse) {
385 SetUpDefaultValues();
386 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
388 PerformURLFetchesWithResults(
389 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
390 net::HTTP_OK, "invalid response",
391 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
393 AssertConsumerTokensAndErrors(0, 1);
396 TEST_F(DeviceOAuth2TokenServiceTest,
397 RefreshTokenValidation_Failure_CloudPrintAccessTokenHttpError) {
398 SetUpDefaultValues();
399 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
401 PerformURLFetchesWithResults(
402 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
403 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
404 net::HTTP_BAD_REQUEST, "");
406 AssertConsumerTokensAndErrors(0, 1);
409 TEST_F(DeviceOAuth2TokenServiceTest,
410 RefreshTokenValidation_Failure_CloudPrintAccessTokenInvalidResponse) {
411 SetUpDefaultValues();
412 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
414 PerformURLFetchesWithResults(
415 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
416 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
417 net::HTTP_OK, "invalid request");
419 AssertConsumerTokensAndErrors(0, 1);
422 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Failure_BadOwner) {
423 SetUpDefaultValues();
424 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
426 SetRobotAccountId("WRONG_service_acct@g.com");
428 PerformURLFetchesWithResults(
429 net::HTTP_OK, GetValidTokenResponse("tokeninfo_access_token", 3600),
430 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
431 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
433 AssertConsumerTokensAndErrors(0, 1);
436 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Retry) {
437 SetUpDefaultValues();
438 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
440 PerformURLFetchesWithResults(
441 net::HTTP_INTERNAL_SERVER_ERROR, "",
442 net::HTTP_OK, GetValidTokenInfoResponse("service_acct@g.com"),
443 net::HTTP_OK, GetValidTokenResponse("ignored", 3600));
445 AssertConsumerTokensAndErrors(0, 1);
447 // Retry should succeed.
448 request = StartTokenRequest();
449 PerformURLFetches();
450 AssertConsumerTokensAndErrors(1, 1);
453 TEST_F(DeviceOAuth2TokenServiceTest, DoNotAnnounceTokenWithoutAccountID) {
454 CreateService();
456 testing::StrictMock<MockOAuth2TokenServiceObserver> observer;
457 oauth2_service_->AddObserver(&observer);
459 // Make a token available during enrollment. Verify that the token is not
460 // announced yet.
461 oauth2_service_->SetAndSaveRefreshToken(
462 "test-token", DeviceOAuth2TokenService::StatusCallback());
463 testing::Mock::VerifyAndClearExpectations(&observer);
465 // Also make the robot account ID available. Verify that the token is
466 // announced now.
467 EXPECT_CALL(observer, OnRefreshTokenAvailable("robot@example.com"));
468 SetRobotAccountId("robot@example.com");
469 testing::Mock::VerifyAndClearExpectations(&observer);
471 oauth2_service_->RemoveObserver(&observer);
474 } // namespace chromeos