Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(433)

Side by Side Diff: chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc

Issue 17109006: Device robot refresh token integrity validation. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Extend device_oauth2_token_service_unittest.cc to cover refresh token validation cases. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" 5 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
6 6
7 #include "base/message_loop.h" 7 #include "base/message_loop.h"
8 #include "base/prefs/testing_pref_service.h" 8 #include "base/prefs/testing_pref_service.h"
9 #include "chrome/browser/signin/oauth2_token_service_test_util.h"
10 #include "chrome/common/pref_names.h"
9 #include "chrome/test/base/scoped_testing_local_state.h" 11 #include "chrome/test/base/scoped_testing_local_state.h"
10 #include "chrome/test/base/testing_browser_process.h" 12 #include "chrome/test/base/testing_browser_process.h"
11 #include "chromeos/cryptohome/mock_cryptohome_library.h" 13 #include "chromeos/cryptohome/mock_cryptohome_library.h"
12 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
13 #include "content/public/test/test_browser_thread.h" 15 #include "content/public/test/test_browser_thread.h"
16 #include "net/http/http_status_code.h"
17 #include "net/url_request/test_url_fetcher_factory.h"
18 #include "net/url_request/url_fetcher_delegate.h"
14 #include "net/url_request/url_request_test_util.h" 19 #include "net/url_request/url_request_test_util.h"
15 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
17 22
18 using ::testing::_; 23 using ::testing::_;
19 using ::testing::AnyNumber; 24 using ::testing::AnyNumber;
20 using ::testing::Return; 25 using ::testing::Return;
21 using ::testing::StrEq; 26 using ::testing::StrEq;
22 using ::testing::StrictMock; 27 using ::testing::StrictMock;
23 28
24 namespace chromeos { 29 namespace chromeos {
25 30
31 class TestDeviceOAuth2TokenService : public DeviceOAuth2TokenService {
32 public:
33 explicit TestDeviceOAuth2TokenService(net::URLRequestContextGetter* getter,
34 PrefService* local_state)
35 : DeviceOAuth2TokenService(getter, local_state) {
36 }
37 void SetRobotAccountIdPolicyValue(const std::string& id) {
38 robot_account_id_ = id;
39 }
Mattias Nissler (ping if slow) 2013/06/19 17:53:17 nit: newline
David Roche 2013/06/20 17:49:29 Done.
40 protected:
41 // Skip calling into the policy subsystem and return our test value.
42 virtual std::string GetRobotAccountId() OVERRIDE {
43 return robot_account_id_;
44 }
Mattias Nissler (ping if slow) 2013/06/19 17:53:17 nit: newline
David Roche 2013/06/20 17:49:29 Done.
45 private:
46 std::string robot_account_id_;
47 DISALLOW_COPY_AND_ASSIGN(TestDeviceOAuth2TokenService);
48 };
49
26 class DeviceOAuth2TokenServiceTest : public testing::Test { 50 class DeviceOAuth2TokenServiceTest : public testing::Test {
27 public: 51 public:
28 DeviceOAuth2TokenServiceTest() 52 DeviceOAuth2TokenServiceTest()
29 : ui_thread_(content::BrowserThread::UI, &message_loop_), 53 : ui_thread_(content::BrowserThread::UI, &message_loop_),
30 scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) {} 54 scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
55 request_context_getter_(new net::TestURLRequestContextGetter(
56 message_loop_.message_loop_proxy())),
57 cryptohome_library_(chromeos::CryptohomeLibrary::GetTestImpl()) {}
31 virtual ~DeviceOAuth2TokenServiceTest() {} 58 virtual ~DeviceOAuth2TokenServiceTest() {}
32 59
33 virtual void SetUp() OVERRIDE { 60 virtual void SetUp() OVERRIDE {
61 oauth2_service_ = new TestDeviceOAuth2TokenService(
62 request_context_getter_,
63 scoped_testing_local_state_.Get());
64 oauth2_service_->max_refresh_token_validation_retries_ = 0;
65 oauth2_service_->set_max_authorization_token_fetch_retries_for_testing(0);
34 } 66 }
35 67
36 virtual void TearDown() OVERRIDE { 68 virtual void TearDown() OVERRIDE {
69 delete oauth2_service_;
Mattias Nissler (ping if slow) 2013/06/19 17:53:17 wrap in a scoped_ptr_, or make a plain class membe
David Roche 2013/06/20 17:49:29 Can't use scoped_ptr, since the constructor/destru
70 CryptohomeLibrary::SetForTest(NULL);
37 } 71 }
38 72
73 // Utility method to set a value in Local State for the device refresh token
74 // (it must have a non-empty value or it won't be used).
75 void SetDeviceRefreshTokenInLocalState(const std::string& refresh_token) {
76 chromeos::CryptohomeLibrary::SetForTest(cryptohome_library_.get());
77 scoped_testing_local_state_.Get()->SetManagedPref(
78 prefs::kDeviceRobotAnyApiRefreshToken,
79 Value::CreateStringValue(refresh_token));
80 }
81
82 std::string GetValidTokenInfoResponse(const std::string issued_to) {
83 return "{ \"issued_to\": \"" + issued_to + "\","
84 " \"user_id\": \"1234567890\" }";
85 }
86
87 // See implementation below for comments.
88 void AssertRefreshTokenValidation(
89 net::HttpStatusCode tokeninfo_access_token_fetch_response_code,
90 const std::string& tokeninfo_access_token_fetch_response_string,
91 int tokeninfo_access_token_fetch_successful_tokens,
92 int tokeninfo_access_token_fetch_number_of_errors,
93 net::HttpStatusCode tokeninfo_api_call_response_code,
94 const std::string& tokeninfo_api_call_response_string,
95 int tokeninfo_api_call_successful_tokens,
96 int tokeninfo_api_call_number_of_errors,
97 net::HttpStatusCode cloudprint_access_token_fetch_response_code,
98 const std::string& cloudprint_access_token_fetch_response_string,
99 int cloudprint_access_token_fetch_successful_tokens,
100 int cloudprint_access_token_fetch_number_of_errors);
101
39 protected: 102 protected:
40 base::MessageLoop message_loop_; 103 base::MessageLoop message_loop_;
41 content::TestBrowserThread ui_thread_; 104 content::TestBrowserThread ui_thread_;
42 ScopedTestingLocalState scoped_testing_local_state_; 105 ScopedTestingLocalState scoped_testing_local_state_;
106 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
107 net::TestURLFetcherFactory factory_;
108 TestDeviceOAuth2TokenService* oauth2_service_;
109 TestingOAuth2TokenServiceConsumer consumer_;
110 scoped_ptr<chromeos::CryptohomeLibrary> cryptohome_library_;
111
43 }; 112 };
44 113
114 void DeviceOAuth2TokenServiceTest::AssertRefreshTokenValidation(
115 // Step 1: fetch the access token for the tokeninfo API.
116 net::HttpStatusCode tokeninfo_access_token_fetch_response_code,
117 const std::string& tokeninfo_access_token_fetch_response_string,
118 int tokeninfo_access_token_fetch_successful_tokens,
119 int tokeninfo_access_token_fetch_number_of_errors,
120
121 // Step 2: call the tokeninfo API.
122 net::HttpStatusCode tokeninfo_api_call_response_code,
123 const std::string& tokeninfo_api_call_response_string,
124 int tokeninfo_api_call_successful_tokens,
125 int tokeninfo_api_call_number_of_errors,
126
127 // Step 3: if steps 1 and 2 pass, fetch the access token for the requested
128 // scope (in this case, cloudprint).
129 net::HttpStatusCode cloudprint_access_token_fetch_response_code,
130 const std::string& cloudprint_access_token_fetch_response_string,
131 int cloudprint_access_token_fetch_successful_tokens,
132 int cloudprint_access_token_fetch_number_of_errors) {
133
134 SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
135
136 scoped_ptr<OAuth2TokenService::Request> request(
137 oauth2_service_->StartRequest(std::set<std::string>(), &consumer_));
138 message_loop_.RunUntilIdle();
139
140 EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
141 EXPECT_EQ(0, consumer_.number_of_errors_);
142
143 // First the access token with tokeninfo scope is fetched.
144 net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
145 ASSERT_TRUE(fetcher);
146 fetcher->set_response_code(tokeninfo_access_token_fetch_response_code);
147 fetcher->SetResponseString(tokeninfo_access_token_fetch_response_string);
148 fetcher->delegate()->OnURLFetchComplete(fetcher);
149 EXPECT_EQ(tokeninfo_access_token_fetch_successful_tokens,
150 consumer_.number_of_successful_tokens_);
151 EXPECT_EQ(tokeninfo_access_token_fetch_number_of_errors,
152 consumer_.number_of_errors_);
153
154 // Then the actual tokeninfo call is made.
155 if (consumer_.number_of_successful_tokens_ == 0 &&
156 consumer_.number_of_errors_ == 0) {
157 fetcher = factory_.GetFetcherByID(0);
158 fetcher->set_response_code(tokeninfo_api_call_response_code);
159 fetcher->SetResponseString(tokeninfo_api_call_response_string);
160 fetcher->delegate()->OnURLFetchComplete(fetcher);
161 EXPECT_EQ(tokeninfo_api_call_successful_tokens,
162 consumer_.number_of_successful_tokens_);
163 EXPECT_EQ(tokeninfo_api_call_number_of_errors,
164 consumer_.number_of_errors_);
165 }
166
167 // Finally, the token for the requested scope is requested.
168 if (consumer_.number_of_successful_tokens_ == 0 &&
169 consumer_.number_of_errors_ == 0) {
170 fetcher = factory_.GetFetcherByID(0);
171 fetcher->set_response_code(cloudprint_access_token_fetch_response_code);
172 fetcher->SetResponseString(cloudprint_access_token_fetch_response_string);
173 fetcher->delegate()->OnURLFetchComplete(fetcher);
174 EXPECT_EQ(cloudprint_access_token_fetch_successful_tokens,
175 consumer_.number_of_successful_tokens_);
176 EXPECT_EQ(cloudprint_access_token_fetch_number_of_errors,
177 consumer_.number_of_errors_);
178 }
179 }
180
45 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) { 181 TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) {
46 StrictMock<MockCryptohomeLibrary> mock_cryptohome_library; 182 StrictMock<MockCryptohomeLibrary> mock_cryptohome_library;
47 CryptohomeLibrary::SetForTest(&mock_cryptohome_library); 183 CryptohomeLibrary::SetForTest(&mock_cryptohome_library);
48 184
49 EXPECT_CALL(mock_cryptohome_library, DecryptWithSystemSalt(StrEq(""))) 185 EXPECT_CALL(mock_cryptohome_library, DecryptWithSystemSalt(StrEq("")))
50 .Times(1) 186 .Times(1)
51 .WillOnce(Return("")); 187 .WillOnce(Return(""));
52 EXPECT_CALL(mock_cryptohome_library, 188 EXPECT_CALL(mock_cryptohome_library,
53 EncryptWithSystemSalt(StrEq("test-token"))) 189 EncryptWithSystemSalt(StrEq("test-token")))
54 .Times(1) 190 .Times(1)
55 .WillOnce(Return("encrypted")); 191 .WillOnce(Return("encrypted"));
56 EXPECT_CALL(mock_cryptohome_library, 192 EXPECT_CALL(mock_cryptohome_library,
57 DecryptWithSystemSalt(StrEq("encrypted"))) 193 DecryptWithSystemSalt(StrEq("encrypted")))
58 .Times(1) 194 .Times(1)
59 .WillOnce(Return("test-token")); 195 .WillOnce(Return("test-token"));
60 196
61 DeviceOAuth2TokenService oauth2_service( 197 ASSERT_EQ("", oauth2_service_->GetRefreshToken());
62 new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy()), 198 oauth2_service_->SetAndSaveRefreshToken("test-token");
63 scoped_testing_local_state_.Get()); 199 ASSERT_EQ("test-token", oauth2_service_->GetRefreshToken());
64
65 ASSERT_EQ("", oauth2_service.GetRefreshToken());
66 oauth2_service.SetAndSaveRefreshToken("test-token");
67 ASSERT_EQ("test-token", oauth2_service.GetRefreshToken());
68 200
69 // This call won't invoke decrypt again, since the value is cached. 201 // This call won't invoke decrypt again, since the value is cached.
70 ASSERT_EQ("test-token", oauth2_service.GetRefreshToken()); 202 ASSERT_EQ("test-token", oauth2_service_->GetRefreshToken());
203 }
204
205 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Success) {
206 oauth2_service_->SetRobotAccountIdPolicyValue("service_acct@g.com");
207
208 AssertRefreshTokenValidation(
209
210 // TokenInfo-scoped access token fetch.
211 net::HTTP_OK,
212 GetValidTokenResponse("tokeninfo_access_token", 3600),
213 0, // tokens
214 0, // errors
215
216 // TokenInfo API call.
217 net::HTTP_OK,
218 GetValidTokenInfoResponse("service_acct@g.com"),
219 0, // tokens
220 0, // errors
221
222 // CloudPrint access token fetch.
223 net::HTTP_OK,
224 GetValidTokenResponse("scoped_access_token", 3600),
225 1, // tokens
226 0); // errors
227
228 EXPECT_EQ("scoped_access_token", consumer_.last_token_);
229 }
230
231 TEST_F(DeviceOAuth2TokenServiceTest,
232 RefreshTokenValidation_Failure_TokenInfoAccessTokenHttpError) {
233 oauth2_service_->SetRobotAccountIdPolicyValue("service_acct@g.com");
234
235 AssertRefreshTokenValidation(
236
237 // TokenInfo-scoped access token fetch.
238 net::HTTP_UNAUTHORIZED,
239 "",
240 0, // tokens
241 1, // errors
242
243 // TokenInfo API call skipped (error returned in previous step).
244 net::HTTP_OK, "", 0, 0,
245
246 // CloudPrint access token fetch skipped (error returned in previous step).
247 net::HTTP_OK, "", 0, 0);
248 }
249
250 TEST_F(DeviceOAuth2TokenServiceTest,
251 RefreshTokenValidation_Failure_TokenInfoAccessTokenInvalidResponse) {
252 oauth2_service_->SetRobotAccountIdPolicyValue("service_acct@g.com");
253
254 AssertRefreshTokenValidation(
255
256 // TokenInfo-scoped access token fetch.
257 net::HTTP_OK,
258 "invalid response",
259 0, // tokens
260 1, // errors
261
262 // TokenInfo API call skipped (error returned in previous step).
263 net::HTTP_OK, "", 0, 0,
264
265 // CloudPrint access token fetch skipped (error returned in previous step).
266 net::HTTP_OK, "", 0, 0);
267 }
268
269 TEST_F(DeviceOAuth2TokenServiceTest,
270 RefreshTokenValidation_Failure_TokenInfoApiCallHttpError) {
271 oauth2_service_->SetRobotAccountIdPolicyValue("service_acct@g.com");
272
273 AssertRefreshTokenValidation(
274
275 // TokenInfo-scoped access token fetch.
276 net::HTTP_OK,
277 GetValidTokenResponse("tokeninfo_access_token", 3600),
278 0, // tokens
279 0, // errors
280
281 // TokenInfo API call.
282 net::HTTP_INTERNAL_SERVER_ERROR,
283 "",
284 0, // tokens
285 1, // errors
286
287 // CloudPrint access token fetch skipped (error returned in previous step).
288 net::HTTP_OK, "", 0, 0);
289 }
290
291 TEST_F(DeviceOAuth2TokenServiceTest,
292 RefreshTokenValidation_Failure_TokenInfoApiCallInvalidResponse) {
293 oauth2_service_->SetRobotAccountIdPolicyValue("service_acct@g.com");
294
295 AssertRefreshTokenValidation(
296
297 // TokenInfo-scoped access token fetch.
298 net::HTTP_OK,
299 GetValidTokenResponse("tokeninfo_access_token", 3600),
300 0, // tokens
301 0, // errors
302
303 // TokenInfo API call.
304 net::HTTP_OK,
305 "invalid response",
306 0, // tokens
307 1, // errors
308
309 // CloudPrint access token fetch skipped (error returned in previous step).
310 net::HTTP_OK, "", 0, 0);
311 }
312
313 TEST_F(DeviceOAuth2TokenServiceTest,
314 RefreshTokenValidation_Failure_CloudPrintAccessTokenHttpError) {
315 oauth2_service_->SetRobotAccountIdPolicyValue("service_acct@g.com");
316
317 AssertRefreshTokenValidation(
318
319 // TokenInfo-scoped access token fetch.
320 net::HTTP_OK,
321 GetValidTokenResponse("tokeninfo_access_token", 3600),
322 0, // tokens
323 0, // errors
324
325 // TokenInfo API call.
326 net::HTTP_OK,
327 GetValidTokenInfoResponse("service_acct@g.com"),
328 0, // tokens
329 0, // errors
330
331 // CloudPrint access token fetch.
332 net::HTTP_BAD_REQUEST,
333 "",
334 0, // tokens
335 1); // errors
336 }
337
338 TEST_F(DeviceOAuth2TokenServiceTest,
339 RefreshTokenValidation_Failure_CloudPrintAccessTokenInvalidResponse) {
340 oauth2_service_->SetRobotAccountIdPolicyValue("service_acct@g.com");
341
342 AssertRefreshTokenValidation(
343
344 // TokenInfo-scoped access token fetch.
345 net::HTTP_OK,
346 GetValidTokenResponse("tokeninfo_access_token", 3600),
347 0, // tokens
348 0, // errors
349
350 // TokenInfo API call.
351 net::HTTP_OK,
352 GetValidTokenInfoResponse("service_acct@g.com"),
353 0, // tokens
354 0, // errors
355
356 // CloudPrint access token fetch.
357 net::HTTP_OK,
358 "invalid request",
359 0, // tokens
360 1); // errors
361 }
362
363 TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Failure_BadOwner) {
364 oauth2_service_->SetRobotAccountIdPolicyValue("WRONG_service_acct@g.com");
365
366 AssertRefreshTokenValidation(
367
368 // TokenInfo-scoped access token fetch.
369 net::HTTP_OK,
370 GetValidTokenResponse("tokeninfo_access_token", 3600),
371 0, // tokens
372 0, // errors
373
374 // TokenInfo API call.
375 // The token owner doesn't match the policy value; an error is returned.
376 net::HTTP_OK,
377 GetValidTokenInfoResponse("service_acct@g.com"),
378 0, // tokens
379 1, // errors
380
381 // CloudPrint access token fetch is skipped.
382 net::HTTP_OK, "", 0, 0);
71 } 383 }
72 384
73 } // namespace chromeos 385 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698