Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / settings / device_oauth2_token_service_unittest.cc
blob8de6395ec84946379e86f14eff13d89855a5f0d4
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 "chrome/browser/chromeos/settings/token_encryptor.h"
11 #include "chrome/common/pref_names.h"
12 #include "chrome/test/base/scoped_testing_local_state.h"
13 #include "chrome/test/base/testing_browser_process.h"
14 #include "chromeos/cryptohome/system_salt_getter.h"
15 #include "chromeos/dbus/fake_dbus_thread_manager.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/test/test_browser_thread.h"
18 #include "google_apis/gaia/gaia_oauth_client.h"
19 #include "google_apis/gaia/oauth2_token_service_test_util.h"
20 #include "net/http/http_status_code.h"
21 #include "net/url_request/test_url_fetcher_factory.h"
22 #include "net/url_request/url_fetcher_delegate.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using ::testing::_;
28 using ::testing::AnyNumber;
29 using ::testing::Return;
30 using ::testing::ReturnArg;
31 using ::testing::StrEq;
32 using ::testing::StrictMock;
34 namespace chromeos {
36 static const int kOAuthTokenServiceUrlFetcherId = 0;
37 static const int kValidatorUrlFetcherId = gaia::GaiaOAuthClient::kUrlFetcherId;
39 class TestDeviceOAuth2TokenService : public DeviceOAuth2TokenService {
40 public:
41 explicit TestDeviceOAuth2TokenService(net::URLRequestContextGetter* getter,
42 PrefService* local_state,
43 TokenEncryptor* token_encryptor)
44 : DeviceOAuth2TokenService(getter,
45 local_state,
46 token_encryptor) {
48 void SetRobotAccountIdPolicyValue(const std::string& id) {
49 robot_account_id_ = id;
52 // Skip calling into the policy subsystem and return our test value.
53 virtual std::string GetRobotAccountId() OVERRIDE {
54 return robot_account_id_;
57 private:
58 std::string robot_account_id_;
59 DISALLOW_COPY_AND_ASSIGN(TestDeviceOAuth2TokenService);
62 class MockTokenEncryptor : public TokenEncryptor {
63 public:
64 MOCK_METHOD1(EncryptWithSystemSalt, std::string(const std::string&));
65 MOCK_METHOD1(DecryptWithSystemSalt, std::string(const std::string&));
68 class DeviceOAuth2TokenServiceTest : public testing::Test {
69 public:
70 DeviceOAuth2TokenServiceTest()
71 : ui_thread_(content::BrowserThread::UI, &message_loop_),
72 scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
73 request_context_getter_(new net::TestURLRequestContextGetter(
74 message_loop_.message_loop_proxy())),
75 mock_token_encryptor_(new StrictMock<MockTokenEncryptor>),
76 oauth2_service_(request_context_getter_.get(),
77 scoped_testing_local_state_.Get(),
78 mock_token_encryptor_) {
79 oauth2_service_.max_refresh_token_validation_retries_ = 0;
80 oauth2_service_.set_max_authorization_token_fetch_retries_for_testing(0);
82 virtual ~DeviceOAuth2TokenServiceTest() {}
84 // Most tests just want a noop crypto impl with a dummy refresh token value in
85 // Local State (if the value is an empty string, it will be ignored).
86 void SetUpDefaultValues() {
87 SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
88 oauth2_service_.SetRobotAccountIdPolicyValue("service_acct@g.com");
89 AssertConsumerTokensAndErrors(0, 0);
91 // Returns the input token as-is.
92 EXPECT_CALL(*mock_token_encryptor_, DecryptWithSystemSalt(_))
93 .WillRepeatedly(ReturnArg<0>());
96 scoped_ptr<OAuth2TokenService::Request> StartTokenRequest() {
97 return oauth2_service_.StartRequest(oauth2_service_.GetRobotAccountId(),
98 std::set<std::string>(),
99 &consumer_);
102 virtual void SetUp() OVERRIDE {
103 // TODO(xiyuan): Remove this when cleaning up the system salt load temp fix.
104 scoped_ptr<FakeDBusThreadManager> fake_dbus_thread_manager(
105 new FakeDBusThreadManager);
106 DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager.release());
107 SystemSaltGetter::Initialize();
110 virtual void TearDown() OVERRIDE {
111 SystemSaltGetter::Shutdown();
112 DBusThreadManager::Shutdown();
113 base::RunLoop().RunUntilIdle();
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()->SetManagedPref(
120 prefs::kDeviceRobotAnyApiRefreshToken,
121 base::Value::CreateStringValue(refresh_token));
124 std::string GetValidTokenInfoResponse(const std::string email) {
125 return "{ \"email\": \"" + email + "\","
126 " \"user_id\": \"1234567890\" }";
129 // A utility method to return fake URL results, for testing the refresh token
130 // validation logic. For a successful validation attempt, this method will be
131 // called three times for the steps listed below (steps 1 and 2 happen in
132 // parallel).
134 // Step 1a: fetch the access token for the tokeninfo API.
135 // Step 1b: call the tokeninfo API.
136 // Step 2: Fetch the access token for the requested scope
137 // (in this case, cloudprint).
138 void ReturnOAuthUrlFetchResults(int fetcher_id,
139 net::HttpStatusCode response_code,
140 const std::string& response_string);
142 void AssertConsumerTokensAndErrors(int num_tokens, int num_errors);
144 protected:
145 base::MessageLoop message_loop_;
146 content::TestBrowserThread ui_thread_;
147 ScopedTestingLocalState scoped_testing_local_state_;
148 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
149 net::TestURLFetcherFactory factory_;
150 // Owned by oauth2_service_.
151 StrictMock<MockTokenEncryptor>* mock_token_encryptor_;
152 TestDeviceOAuth2TokenService oauth2_service_;
153 TestingOAuth2TokenServiceConsumer consumer_;
156 void DeviceOAuth2TokenServiceTest::ReturnOAuthUrlFetchResults(
157 int fetcher_id,
158 net::HttpStatusCode response_code,
159 const std::string& response_string) {
161 net::TestURLFetcher* fetcher = factory_.GetFetcherByID(fetcher_id);
162 ASSERT_TRUE(fetcher);
163 fetcher->set_response_code(response_code);
164 fetcher->SetResponseString(response_string);
165 fetcher->delegate()->OnURLFetchComplete(fetcher);
168 void DeviceOAuth2TokenServiceTest::AssertConsumerTokensAndErrors(
169 int num_tokens,
170 int num_errors) {
171 ASSERT_EQ(num_tokens, consumer_.number_of_successful_tokens_);
172 ASSERT_EQ(num_errors, consumer_.number_of_errors_);
175 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) {
176 EXPECT_CALL(*mock_token_encryptor_, DecryptWithSystemSalt(StrEq("")))
177 .Times(1)
178 .WillOnce(Return(""));
179 EXPECT_CALL(*mock_token_encryptor_,
180 EncryptWithSystemSalt(StrEq("test-token")))
181 .Times(1)
182 .WillOnce(Return("encrypted"));
183 EXPECT_CALL(*mock_token_encryptor_,
184 DecryptWithSystemSalt(StrEq("encrypted")))
185 .Times(1)
186 .WillOnce(Return("test-token"));
188 ASSERT_EQ("", oauth2_service_.GetRefreshToken(
189 oauth2_service_.GetRobotAccountId()));
190 oauth2_service_.SetAndSaveRefreshToken("test-token");
191 ASSERT_EQ("test-token", oauth2_service_.GetRefreshToken(
192 oauth2_service_.GetRobotAccountId()));
194 // This call won't invoke decrypt again, since the value is cached.
195 ASSERT_EQ("test-token", oauth2_service_.GetRefreshToken(
196 oauth2_service_.GetRobotAccountId()));
199 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Success) {
200 SetUpDefaultValues();
201 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
203 ReturnOAuthUrlFetchResults(
204 kValidatorUrlFetcherId,
205 net::HTTP_OK,
206 GetValidTokenResponse("tokeninfo_access_token", 3600));
208 ReturnOAuthUrlFetchResults(
209 kValidatorUrlFetcherId,
210 net::HTTP_OK,
211 GetValidTokenInfoResponse("service_acct@g.com"));
213 ReturnOAuthUrlFetchResults(
214 kOAuthTokenServiceUrlFetcherId,
215 net::HTTP_OK,
216 GetValidTokenResponse("scoped_access_token", 3600));
218 AssertConsumerTokensAndErrors(1, 0);
220 EXPECT_EQ("scoped_access_token", consumer_.last_token_);
223 TEST_F(DeviceOAuth2TokenServiceTest,
224 RefreshTokenValidation_Failure_TokenInfoAccessTokenHttpError) {
225 SetUpDefaultValues();
226 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
228 ReturnOAuthUrlFetchResults(
229 kValidatorUrlFetcherId,
230 net::HTTP_UNAUTHORIZED,
231 "");
233 // TokenInfo API call skipped (error returned in previous step).
235 // CloudPrint access token fetch is successful, but consumer still given error
236 // due to bad refresh token.
237 ReturnOAuthUrlFetchResults(
238 kOAuthTokenServiceUrlFetcherId,
239 net::HTTP_OK,
240 GetValidTokenResponse("ignored_scoped_access_token", 3600));
242 AssertConsumerTokensAndErrors(0, 1);
245 TEST_F(DeviceOAuth2TokenServiceTest,
246 RefreshTokenValidation_Failure_TokenInfoAccessTokenInvalidResponse) {
247 SetUpDefaultValues();
248 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
250 ReturnOAuthUrlFetchResults(
251 kValidatorUrlFetcherId,
252 net::HTTP_OK,
253 "invalid response");
255 // TokenInfo API call skipped (error returned in previous step).
257 ReturnOAuthUrlFetchResults(
258 kOAuthTokenServiceUrlFetcherId,
259 net::HTTP_OK,
260 GetValidTokenResponse("ignored_scoped_access_token", 3600));
262 // CloudPrint access token fetch is successful, but consumer still given error
263 // due to bad refresh token.
264 AssertConsumerTokensAndErrors(0, 1);
267 TEST_F(DeviceOAuth2TokenServiceTest,
268 RefreshTokenValidation_Failure_TokenInfoApiCallHttpError) {
269 SetUpDefaultValues();
270 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
272 ReturnOAuthUrlFetchResults(
273 kValidatorUrlFetcherId,
274 net::HTTP_OK,
275 GetValidTokenResponse("tokeninfo_access_token", 3600));
277 ReturnOAuthUrlFetchResults(
278 kValidatorUrlFetcherId,
279 net::HTTP_INTERNAL_SERVER_ERROR,
280 "");
282 ReturnOAuthUrlFetchResults(
283 kOAuthTokenServiceUrlFetcherId,
284 net::HTTP_OK,
285 GetValidTokenResponse("ignored_scoped_access_token", 3600));
287 // CloudPrint access token fetch is successful, but consumer still given error
288 // due to bad refresh token.
289 AssertConsumerTokensAndErrors(0, 1);
292 TEST_F(DeviceOAuth2TokenServiceTest,
293 RefreshTokenValidation_Failure_TokenInfoApiCallInvalidResponse) {
294 SetUpDefaultValues();
295 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
297 ReturnOAuthUrlFetchResults(
298 kValidatorUrlFetcherId,
299 net::HTTP_OK,
300 GetValidTokenResponse("tokeninfo_access_token", 3600));
302 ReturnOAuthUrlFetchResults(
303 kValidatorUrlFetcherId,
304 net::HTTP_OK,
305 "invalid response");
307 ReturnOAuthUrlFetchResults(
308 kOAuthTokenServiceUrlFetcherId,
309 net::HTTP_OK,
310 GetValidTokenResponse("ignored_scoped_access_token", 3600));
312 // CloudPrint access token fetch is successful, but consumer still given error
313 // due to bad refresh token.
314 AssertConsumerTokensAndErrors(0, 1);
317 TEST_F(DeviceOAuth2TokenServiceTest,
318 RefreshTokenValidation_Failure_CloudPrintAccessTokenHttpError) {
319 SetUpDefaultValues();
320 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
322 ReturnOAuthUrlFetchResults(
323 kValidatorUrlFetcherId,
324 net::HTTP_OK,
325 GetValidTokenResponse("tokeninfo_access_token", 3600));
327 ReturnOAuthUrlFetchResults(
328 kValidatorUrlFetcherId,
329 net::HTTP_OK,
330 GetValidTokenInfoResponse("service_acct@g.com"));
332 ReturnOAuthUrlFetchResults(
333 kOAuthTokenServiceUrlFetcherId,
334 net::HTTP_BAD_REQUEST,
335 "");
337 AssertConsumerTokensAndErrors(0, 1);
340 TEST_F(DeviceOAuth2TokenServiceTest,
341 RefreshTokenValidation_Failure_CloudPrintAccessTokenInvalidResponse) {
342 SetUpDefaultValues();
343 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
345 ReturnOAuthUrlFetchResults(
346 kValidatorUrlFetcherId,
347 net::HTTP_OK,
348 GetValidTokenResponse("tokeninfo_access_token", 3600));
350 ReturnOAuthUrlFetchResults(
351 kValidatorUrlFetcherId,
352 net::HTTP_OK,
353 GetValidTokenInfoResponse("service_acct@g.com"));
355 ReturnOAuthUrlFetchResults(
356 kOAuthTokenServiceUrlFetcherId,
357 net::HTTP_OK,
358 "invalid request");
360 AssertConsumerTokensAndErrors(0, 1);
363 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Failure_BadOwner) {
364 SetUpDefaultValues();
365 scoped_ptr<OAuth2TokenService::Request> request = StartTokenRequest();
367 oauth2_service_.SetRobotAccountIdPolicyValue("WRONG_service_acct@g.com");
369 // The requested token comes in before any of the validation calls complete,
370 // but the consumer still gets an error, since the results don't get returned
371 // until validation is over.
372 ReturnOAuthUrlFetchResults(
373 kOAuthTokenServiceUrlFetcherId,
374 net::HTTP_OK,
375 GetValidTokenResponse("ignored_scoped_access_token", 3600));
376 AssertConsumerTokensAndErrors(0, 0);
378 ReturnOAuthUrlFetchResults(
379 kValidatorUrlFetcherId,
380 net::HTTP_OK,
381 GetValidTokenResponse("tokeninfo_access_token", 3600));
382 AssertConsumerTokensAndErrors(0, 0);
384 ReturnOAuthUrlFetchResults(
385 kValidatorUrlFetcherId,
386 net::HTTP_OK,
387 GetValidTokenInfoResponse("service_acct@g.com"));
389 // All fetches were successful, but consumer still given error since
390 // the token owner doesn't match the policy value.
391 AssertConsumerTokensAndErrors(0, 1);
394 } // namespace chromeos