Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / test / integration / sync_auth_test.cc
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.
4
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_factory.h"
9 #include "chrome/browser/sync/profile_sync_service.h"
10 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
11 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
12 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
13 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
14 #include "chrome/browser/sync/test/integration/sync_test.h"
15 #include "components/signin/core/browser/profile_oauth2_token_service.h"
16 #include "google_apis/gaia/google_service_auth_error.h"
17 #include "net/http/http_status_code.h"
18 #include "net/url_request/url_request_status.h"
19
20 using bookmarks_helper::AddURL;
21 using sync_integration_test_util::AwaitCommitActivityCompletion;
22
23 const char kShortLivedOAuth2Token[] =
24     "{"
25     "  \"refresh_token\": \"short_lived_refresh_token\","
26     "  \"access_token\": \"short_lived_access_token\","
27     "  \"expires_in\": 5,"  // 5 seconds.
28     "  \"token_type\": \"Bearer\""
29     "}";
30
31 const char kValidOAuth2Token[] = "{"
32                                  "  \"refresh_token\": \"new_refresh_token\","
33                                  "  \"access_token\": \"new_access_token\","
34                                  "  \"expires_in\": 3600,"  // 1 hour.
35                                  "  \"token_type\": \"Bearer\""
36                                  "}";
37
38 const char kInvalidGrantOAuth2Token[] = "{"
39                                         "  \"error\": \"invalid_grant\""
40                                         "}";
41
42 const char kInvalidClientOAuth2Token[] = "{"
43                                          "  \"error\": \"invalid_client\""
44                                          "}";
45
46 const char kEmptyOAuth2Token[] = "";
47
48 const char kMalformedOAuth2Token[] = "{ \"foo\": ";
49
50 class TestForAuthError : public SingleClientStatusChangeChecker {
51  public:
52   explicit TestForAuthError(ProfileSyncService* service);
53   virtual ~TestForAuthError();
54   virtual bool IsExitConditionSatisfied() OVERRIDE;
55   virtual std::string GetDebugMessage() const OVERRIDE;
56 };
57
58 TestForAuthError::TestForAuthError(ProfileSyncService* service)
59   : SingleClientStatusChangeChecker(service) {}
60
61 TestForAuthError::~TestForAuthError() {}
62
63 bool TestForAuthError::IsExitConditionSatisfied() {
64   return !service()->HasUnsyncedItems() ||
65       (service()->GetSyncTokenStatus().last_get_token_error.state() !=
66        GoogleServiceAuthError::NONE);
67 }
68
69 std::string TestForAuthError::GetDebugMessage() const {
70   return "Waiting for auth error";
71 }
72
73 class SyncAuthTest : public SyncTest {
74  public:
75   SyncAuthTest() : SyncTest(SINGLE_CLIENT), bookmark_index_(0) {}
76   virtual ~SyncAuthTest() {}
77
78   // Helper function that adds a bookmark and waits for either an auth error, or
79   // for the bookmark to be committed.  Returns true if it detects an auth
80   // error, false if the bookmark is committed successfully.
81   bool AttemptToTriggerAuthError() {
82     int bookmark_index = GetNextBookmarkIndex();
83     std::string title = base::StringPrintf("Bookmark %d", bookmark_index);
84     GURL url = GURL(base::StringPrintf("http://www.foo%d.com", bookmark_index));
85     EXPECT_TRUE(AddURL(0, title, url) != NULL);
86
87     // Run until the bookmark is committed or an auth error is encountered.
88     TestForAuthError checker_(GetSyncService((0)));
89     checker_.Wait();
90
91     GoogleServiceAuthError oauth_error =
92         GetSyncService((0))->GetSyncTokenStatus().last_get_token_error;
93
94     return oauth_error.state() != GoogleServiceAuthError::NONE;
95   }
96
97   void DisableTokenFetchRetries() {
98     // If ProfileSyncService observes a transient error like SERVICE_UNAVAILABLE
99     // or CONNECTION_FAILED, this means the OAuth2TokenService has given up
100     // trying to reach Gaia. In practice, OA2TS retries a fixed number of times,
101     // but the count is transparent to PSS.
102     // Override the max retry count in TokenService so that we instantly trigger
103     // the case where ProfileSyncService must pick up where OAuth2TokenService
104     // left off (in terms of retries).
105     ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile(0))->
106         set_max_authorization_token_fetch_retries_for_testing(0);
107   }
108
109
110  private:
111   int GetNextBookmarkIndex() {
112     return bookmark_index_++;
113   }
114
115   int bookmark_index_;
116
117   DISALLOW_COPY_AND_ASSIGN(SyncAuthTest);
118 };
119
120 // Verify that sync works with a valid OAuth2 token.
121 IN_PROC_BROWSER_TEST_F(SyncAuthTest, Sanity) {
122   ASSERT_TRUE(SetupSync());
123   GetFakeServer()->SetAuthenticated();
124   DisableTokenFetchRetries();
125   SetOAuth2TokenResponse(kValidOAuth2Token,
126                          net::HTTP_OK,
127                          net::URLRequestStatus::SUCCESS);
128   ASSERT_FALSE(AttemptToTriggerAuthError());
129 }
130
131 // Verify that ProfileSyncService continues trying to fetch access tokens
132 // when OAuth2TokenService has encountered more than a fixed number of
133 // HTTP_INTERNAL_SERVER_ERROR (500) errors.
134 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnInternalServerError500) {
135   ASSERT_TRUE(SetupSync());
136   ASSERT_FALSE(AttemptToTriggerAuthError());
137   GetFakeServer()->SetUnauthenticated();
138   DisableTokenFetchRetries();
139   SetOAuth2TokenResponse(kValidOAuth2Token,
140                          net::HTTP_INTERNAL_SERVER_ERROR,
141                          net::URLRequestStatus::SUCCESS);
142   ASSERT_TRUE(AttemptToTriggerAuthError());
143   ASSERT_TRUE(
144       GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
145 }
146
147 // Verify that ProfileSyncService continues trying to fetch access tokens
148 // when OAuth2TokenService has encountered more than a fixed number of
149 // HTTP_FORBIDDEN (403) errors.
150 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnHttpForbidden403) {
151   ASSERT_TRUE(SetupSync());
152   ASSERT_FALSE(AttemptToTriggerAuthError());
153   GetFakeServer()->SetUnauthenticated();
154   DisableTokenFetchRetries();
155   SetOAuth2TokenResponse(kEmptyOAuth2Token,
156                          net::HTTP_FORBIDDEN,
157                          net::URLRequestStatus::SUCCESS);
158   ASSERT_TRUE(AttemptToTriggerAuthError());
159   ASSERT_TRUE(
160       GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
161 }
162
163 // Verify that ProfileSyncService continues trying to fetch access tokens
164 // when OAuth2TokenService has encountered a URLRequestStatus of FAILED.
165 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnRequestFailed) {
166   ASSERT_TRUE(SetupSync());
167   ASSERT_FALSE(AttemptToTriggerAuthError());
168   GetFakeServer()->SetUnauthenticated();
169   DisableTokenFetchRetries();
170   SetOAuth2TokenResponse(kEmptyOAuth2Token,
171                          net::HTTP_INTERNAL_SERVER_ERROR,
172                          net::URLRequestStatus::FAILED);
173   ASSERT_TRUE(AttemptToTriggerAuthError());
174   ASSERT_TRUE(
175       GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
176 }
177
178 // Verify that ProfileSyncService continues trying to fetch access tokens
179 // when OAuth2TokenService receives a malformed token.
180 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnMalformedToken) {
181   ASSERT_TRUE(SetupSync());
182   ASSERT_FALSE(AttemptToTriggerAuthError());
183   GetFakeServer()->SetUnauthenticated();
184   DisableTokenFetchRetries();
185   SetOAuth2TokenResponse(kMalformedOAuth2Token,
186                          net::HTTP_OK,
187                          net::URLRequestStatus::SUCCESS);
188   ASSERT_TRUE(AttemptToTriggerAuthError());
189   ASSERT_TRUE(
190       GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
191 }
192
193 // Verify that ProfileSyncService ends up with an INVALID_GAIA_CREDENTIALS auth
194 // error when an invalid_grant error is returned by OAuth2TokenService with an
195 // HTTP_BAD_REQUEST (400) response code.
196 IN_PROC_BROWSER_TEST_F(SyncAuthTest, InvalidGrant) {
197   ASSERT_TRUE(SetupSync());
198   ASSERT_FALSE(AttemptToTriggerAuthError());
199   GetFakeServer()->SetUnauthenticated();
200   DisableTokenFetchRetries();
201   SetOAuth2TokenResponse(kInvalidGrantOAuth2Token,
202                          net::HTTP_BAD_REQUEST,
203                          net::URLRequestStatus::SUCCESS);
204   ASSERT_TRUE(AttemptToTriggerAuthError());
205   ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
206             GetSyncService((0))->GetAuthError().state());
207 }
208
209 // Verify that ProfileSyncService retries after SERVICE_ERROR auth error when
210 // an invalid_client error is returned by OAuth2TokenService with an
211 // HTTP_BAD_REQUEST (400) response code.
212 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryInvalidClient) {
213   ASSERT_TRUE(SetupSync());
214   ASSERT_FALSE(AttemptToTriggerAuthError());
215   GetFakeServer()->SetUnauthenticated();
216   DisableTokenFetchRetries();
217   SetOAuth2TokenResponse(kInvalidClientOAuth2Token,
218                          net::HTTP_BAD_REQUEST,
219                          net::URLRequestStatus::SUCCESS);
220   ASSERT_TRUE(AttemptToTriggerAuthError());
221   ASSERT_TRUE(GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
222 }
223
224 // Verify that ProfileSyncService retries after REQUEST_CANCELED auth error
225 // when OAuth2TokenService has encountered a URLRequestStatus of CANCELED.
226 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryRequestCanceled) {
227   ASSERT_TRUE(SetupSync());
228   ASSERT_FALSE(AttemptToTriggerAuthError());
229   GetFakeServer()->SetUnauthenticated();
230   DisableTokenFetchRetries();
231   SetOAuth2TokenResponse(kEmptyOAuth2Token,
232                          net::HTTP_INTERNAL_SERVER_ERROR,
233                          net::URLRequestStatus::CANCELED);
234   ASSERT_TRUE(AttemptToTriggerAuthError());
235   ASSERT_TRUE(GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
236 }
237
238 // Verify that ProfileSyncService fails initial sync setup during backend
239 // initialization and ends up with an INVALID_GAIA_CREDENTIALS auth error when
240 // an invalid_grant error is returned by OAuth2TokenService with an
241 // HTTP_BAD_REQUEST (400) response code.
242 IN_PROC_BROWSER_TEST_F(SyncAuthTest, FailInitialSetupWithPersistentError) {
243   ASSERT_TRUE(SetupClients());
244   GetFakeServer()->SetUnauthenticated();
245   DisableTokenFetchRetries();
246   SetOAuth2TokenResponse(kInvalidGrantOAuth2Token,
247                          net::HTTP_BAD_REQUEST,
248                          net::URLRequestStatus::SUCCESS);
249   ASSERT_FALSE(GetClient(0)->SetupSync());
250   ASSERT_FALSE(GetSyncService((0))->sync_initialized());
251   ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
252             GetSyncService((0))->GetAuthError().state());
253 }
254
255 // Verify that ProfileSyncService fails initial sync setup during backend
256 // initialization, but continues trying to fetch access tokens when
257 // OAuth2TokenService receives an HTTP_INTERNAL_SERVER_ERROR (500) response
258 // code.
259 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryInitialSetupWithTransientError) {
260   ASSERT_TRUE(SetupClients());
261   GetFakeServer()->SetUnauthenticated();
262   DisableTokenFetchRetries();
263   SetOAuth2TokenResponse(kEmptyOAuth2Token,
264                          net::HTTP_INTERNAL_SERVER_ERROR,
265                          net::URLRequestStatus::SUCCESS);
266   ASSERT_FALSE(GetClient(0)->SetupSync());
267   ASSERT_FALSE(GetSyncService((0))->sync_initialized());
268   ASSERT_TRUE(
269       GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
270 }
271
272 // Verify that ProfileSyncService fetches a new token when an old token expires.
273 IN_PROC_BROWSER_TEST_F(SyncAuthTest, TokenExpiry) {
274   // Initial sync succeeds with a short lived OAuth2 Token.
275   ASSERT_TRUE(SetupClients());
276   GetFakeServer()->SetAuthenticated();
277   DisableTokenFetchRetries();
278   SetOAuth2TokenResponse(kShortLivedOAuth2Token,
279                          net::HTTP_OK,
280                          net::URLRequestStatus::SUCCESS);
281   ASSERT_TRUE(GetClient(0)->SetupSync());
282   std::string old_token = GetSyncService((0))->GetAccessTokenForTest();
283
284   // Wait until the token has expired.
285   base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
286
287   // Trigger an auth error on the server so PSS requests OA2TS for a new token
288   // during the next sync cycle.
289   GetFakeServer()->SetUnauthenticated();
290   SetOAuth2TokenResponse(kEmptyOAuth2Token,
291                          net::HTTP_INTERNAL_SERVER_ERROR,
292                          net::URLRequestStatus::SUCCESS);
293   ASSERT_TRUE(AttemptToTriggerAuthError());
294   ASSERT_TRUE(
295       GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
296
297   // Trigger an auth success state and set up a new valid OAuth2 token.
298   GetFakeServer()->SetAuthenticated();
299   SetOAuth2TokenResponse(kValidOAuth2Token,
300                          net::HTTP_OK,
301                          net::URLRequestStatus::SUCCESS);
302
303   // Verify that the next sync cycle is successful, and uses the new auth token.
304   ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
305   std::string new_token = GetSyncService((0))->GetAccessTokenForTest();
306   ASSERT_NE(old_token, new_token);
307 }