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 "base/strings/stringprintf.h"
6 #include "base/threading/platform_thread.h"
7 #include "base/time/time.h"
8 #include "chrome/browser/signin/profile_oauth2_token_service.h"
9 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
10 #include "chrome/browser/sync/profile_sync_service.h"
11 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
12 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
13 #include "chrome/browser/sync/test/integration/sync_test.h"
14 #include "google_apis/gaia/google_service_auth_error.h"
15 #include "net/http/http_status_code.h"
16 #include "net/url_request/url_request_status.h"
18 using bookmarks_helper::AddURL
;
20 const char kShortLivedOAuth2Token
[] =
22 " \"refresh_token\": \"short_lived_refresh_token\","
23 " \"access_token\": \"short_lived_access_token\","
24 " \"expires_in\": 5," // 5 seconds.
25 " \"token_type\": \"Bearer\""
28 const char kValidOAuth2Token
[] = "{"
29 " \"refresh_token\": \"new_refresh_token\","
30 " \"access_token\": \"new_access_token\","
31 " \"expires_in\": 3600," // 1 hour.
32 " \"token_type\": \"Bearer\""
35 const char kInvalidGrantOAuth2Token
[] = "{"
36 " \"error\": \"invalid_grant\""
39 const char kInvalidClientOAuth2Token
[] = "{"
40 " \"error\": \"invalid_client\""
43 const char kEmptyOAuth2Token
[] = "";
45 const char kMalformedOAuth2Token
[] = "{ \"foo\": ";
47 class SyncAuthTest
: public SyncTest
{
49 SyncAuthTest() : SyncTest(SINGLE_CLIENT
) {}
50 virtual ~SyncAuthTest() {}
52 // Helper function that adds a bookmark with index |bookmark_index| and waits
53 // for sync to complete. The return value indicates whether the sync cycle
54 // completed successfully (true) or encountered an auth error (false).
55 bool AddBookmarkAndWaitForSync(int bookmark_index
) {
56 std::wstring title
= base::StringPrintf(L
"Bookmark %d", bookmark_index
);
57 GURL url
= GURL(base::StringPrintf("http://www.foo%d.com", bookmark_index
));
58 EXPECT_TRUE(AddURL(0, title
, url
) != NULL
);
59 return GetClient(0)->AwaitFullSyncCompletion();
62 // Sets the authenticated state of the python sync server to |auth_state| and
63 // sets the canned response that will be returned to the OAuth2TokenService
64 // when it tries to fetch an access token.
65 void SetAuthStateAndTokenResponse(PythonServerAuthState auth_state
,
66 const std::string
& response_data
,
67 net::HttpStatusCode response_code
,
68 net::URLRequestStatus::Status status
) {
69 TriggerAuthState(auth_state
);
71 // If ProfileSyncService observes a transient error like SERVICE_UNAVAILABLE
72 // or CONNECTION_FAILED, this means the OAuth2TokenService has given up
73 // trying to reach Gaia. In practice, OA2TS retries a fixed number of times,
74 // but the count is transparent to PSS.
75 // Override the max retry count in TokenService so that we instantly trigger
76 // the case where ProfileSyncService must pick up where OAuth2TokenService
77 // left off (in terms of retries).
78 ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile(0))->
79 set_max_authorization_token_fetch_retries_for_testing(0);
81 SetOAuth2TokenResponse(response_data
, response_code
, status
);
85 DISALLOW_COPY_AND_ASSIGN(SyncAuthTest
);
88 // Verify that sync works with a valid OAuth2 token.
89 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, Sanity
) {
90 ASSERT_TRUE(SetupSync());
91 SetAuthStateAndTokenResponse(AUTHENTICATED_TRUE
,
94 net::URLRequestStatus::SUCCESS
);
95 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
98 // Verify that ProfileSyncService continues trying to fetch access tokens
99 // when OAuth2TokenService has encountered more than a fixed number of
100 // HTTP_INTERNAL_SERVER_ERROR (500) errors.
101 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, RetryOnInternalServerError500
) {
102 ASSERT_TRUE(SetupSync());
103 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
104 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
106 net::HTTP_INTERNAL_SERVER_ERROR
,
107 net::URLRequestStatus::SUCCESS
);
108 ASSERT_FALSE(AddBookmarkAndWaitForSync(2));
110 GetClient(0)->service()->IsRetryingAccessTokenFetchForTest());
113 // Verify that ProfileSyncService continues trying to fetch access tokens
114 // when OAuth2TokenService has encountered more than a fixed number of
115 // HTTP_FORBIDDEN (403) errors.
116 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, RetryOnHttpForbidden403
) {
117 ASSERT_TRUE(SetupSync());
118 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
119 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
122 net::URLRequestStatus::SUCCESS
);
123 ASSERT_FALSE(AddBookmarkAndWaitForSync(2));
125 GetClient(0)->service()->IsRetryingAccessTokenFetchForTest());
128 // Verify that ProfileSyncService continues trying to fetch access tokens
129 // when OAuth2TokenService has encountered a URLRequestStatus of FAILED.
130 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, RetryOnRequestFailed
) {
131 ASSERT_TRUE(SetupSync());
132 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
133 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
135 net::HTTP_INTERNAL_SERVER_ERROR
,
136 net::URLRequestStatus::FAILED
);
137 ASSERT_FALSE(AddBookmarkAndWaitForSync(2));
139 GetClient(0)->service()->IsRetryingAccessTokenFetchForTest());
142 // Verify that ProfileSyncService continues trying to fetch access tokens
143 // when OAuth2TokenService receives a malformed token.
144 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, RetryOnMalformedToken
) {
145 ASSERT_TRUE(SetupSync());
146 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
147 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
148 kMalformedOAuth2Token
,
150 net::URLRequestStatus::SUCCESS
);
151 ASSERT_FALSE(AddBookmarkAndWaitForSync(2));
153 GetClient(0)->service()->IsRetryingAccessTokenFetchForTest());
156 // Verify that ProfileSyncService ends up with an INVALID_GAIA_CREDENTIALS auth
157 // error when an invalid_grant error is returned by OAuth2TokenService with an
158 // HTTP_BAD_REQUEST (400) response code.
159 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, InvalidGrant
) {
160 ASSERT_TRUE(SetupSync());
161 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
162 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
163 kInvalidGrantOAuth2Token
,
164 net::HTTP_BAD_REQUEST
,
165 net::URLRequestStatus::SUCCESS
);
166 ASSERT_FALSE(AddBookmarkAndWaitForSync(2));
167 ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
,
168 GetClient(0)->service()->GetAuthError().state());
171 // Verify that ProfileSyncService ends up with an SERVICE_ERROR auth error when
172 // an invalid_client error is returned by OAuth2TokenService with an
173 // HTTP_BAD_REQUEST (400) response code.
174 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, InvalidClient
) {
175 ASSERT_TRUE(SetupSync());
176 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
177 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
178 kInvalidClientOAuth2Token
,
179 net::HTTP_BAD_REQUEST
,
180 net::URLRequestStatus::SUCCESS
);
181 ASSERT_FALSE(AddBookmarkAndWaitForSync(2));
182 ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR
,
183 GetClient(0)->service()->GetAuthError().state());
186 // Verify that ProfileSyncService ends up with a REQUEST_CANCELED auth error
187 // when when OAuth2TokenService has encountered a URLRequestStatus of CANCELED.
188 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, RequestCanceled
) {
189 ASSERT_TRUE(SetupSync());
190 ASSERT_TRUE(AddBookmarkAndWaitForSync(1));
191 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
193 net::HTTP_INTERNAL_SERVER_ERROR
,
194 net::URLRequestStatus::CANCELED
);
195 ASSERT_FALSE(AddBookmarkAndWaitForSync(2));
196 ASSERT_EQ(GoogleServiceAuthError::REQUEST_CANCELED
,
197 GetClient(0)->service()->GetAuthError().state());
200 // Verify that ProfileSyncService fails initial sync setup during backend
201 // initialization and ends up with an INVALID_GAIA_CREDENTIALS auth error when
202 // an invalid_grant error is returned by OAuth2TokenService with an
203 // HTTP_BAD_REQUEST (400) response code.
204 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, FailInitialSetupWithPersistentError
) {
205 ASSERT_TRUE(SetupClients());
206 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
207 kInvalidGrantOAuth2Token
,
208 net::HTTP_BAD_REQUEST
,
209 net::URLRequestStatus::SUCCESS
);
210 ASSERT_FALSE(GetClient(0)->SetupSync());
211 ASSERT_FALSE(GetClient(0)->service()->sync_initialized());
212 ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
,
213 GetClient(0)->service()->GetAuthError().state());
216 // Verify that ProfileSyncService fails initial sync setup during backend
217 // initialization, but continues trying to fetch access tokens when
218 // OAuth2TokenService receives an HTTP_INTERNAL_SERVER_ERROR (500) response
220 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, RetryInitialSetupWithTransientError
) {
221 ASSERT_TRUE(SetupClients());
222 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
224 net::HTTP_INTERNAL_SERVER_ERROR
,
225 net::URLRequestStatus::SUCCESS
);
226 ASSERT_FALSE(GetClient(0)->SetupSync());
227 ASSERT_FALSE(GetClient(0)->service()->sync_initialized());
229 GetClient(0)->service()->IsRetryingAccessTokenFetchForTest());
232 // Verify that ProfileSyncService fetches a new token when an old token expires.
233 IN_PROC_BROWSER_TEST_F(SyncAuthTest
, TokenExpiry
) {
234 // Initial sync succeeds with a short lived OAuth2 Token.
235 ASSERT_TRUE(SetupClients());
236 SetAuthStateAndTokenResponse(AUTHENTICATED_TRUE
,
237 kShortLivedOAuth2Token
,
239 net::URLRequestStatus::SUCCESS
);
240 ASSERT_TRUE(GetClient(0)->SetupSync());
241 std::string old_token
= GetClient(0)->service()->GetAccessTokenForTest();
243 // Wait until the token has expired.
244 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
246 // Trigger an auth error on the server so PSS requests OA2TS for a new token
247 // during the next sync cycle.
248 SetAuthStateAndTokenResponse(AUTHENTICATED_FALSE
,
250 net::HTTP_INTERNAL_SERVER_ERROR
,
251 net::URLRequestStatus::SUCCESS
);
252 ASSERT_FALSE(AddBookmarkAndWaitForSync(1));
254 GetClient(0)->service()->IsRetryingAccessTokenFetchForTest());
256 // Trigger an auth success state and set up a new valid OAuth2 token.
257 SetAuthStateAndTokenResponse(AUTHENTICATED_TRUE
,
260 net::URLRequestStatus::SUCCESS
);
262 // Verify that the next sync cycle is successful, and uses the new auth token.
263 ASSERT_TRUE(GetClient(0)->AwaitFullSyncCompletion());
264 std::string new_token
= GetClient(0)->service()->GetAccessTokenForTest();
265 ASSERT_NE(old_token
, new_token
);