supervised_user_refresh_token_fetcher_unittest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright 2014 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/bind.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/strings/stringprintf.h"
8#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
9#include "chrome/browser/supervised_user/supervised_user_refresh_token_fetcher.h"
10#include "chrome/test/base/testing_profile.h"
11#include "content/public/test/test_browser_thread_bundle.h"
12#include "google_apis/gaia/gaia_constants.h"
13#include "google_apis/gaia/gaia_oauth_client.h"
14#include "google_apis/gaia/gaia_urls.h"
15#include "google_apis/gaia/google_service_auth_error.h"
16#include "google_apis/gaia/oauth2_token_service.h"
17#include "net/base/net_errors.h"
18#include "net/base/url_util.h"
19#include "net/http/http_request_headers.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 "testing/gtest/include/gtest/gtest.h"
24
25namespace {
26
27const char kAccountId[] = "account_id";
28const char kDeviceName[] = "Compy";
29const char kSupervisedUserId[] = "abcdef";
30
31const char kAccessToken[] = "accesstoken";
32const char kAuthorizationCode[] = "authorizationcode";
33const char kSupervisedUserToken[] = "supervisedusertoken";
34const char kOAuth2RefreshToken[] = "refreshtoken";
35
36const char kIssueTokenResponseFormat[] =
37    "{"
38    "  \"code\": \"%s\""
39    "}";
40
41const char kGetRefreshTokenResponseFormat[] =
42    "{"
43    "  \"access_token\": \"<ignored>\","
44    "  \"expires_in\": 12345,"
45    "  \"refresh_token\": \"%s\""
46    "}";
47
48// Utility methods --------------------------------------------------
49
50// Slightly hacky way to extract a value from a URL-encoded POST request body.
51bool GetValueForKey(const std::string& encoded_string,
52                    const std::string& key,
53                    std::string* value) {
54  GURL url("http://example.com/?" + encoded_string);
55  return net::GetValueForKeyInQuery(url, key, value);
56}
57
58void SendResponse(net::TestURLFetcher* url_fetcher,
59                  const std::string& response) {
60  url_fetcher->set_status(
61      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
62  url_fetcher->set_response_code(net::HTTP_OK);
63  url_fetcher->SetResponseString(response);
64  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
65}
66
67void SetNetworkError(net::TestURLFetcher* url_fetcher, int error) {
68  url_fetcher->set_status(
69      net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
70  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
71}
72
73void SetHttpError(net::TestURLFetcher* url_fetcher, int error) {
74  url_fetcher->set_status(net::URLRequestStatus());
75  url_fetcher->set_response_code(error);
76  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
77}
78
79void VerifyTokenRequest(
80    std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests) {
81  ASSERT_EQ(1u, requests.size());
82  EXPECT_EQ(1u, requests[0].scopes.size());
83  EXPECT_EQ(1u, requests[0].scopes.count(GaiaConstants::kOAuth1LoginScope));
84}
85
86}  // namespace
87
88class SupervisedUserRefreshTokenFetcherTest : public testing::Test {
89 public:
90  SupervisedUserRefreshTokenFetcherTest();
91  virtual ~SupervisedUserRefreshTokenFetcherTest() {}
92
93 protected:
94  void StartFetching();
95
96  net::TestURLFetcher* GetIssueTokenRequest();
97  net::TestURLFetcher* GetRefreshTokenRequest();
98
99  void MakeOAuth2TokenServiceRequestSucceed();
100  void MakeOAuth2TokenServiceRequestFail(GoogleServiceAuthError::State error);
101  void MakeIssueTokenRequestSucceed();
102  void MakeRefreshTokenFetchSucceed();
103
104  void Reset();
105
106  const GoogleServiceAuthError& error() const { return error_; }
107  const std::string& token() const { return token_; }
108
109 private:
110  void OnTokenFetched(const GoogleServiceAuthError& error,
111                      const std::string& token);
112
113  content::TestBrowserThreadBundle thread_bundle_;
114  TestingProfile profile_;
115  FakeProfileOAuth2TokenService oauth2_token_service_;
116  net::TestURLFetcherFactory url_fetcher_factory_;
117  scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher_;
118
119  GoogleServiceAuthError error_;
120  std::string token_;
121  base::WeakPtrFactory<SupervisedUserRefreshTokenFetcherTest> weak_ptr_factory_;
122};
123
124SupervisedUserRefreshTokenFetcherTest::SupervisedUserRefreshTokenFetcherTest()
125    : token_fetcher_(SupervisedUserRefreshTokenFetcher::Create(
126                         &oauth2_token_service_,
127                         kAccountId,
128                         profile_.GetRequestContext())),
129      error_(GoogleServiceAuthError::NONE),
130      weak_ptr_factory_(this) {}
131
132void SupervisedUserRefreshTokenFetcherTest::StartFetching() {
133  oauth2_token_service_.IssueRefreshToken(kOAuth2RefreshToken);
134  token_fetcher_->Start(
135      kSupervisedUserId,
136      kDeviceName,
137      base::Bind(
138          &SupervisedUserRefreshTokenFetcherTest::OnTokenFetched,
139          weak_ptr_factory_.GetWeakPtr()));
140}
141
142net::TestURLFetcher*
143SupervisedUserRefreshTokenFetcherTest::GetIssueTokenRequest() {
144  net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(1);
145  if (!url_fetcher)
146    return NULL;
147
148  EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_issue_token_url(),
149            url_fetcher->GetOriginalURL());
150  std::string access_token;
151  net::HttpRequestHeaders headers;
152  url_fetcher->GetExtraRequestHeaders(&headers);
153  EXPECT_TRUE(headers.GetHeader("Authorization", &access_token));
154  EXPECT_EQ(std::string("Bearer ") + kAccessToken, access_token);
155  const std::string upload_data = url_fetcher->upload_data();
156  std::string supervised_user_id;
157  EXPECT_TRUE(GetValueForKey(upload_data, "profile_id", &supervised_user_id));
158  EXPECT_EQ(kSupervisedUserId, supervised_user_id);
159  std::string device_name;
160  EXPECT_TRUE(GetValueForKey(upload_data, "device_name", &device_name));
161  EXPECT_EQ(kDeviceName, device_name);
162  return url_fetcher;
163}
164
165net::TestURLFetcher*
166SupervisedUserRefreshTokenFetcherTest::GetRefreshTokenRequest() {
167  net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(
168      gaia::GaiaOAuthClient::kUrlFetcherId);
169  if (!url_fetcher)
170    return NULL;
171
172  EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_token_url(),
173            url_fetcher->GetOriginalURL());
174  std::string auth_code;
175  EXPECT_TRUE(GetValueForKey(url_fetcher->upload_data(), "code", &auth_code));
176  EXPECT_EQ(kAuthorizationCode, auth_code);
177  return url_fetcher;
178}
179
180void
181SupervisedUserRefreshTokenFetcherTest::MakeOAuth2TokenServiceRequestSucceed() {
182  std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
183      oauth2_token_service_.GetPendingRequests();
184  VerifyTokenRequest(requests);
185  base::Time expiration_date = base::Time::Now() +
186                               base::TimeDelta::FromHours(1);
187  oauth2_token_service_.IssueTokenForScope(requests[0].scopes,
188                                           kAccessToken,
189                                           expiration_date);
190}
191
192void
193SupervisedUserRefreshTokenFetcherTest::MakeOAuth2TokenServiceRequestFail(
194    GoogleServiceAuthError::State error) {
195  std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
196      oauth2_token_service_.GetPendingRequests();
197  VerifyTokenRequest(requests);
198  oauth2_token_service_.IssueErrorForScope(requests[0].scopes,
199                                           GoogleServiceAuthError(error));
200}
201
202void SupervisedUserRefreshTokenFetcherTest::MakeIssueTokenRequestSucceed() {
203  SendResponse(GetIssueTokenRequest(),
204               base::StringPrintf(kIssueTokenResponseFormat,
205                                  kAuthorizationCode));
206}
207
208void SupervisedUserRefreshTokenFetcherTest::MakeRefreshTokenFetchSucceed() {
209  SendResponse(GetRefreshTokenRequest(),
210               base::StringPrintf(kGetRefreshTokenResponseFormat,
211                                  kSupervisedUserToken));
212}
213
214void SupervisedUserRefreshTokenFetcherTest::Reset() {
215  token_fetcher_.reset();
216}
217
218void SupervisedUserRefreshTokenFetcherTest::OnTokenFetched(
219    const GoogleServiceAuthError& error,
220    const std::string& token) {
221  error_ = error;
222  token_ = token;
223}
224
225// Tests --------------------------------------------------------
226
227TEST_F(SupervisedUserRefreshTokenFetcherTest, Success) {
228  StartFetching();
229  MakeOAuth2TokenServiceRequestSucceed();
230  MakeIssueTokenRequestSucceed();
231  MakeRefreshTokenFetchSucceed();
232
233  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
234  EXPECT_EQ(kSupervisedUserToken, token());
235}
236
237TEST_F(SupervisedUserRefreshTokenFetcherTest, ExpiredAccessToken) {
238  StartFetching();
239  MakeOAuth2TokenServiceRequestSucceed();
240  SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
241  MakeOAuth2TokenServiceRequestSucceed();
242  MakeIssueTokenRequestSucceed();
243  MakeRefreshTokenFetchSucceed();
244
245  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
246  EXPECT_EQ(kSupervisedUserToken, token());
247}
248
249TEST_F(SupervisedUserRefreshTokenFetcherTest, ExpiredAccessTokenRetry) {
250  // If we get a 401 error for the second time, we should give up instead of
251  // retrying again.
252  StartFetching();
253  MakeOAuth2TokenServiceRequestSucceed();
254  SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
255  MakeOAuth2TokenServiceRequestSucceed();
256  SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
257
258  EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
259  EXPECT_EQ(net::ERR_FAILED, error().network_error());
260  EXPECT_EQ(std::string(), token());
261}
262
263TEST_F(SupervisedUserRefreshTokenFetcherTest, MalformedIssueTokenResponse) {
264  StartFetching();
265  MakeOAuth2TokenServiceRequestSucceed();
266  SendResponse(GetIssueTokenRequest(), "choke");
267
268  EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
269  EXPECT_EQ(net::ERR_INVALID_RESPONSE, error().network_error());
270  EXPECT_EQ(std::string(), token());
271}
272
273TEST_F(SupervisedUserRefreshTokenFetcherTest, FetchAccessTokenFailure) {
274  StartFetching();
275  MakeOAuth2TokenServiceRequestFail(
276      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
277
278  EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, error().state());
279  EXPECT_EQ(std::string(), token());
280}
281
282TEST_F(SupervisedUserRefreshTokenFetcherTest, IssueTokenNetworkError) {
283  StartFetching();
284  MakeOAuth2TokenServiceRequestSucceed();
285  SetNetworkError(GetIssueTokenRequest(), net::ERR_SSL_PROTOCOL_ERROR);
286
287  EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
288  EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, error().network_error());
289  EXPECT_EQ(std::string(), token());
290}
291
292TEST_F(SupervisedUserRefreshTokenFetcherTest, FetchRefreshTokenNetworkError) {
293  StartFetching();
294  MakeOAuth2TokenServiceRequestSucceed();
295  MakeIssueTokenRequestSucceed();
296  SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
297  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
298  SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
299
300  EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
301  EXPECT_EQ(net::ERR_FAILED, error().network_error());
302  EXPECT_EQ(std::string(), token());
303}
304
305TEST_F(SupervisedUserRefreshTokenFetcherTest,
306       FetchRefreshTokenTransientNetworkError) {
307  StartFetching();
308  MakeOAuth2TokenServiceRequestSucceed();
309  MakeIssueTokenRequestSucceed();
310  SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
311
312  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
313  MakeRefreshTokenFetchSucceed();
314
315  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
316  EXPECT_EQ(kSupervisedUserToken, token());
317}
318
319TEST_F(SupervisedUserRefreshTokenFetcherTest, FetchRefreshTokenBadRequest) {
320  StartFetching();
321  MakeOAuth2TokenServiceRequestSucceed();
322  MakeIssueTokenRequestSucceed();
323  SetHttpError(GetRefreshTokenRequest(), net::HTTP_BAD_REQUEST);
324
325  EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
326  EXPECT_EQ(net::ERR_FAILED, error().network_error());
327  EXPECT_EQ(std::string(), token());
328}
329
330TEST_F(SupervisedUserRefreshTokenFetcherTest, CancelWhileFetchingAccessToken) {
331  StartFetching();
332  Reset();
333
334  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
335  EXPECT_EQ(std::string(), token());
336}
337
338TEST_F(SupervisedUserRefreshTokenFetcherTest, CancelWhileCallingIssueToken) {
339  StartFetching();
340  MakeOAuth2TokenServiceRequestSucceed();
341  Reset();
342
343  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
344  EXPECT_EQ(std::string(), token());
345}
346
347TEST_F(SupervisedUserRefreshTokenFetcherTest, CancelWhileFetchingRefreshToken) {
348  StartFetching();
349  MakeOAuth2TokenServiceRequestSucceed();
350  MakeIssueTokenRequestSucceed();
351  Reset();
352
353  EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
354  EXPECT_EQ(std::string(), token());
355}
356