blob: 75608a6ae3260804f662a93ae64b9bcc266f3c55 [file] [log] [blame]
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001// 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/bind.h"
6#include "base/memory/scoped_ptr.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01007#include "base/strings/stringprintf.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01008#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
9#include "chrome/browser/signin/oauth2_token_service.h"
10#include "chrome/test/base/testing_profile.h"
Ben Murdocha3f7b4e2013-07-24 10:36:34 +010011#include "content/public/test/test_browser_thread_bundle.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010012#include "google_apis/gaia/gaia_oauth_client.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010013#include "google_apis/gaia/gaia_urls.h"
14#include "google_apis/gaia/google_service_auth_error.h"
15#include "net/base/net_errors.h"
16#include "net/base/url_util.h"
17#include "net/http/http_request_headers.h"
18#include "net/http/http_status_code.h"
19#include "net/url_request/test_url_fetcher_factory.h"
20#include "net/url_request/url_fetcher_delegate.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace {
24
25const char kManagedUserId[] = "abcdef";
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010026const char kDeviceName[] = "Compy";
27
28const char kAccessToken[] = "accesstoken";
29const char kAuthorizationCode[] = "authorizationcode";
30const char kManagedUserToken[] = "managedusertoken";
31
32const char kIssueTokenResponseFormat[] =
33 "{"
34 " \"code\": \"%s\""
35 "}";
36
37const char kGetRefreshTokenResponseFormat[] =
38 "{"
39 " \"access_token\": \"<ignored>\","
40 " \"expires_in\": 12345,"
41 " \"refresh_token\": \"%s\""
42 "}";
43
44// MockOAuth2TokenService ---------------------------------------------
45
46class MockOAuth2TokenService : public OAuth2TokenService {
47 public:
48 class Request : public OAuth2TokenService::Request {
49 public:
50 Request(const OAuth2TokenService::ScopeSet& scopes,
51 OAuth2TokenService::Consumer* consumer,
52 MockOAuth2TokenService* owner);
53 virtual ~Request();
54
55 void Succeed();
56 void Fail(GoogleServiceAuthError::State error);
57
58 const OAuth2TokenService::ScopeSet& scopes() const { return scopes_; }
59
60 private:
61 OAuth2TokenService::ScopeSet scopes_;
62
63 OAuth2TokenService::Consumer* consumer_;
64
65 MockOAuth2TokenService* owner_;
66 };
67
68 MockOAuth2TokenService();
69 virtual ~MockOAuth2TokenService();
70
71 Request* request() const { return request_; }
72
73 void ClearRequest(Request* request);
74
75 private:
76 // OAuth2TokenService overrides:
77 virtual scoped_ptr<OAuth2TokenService::Request> StartRequest(
78 const OAuth2TokenService::ScopeSet& scopes,
79 OAuth2TokenService::Consumer* consumer) OVERRIDE;
80 virtual std::string GetRefreshToken() OVERRIDE;
Ben Murdochca12bfa2013-07-23 11:17:05 +010081 virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE {
82 return NULL;
83 }
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010084
85 Request* request_;
86
87 DISALLOW_COPY_AND_ASSIGN(MockOAuth2TokenService);
88};
89
90MockOAuth2TokenService::Request::Request(
91 const OAuth2TokenService::ScopeSet& scopes,
92 OAuth2TokenService::Consumer* consumer,
93 MockOAuth2TokenService* owner)
94 : scopes_(scopes),
95 consumer_(consumer),
96 owner_(owner) {}
97
98MockOAuth2TokenService::Request::~Request() {
99 owner_->ClearRequest(this);
100}
101
102void MockOAuth2TokenService::Request::Succeed() {
103 base::Time expiration_date = base::Time::Now() +
104 base::TimeDelta::FromHours(1);
105 consumer_->OnGetTokenSuccess(this, kAccessToken, expiration_date);
106}
107
108void MockOAuth2TokenService::Request::Fail(
109 GoogleServiceAuthError::State error) {
110 consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(error));
111}
112
Ben Murdochca12bfa2013-07-23 11:17:05 +0100113MockOAuth2TokenService::MockOAuth2TokenService() : request_(NULL) {}
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100114
115MockOAuth2TokenService::~MockOAuth2TokenService() {
116 EXPECT_FALSE(request_);
117}
118
119void MockOAuth2TokenService::ClearRequest(
120 MockOAuth2TokenService::Request* request) {
121 if (request_ == request)
122 request_ = NULL;
123}
124
125scoped_ptr<OAuth2TokenService::Request> MockOAuth2TokenService::StartRequest(
126 const OAuth2TokenService::ScopeSet& scopes,
127 OAuth2TokenService::Consumer* consumer) {
128 scoped_ptr<Request> request(new Request(scopes, consumer, this));
129 request_ = request.get();
130 return request.PassAs<OAuth2TokenService::Request>();
131}
132
133std::string MockOAuth2TokenService::GetRefreshToken() {
134 NOTREACHED();
135 return std::string();
136}
137
138// Utility methods --------------------------------------------------
139
140// Slightly hacky way to extract a value from a URL-encoded POST request body.
141bool GetValueForKey(const std::string& encoded_string,
142 const std::string& key,
143 std::string* value) {
144 GURL url("http://example.com/?" + encoded_string);
145 return net::GetValueForKeyInQuery(url, key, value);
146}
147
148void SendResponse(net::TestURLFetcher* url_fetcher,
149 const std::string& response) {
150 url_fetcher->set_status(
151 net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
152 url_fetcher->set_response_code(net::HTTP_OK);
153 url_fetcher->SetResponseString(response);
154 url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
155}
156
157void SetNetworkError(net::TestURLFetcher* url_fetcher, int error) {
158 url_fetcher->set_status(
159 net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
160 url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
161}
162
163void SetHttpError(net::TestURLFetcher* url_fetcher, int error) {
164 url_fetcher->set_status(net::URLRequestStatus());
165 url_fetcher->set_response_code(error);
166 url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
167}
168
169} // namespace
170
171class ManagedUserRefreshTokenFetcherTest : public testing::Test {
172 public:
173 ManagedUserRefreshTokenFetcherTest();
174 virtual ~ManagedUserRefreshTokenFetcherTest() {}
175
176 protected:
177 void StartFetching();
178
179 MockOAuth2TokenService::Request* GetOAuth2TokenServiceRequest();
180 net::TestURLFetcher* GetIssueTokenRequest();
181 net::TestURLFetcher* GetRefreshTokenRequest();
182
183 void MakeIssueTokenRequestSucceed();
184 void MakeRefreshTokenFetchSucceed();
185
186 void Reset();
187
188 const GoogleServiceAuthError& error() const { return error_; }
189 const std::string& token() const { return token_; }
190
191 private:
192 void OnTokenFetched(const GoogleServiceAuthError& error,
193 const std::string& token);
194
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100195 content::TestBrowserThreadBundle thread_bundle_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100196 TestingProfile profile_;
197 MockOAuth2TokenService oauth2_token_service_;
198 net::TestURLFetcherFactory url_fetcher_factory_;
199 scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher_;
200
201 GoogleServiceAuthError error_;
202 std::string token_;
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100203 base::WeakPtrFactory<ManagedUserRefreshTokenFetcherTest> weak_ptr_factory_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100204};
205
206ManagedUserRefreshTokenFetcherTest::ManagedUserRefreshTokenFetcherTest()
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100207 : token_fetcher_(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100208 ManagedUserRefreshTokenFetcher::Create(&oauth2_token_service_,
209 profile_.GetRequestContext())),
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100210 error_(GoogleServiceAuthError::NONE),
211 weak_ptr_factory_(this) {}
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100212
213void ManagedUserRefreshTokenFetcherTest::StartFetching() {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100214 token_fetcher_->Start(kManagedUserId, kDeviceName,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100215 base::Bind(
216 &ManagedUserRefreshTokenFetcherTest::OnTokenFetched,
217 weak_ptr_factory_.GetWeakPtr()));
218}
219
220MockOAuth2TokenService::Request*
221ManagedUserRefreshTokenFetcherTest::GetOAuth2TokenServiceRequest() {
222 MockOAuth2TokenService::Request* request = oauth2_token_service_.request();
223
224 OAuth2TokenService::ScopeSet scopes = request->scopes();
225 EXPECT_EQ(1u, scopes.size());
226 EXPECT_EQ(1u, scopes.count(GaiaUrls::GetInstance()->oauth1_login_scope()));
227 return request;
228}
229
230net::TestURLFetcher*
231ManagedUserRefreshTokenFetcherTest::GetIssueTokenRequest() {
232 net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(1);
233 if (!url_fetcher)
234 return NULL;
235
236 EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_issue_token_url(),
237 url_fetcher->GetOriginalURL().spec());
238 std::string access_token;
239 net::HttpRequestHeaders headers;
240 url_fetcher->GetExtraRequestHeaders(&headers);
241 EXPECT_TRUE(headers.GetHeader("Authorization", &access_token));
242 EXPECT_EQ(std::string("Bearer ") + kAccessToken, access_token);
243 const std::string upload_data = url_fetcher->upload_data();
244 std::string managed_user_id;
245 EXPECT_TRUE(GetValueForKey(upload_data, "profile_id", &managed_user_id));
246 EXPECT_EQ(kManagedUserId, managed_user_id);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100247 std::string device_name;
248 EXPECT_TRUE(GetValueForKey(upload_data, "device_name", &device_name));
249 EXPECT_EQ(kDeviceName, device_name);
250 return url_fetcher;
251}
252
253net::TestURLFetcher*
254ManagedUserRefreshTokenFetcherTest::GetRefreshTokenRequest() {
Ben Murdocheb525c52013-07-10 11:40:50 +0100255 net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(
256 gaia::GaiaOAuthClient::kUrlFetcherId);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100257 if (!url_fetcher)
258 return NULL;
259
260 EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_token_url(),
261 url_fetcher->GetOriginalURL().spec());
262 std::string auth_code;
263 EXPECT_TRUE(GetValueForKey(url_fetcher->upload_data(), "code", &auth_code));
264 EXPECT_EQ(kAuthorizationCode, auth_code);
265 return url_fetcher;
266}
267
268void ManagedUserRefreshTokenFetcherTest::MakeIssueTokenRequestSucceed() {
269 SendResponse(GetIssueTokenRequest(),
270 base::StringPrintf(kIssueTokenResponseFormat,
271 kAuthorizationCode));
272}
273
274void ManagedUserRefreshTokenFetcherTest::MakeRefreshTokenFetchSucceed() {
275 SendResponse(GetRefreshTokenRequest(),
276 base::StringPrintf(kGetRefreshTokenResponseFormat,
277 kManagedUserToken));
278}
279
280void ManagedUserRefreshTokenFetcherTest::Reset() {
281 token_fetcher_.reset();
282}
283
284void ManagedUserRefreshTokenFetcherTest::OnTokenFetched(
285 const GoogleServiceAuthError& error,
286 const std::string& token) {
287 error_ = error;
288 token_ = token;
289}
290
291// Tests --------------------------------------------------------
292
293TEST_F(ManagedUserRefreshTokenFetcherTest, Success) {
294 StartFetching();
295 GetOAuth2TokenServiceRequest()->Succeed();
296 MakeIssueTokenRequestSucceed();
297 MakeRefreshTokenFetchSucceed();
298
299 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
300 EXPECT_EQ(kManagedUserToken, token());
301}
302
303TEST_F(ManagedUserRefreshTokenFetcherTest, ExpiredAccessToken) {
304 StartFetching();
305 GetOAuth2TokenServiceRequest()->Succeed();
306 SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
307 GetOAuth2TokenServiceRequest()->Succeed();
308 MakeIssueTokenRequestSucceed();
309 MakeRefreshTokenFetchSucceed();
310
311 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
312 EXPECT_EQ(kManagedUserToken, token());
313}
314
315TEST_F(ManagedUserRefreshTokenFetcherTest, ExpiredAccessTokenRetry) {
316 // If we get a 401 error for the second time, we should give up instead of
317 // retrying again.
318 StartFetching();
319 GetOAuth2TokenServiceRequest()->Succeed();
320 SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
321 GetOAuth2TokenServiceRequest()->Succeed();
322 SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
323
324 EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
325 EXPECT_EQ(net::ERR_FAILED, error().network_error());
326 EXPECT_EQ(std::string(), token());
327}
328
329TEST_F(ManagedUserRefreshTokenFetcherTest, MalformedIssueTokenResponse) {
330 StartFetching();
331 GetOAuth2TokenServiceRequest()->Succeed();
332 SendResponse(GetIssueTokenRequest(), "choke");
333
334 EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
335 EXPECT_EQ(net::ERR_INVALID_RESPONSE, error().network_error());
336 EXPECT_EQ(std::string(), token());
337}
338
339TEST_F(ManagedUserRefreshTokenFetcherTest, FetchAccessTokenFailure) {
340 StartFetching();
341 GetOAuth2TokenServiceRequest()->Fail(
342 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
343
344 EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, error().state());
345 EXPECT_EQ(std::string(), token());
346}
347
348TEST_F(ManagedUserRefreshTokenFetcherTest, IssueTokenNetworkError) {
349 StartFetching();
350 GetOAuth2TokenServiceRequest()->Succeed();
351 SetNetworkError(GetIssueTokenRequest(), net::ERR_SSL_PROTOCOL_ERROR);
352
353 EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
354 EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, error().network_error());
355 EXPECT_EQ(std::string(), token());
356}
357
358TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenNetworkError) {
359 StartFetching();
360 GetOAuth2TokenServiceRequest()->Succeed();
361 MakeIssueTokenRequestSucceed();
362 SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
363 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
364 SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
365
366 EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
367 EXPECT_EQ(net::ERR_FAILED, error().network_error());
368 EXPECT_EQ(std::string(), token());
369}
370
371TEST_F(ManagedUserRefreshTokenFetcherTest,
372 FetchRefreshTokenTransientNetworkError) {
373 StartFetching();
374 GetOAuth2TokenServiceRequest()->Succeed();
375 MakeIssueTokenRequestSucceed();
376 SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
377
378 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
379 MakeRefreshTokenFetchSucceed();
380
381 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
382 EXPECT_EQ(kManagedUserToken, token());
383}
384
385TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenBadRequest) {
386 StartFetching();
387 GetOAuth2TokenServiceRequest()->Succeed();
388 MakeIssueTokenRequestSucceed();
389 SetHttpError(GetRefreshTokenRequest(), net::HTTP_BAD_REQUEST);
390
391 EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
392 EXPECT_EQ(net::ERR_FAILED, error().network_error());
393 EXPECT_EQ(std::string(), token());
394}
395
396TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileFetchingAccessToken) {
397 StartFetching();
398 Reset();
399
400 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
401 EXPECT_EQ(std::string(), token());
402}
403
404TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileCallingIssueToken) {
405 StartFetching();
406 GetOAuth2TokenServiceRequest()->Succeed();
407 Reset();
408
409 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
410 EXPECT_EQ(std::string(), token());
411}
412
413TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileFetchingRefreshToken) {
414 StartFetching();
415 GetOAuth2TokenServiceRequest()->Succeed();
416 MakeIssueTokenRequestSucceed();
417 Reset();
418
419 EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
420 EXPECT_EQ(std::string(), token());
421}