Commit 40b389af authored by bauerb@chromium.org's avatar bauerb@chromium.org

Add ManagedUserTokenFetcher to fetch scoped-down tokens.

TBR=rogerta@chromium.org
BUG=228833

Review URL: https://chromiumcodereview.appspot.com/15977002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203015 0039d316-1c4b-4281-b951-d872f2087c98
parent ca5839dc
...@@ -324,10 +324,7 @@ class DeviceCloudPolicyManagerChromeOSEnrollmentTest ...@@ -324,10 +324,7 @@ class DeviceCloudPolicyManagerChromeOSEnrollmentTest
if (robot_auth_fetch_status_ == DM_STATUS_SUCCESS) { if (robot_auth_fetch_status_ == DM_STATUS_SUCCESS) {
net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0); net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0);
ASSERT_TRUE(url_fetcher); ASSERT_TRUE(url_fetcher);
// The logic in GaiaOAuthClient seems broken, it always retries 1x on url_fetcher->SetMaxRetriesOn5xx(0);
// non-200 response codes, even if the retries are set to 0. Seems like
// its num_retries_ > source->GetMaxRetriesOn5xx() should have a >=?
url_fetcher->SetMaxRetriesOn5xx(-2);
url_fetcher->set_status(net::URLRequestStatus()); url_fetcher->set_status(net::URLRequestStatus());
url_fetcher->set_response_code(url_fetcher_response_code_); url_fetcher->set_response_code(url_fetcher_response_code_);
url_fetcher->SetResponseString(url_fetcher_response_string_); url_fetcher->SetResponseString(url_fetcher_response_string_);
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
#include "base/callback.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/string16.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/signin/oauth2_token_service.h"
#include "google_apis/gaia/gaia_oauth_client.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_api_call_flow.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_status.h"
using base::Time;
using gaia::GaiaOAuthClient;
using net::URLFetcher;
using net::URLFetcherDelegate;
using net::URLRequestContextGetter;
namespace {
const int kNumRetries = 1;
static const char kChromeSyncManagedScope[] =
"https://www.googleapis.com/auth/chromesync_playpen";
static const char kIssueTokenBodyFormat[] =
"client_id=%s"
"&scope=&%s"
"&response_type=code"
"&profile_id=%s"
"&profile_name=%s"
"&device_name=%s";
static const char kAuthorizationHeaderFormat[] =
"Authorization: Bearer %s";
static const char kCodeKey[] = "code";
class ManagedUserRefreshTokenFetcherImpl
: public ManagedUserRefreshTokenFetcher,
public OAuth2TokenService::Consumer,
public URLFetcherDelegate,
public GaiaOAuthClient::Delegate {
public:
ManagedUserRefreshTokenFetcherImpl(OAuth2TokenService* oauth2_token_service,
URLRequestContextGetter* context);
virtual ~ManagedUserRefreshTokenFetcherImpl();
// ManagedUserRefreshTokenFetcher implementation:
virtual void Start(const std::string& managed_user_id,
const string16& name,
const std::string& device_name,
const TokenCallback& callback) OVERRIDE;
protected:
// OAuth2TokenService::Consumer implementation:
virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
const std::string& access_token,
const Time& expiration_time) OVERRIDE;
virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) OVERRIDE;
// net::URLFetcherDelegate implementation.
virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE;
// GaiaOAuthClient::Delegate implementation:
virtual void OnGetTokensResponse(const std::string& refresh_token,
const std::string& access_token,
int expires_in_seconds) OVERRIDE;
virtual void OnRefreshTokenResponse(const std::string& access_token,
int expires_in_seconds) OVERRIDE;
virtual void OnOAuthError() OVERRIDE;
virtual void OnNetworkError(int response_code) OVERRIDE;
private:
// Requests an access token, which is the first thing we need. This is where
// we restart when the returned access token has expired.
void StartFetching();
void DispatchNetworkError(int error_code);
void DispatchGoogleServiceAuthError(const GoogleServiceAuthError& error,
const std::string& token);
OAuth2TokenService* oauth2_token_service_;
URLRequestContextGetter* context_;
std::string device_name_;
std::string managed_user_id_;
string16 name_;
TokenCallback callback_;
scoped_ptr<OAuth2TokenService::Request> access_token_request_;
std::string access_token_;
bool access_token_expired_;
scoped_ptr<URLFetcher> url_fetcher_;
scoped_ptr<GaiaOAuthClient> gaia_oauth_client_;
};
ManagedUserRefreshTokenFetcherImpl::ManagedUserRefreshTokenFetcherImpl(
OAuth2TokenService* oauth2_token_service,
URLRequestContextGetter* context)
: oauth2_token_service_(oauth2_token_service),
context_(context),
access_token_expired_(false) {}
ManagedUserRefreshTokenFetcherImpl::~ManagedUserRefreshTokenFetcherImpl() {}
void ManagedUserRefreshTokenFetcherImpl::Start(
const std::string& managed_user_id,
const string16& name,
const std::string& device_name,
const TokenCallback& callback) {
DCHECK(callback_.is_null());
managed_user_id_ = managed_user_id;
name_ = name;
device_name_ = device_name;
callback_ = callback;
StartFetching();
}
void ManagedUserRefreshTokenFetcherImpl::StartFetching() {
OAuth2TokenService::ScopeSet scopes;
scopes.insert(GaiaUrls::GetInstance()->oauth1_login_scope());
access_token_request_ = oauth2_token_service_->StartRequest(scopes, this);
}
void ManagedUserRefreshTokenFetcherImpl::OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
const std::string& access_token,
const Time& expiration_time) {
DCHECK_EQ(access_token_request_.get(), request);
access_token_ = access_token;
GURL url(GaiaUrls::GetInstance()->oauth2_issue_token_url());
// GaiaOAuthClient uses id 0, so we use 1 to distinguish the requests in
// unit tests.
const int id = 1;
url_fetcher_.reset(URLFetcher::Create(id, url, URLFetcher::POST, this));
url_fetcher_->SetRequestContext(context_);
url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES);
url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kNumRetries);
url_fetcher_->AddExtraRequestHeader(
base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
std::string body = base::StringPrintf(
kIssueTokenBodyFormat,
net::EscapeUrlEncodedData(
GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true).c_str(),
net::EscapeUrlEncodedData(kChromeSyncManagedScope, true).c_str(),
net::EscapeUrlEncodedData(managed_user_id_, true).c_str(),
net::EscapeUrlEncodedData(UTF16ToUTF8(name_), true).c_str(),
net::EscapeUrlEncodedData(device_name_, true).c_str());
url_fetcher_->SetUploadData("application/x-www-form-urlencoded", body);
url_fetcher_->Start();
}
void ManagedUserRefreshTokenFetcherImpl::OnGetTokenFailure(
const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) {
DCHECK_EQ(access_token_request_.get(), request);
callback_.Run(error, std::string());
callback_.Reset();
}
void ManagedUserRefreshTokenFetcherImpl::OnURLFetchComplete(
const URLFetcher* source) {
const net::URLRequestStatus& status = source->GetStatus();
if (!status.is_success()) {
DispatchNetworkError(status.error());
return;
}
int response_code = source->GetResponseCode();
if (response_code == net::HTTP_UNAUTHORIZED && !access_token_expired_) {
access_token_expired_ = true;
oauth2_token_service_->InvalidateToken(OAuth2TokenService::ScopeSet(),
access_token_);
StartFetching();
return;
}
if (response_code != net::HTTP_OK) {
// TODO(bauerb): We should return the HTTP response code somehow.
DLOG(WARNING) << "HTTP error " << response_code;
DispatchGoogleServiceAuthError(
GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
std::string());
return;
}
std::string response_body;
source->GetResponseAsString(&response_body);
scoped_ptr<base::Value> value(base::JSONReader::Read(response_body));
DictionaryValue* dict = NULL;
if (!value.get() || !value->GetAsDictionary(&dict)) {
DispatchNetworkError(net::ERR_INVALID_RESPONSE);
return;
}
std::string auth_code;
if (!dict->GetString(kCodeKey, &auth_code)) {
DispatchNetworkError(net::ERR_INVALID_RESPONSE);
return;
}
gaia::OAuthClientInfo client_info;
GaiaUrls* urls = GaiaUrls::GetInstance();
client_info.client_id = urls->oauth2_chrome_client_id();
client_info.client_secret = urls->oauth2_chrome_client_secret();
gaia_oauth_client_.reset(
new gaia::GaiaOAuthClient(GaiaUrls::GetInstance()->oauth2_token_url(),
context_));
gaia_oauth_client_->GetTokensFromAuthCode(client_info, auth_code, kNumRetries,
this);
}
void ManagedUserRefreshTokenFetcherImpl::OnGetTokensResponse(
const std::string& refresh_token,
const std::string& access_token,
int expires_in_seconds) {
// TODO(bauerb): It would be nice if we could pass the access token as well,
// so we don't need to fetch another one immediately.
DispatchGoogleServiceAuthError(GoogleServiceAuthError::AuthErrorNone(),
refresh_token);
}
void ManagedUserRefreshTokenFetcherImpl::OnRefreshTokenResponse(
const std::string& access_token,
int expires_in_seconds) {
NOTREACHED();
}
void ManagedUserRefreshTokenFetcherImpl::OnOAuthError() {
DispatchGoogleServiceAuthError(
GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
std::string());
}
void ManagedUserRefreshTokenFetcherImpl::OnNetworkError(int response_code) {
// TODO(bauerb): We should return the HTTP response code somehow.
DLOG(WARNING) << "HTTP error " << response_code;
DispatchGoogleServiceAuthError(
GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
std::string());
}
void ManagedUserRefreshTokenFetcherImpl::DispatchNetworkError(int error_code) {
DispatchGoogleServiceAuthError(
GoogleServiceAuthError::FromConnectionError(error_code), std::string());
}
void ManagedUserRefreshTokenFetcherImpl::DispatchGoogleServiceAuthError(
const GoogleServiceAuthError& error,
const std::string& token) {
callback_.Run(error, token);
callback_.Reset();
}
} // namespace
// static
scoped_ptr<ManagedUserRefreshTokenFetcher>
ManagedUserRefreshTokenFetcher::Create(OAuth2TokenService* oauth2_token_service,
URLRequestContextGetter* context) {
scoped_ptr<ManagedUserRefreshTokenFetcher> fetcher(
new ManagedUserRefreshTokenFetcherImpl(oauth2_token_service, context));
return fetcher.Pass();
}
ManagedUserRefreshTokenFetcher::~ManagedUserRefreshTokenFetcher() {}
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_REFRESH_TOKEN_FETCHER_H_
#define CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_REFRESH_TOKEN_FETCHER_H_
#include <string>
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
class GoogleServiceAuthError;
class OAuth2TokenService;
namespace net {
class URLRequestContextGetter;
}
// This class fetches an OAuth2 refresh token that is tied to a managed user ID
// and downscoped to a special scope for Chrome Sync for managed users.
// Fetching the token consists of the following steps:
// 1. Get an access token for the custodian from OAuth2TokenService
// (either cached or fetched).
// 2. Call the IssueToken API to mint a scoped authorization code for a
// refresh token for the managed user from the custodian's access token.
// 3. Exchange the authorization code for a refresh token for the managed
// user and return it to the caller. The refresh token can only be used to
// mint tokens with the special managed user Sync scope.
class ManagedUserRefreshTokenFetcher {
public:
typedef base::Callback<void(const GoogleServiceAuthError& /* error */,
const std::string& /* refresh_token */)>
TokenCallback;
static scoped_ptr<ManagedUserRefreshTokenFetcher> Create(
OAuth2TokenService* oauth2_token_service,
net::URLRequestContextGetter* context);
virtual ~ManagedUserRefreshTokenFetcher();
virtual void Start(const std::string& managed_user_id,
const string16& name,
const std::string& device_name,
const TokenCallback& callback) = 0;
};
#endif // CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_REFRESH_TOKEN_FETCHER_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
#include "chrome/browser/signin/oauth2_token_service.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "net/base/net_errors.h"
#include "net/base/url_util.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_status_code.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kManagedUserId[] = "abcdef";
const char kName[] = "Homestar";
const char kDeviceName[] = "Compy";
const char kAccessToken[] = "accesstoken";
const char kAuthorizationCode[] = "authorizationcode";
const char kManagedUserToken[] = "managedusertoken";
const char kIssueTokenResponseFormat[] =
"{"
" \"code\": \"%s\""
"}";
const char kGetRefreshTokenResponseFormat[] =
"{"
" \"access_token\": \"<ignored>\","
" \"expires_in\": 12345,"
" \"refresh_token\": \"%s\""
"}";
// MockOAuth2TokenService ---------------------------------------------
class MockOAuth2TokenService : public OAuth2TokenService {
public:
class Request : public OAuth2TokenService::Request {
public:
Request(const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer,
MockOAuth2TokenService* owner);
virtual ~Request();
void Succeed();
void Fail(GoogleServiceAuthError::State error);
const OAuth2TokenService::ScopeSet& scopes() const { return scopes_; }
private:
OAuth2TokenService::ScopeSet scopes_;
OAuth2TokenService::Consumer* consumer_;
MockOAuth2TokenService* owner_;
};
MockOAuth2TokenService();
virtual ~MockOAuth2TokenService();
Request* request() const { return request_; }
void ClearRequest(Request* request);
private:
// OAuth2TokenService overrides:
virtual scoped_ptr<OAuth2TokenService::Request> StartRequest(
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer) OVERRIDE;
virtual std::string GetRefreshToken() OVERRIDE;
Request* request_;
DISALLOW_COPY_AND_ASSIGN(MockOAuth2TokenService);
};
MockOAuth2TokenService::Request::Request(
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer,
MockOAuth2TokenService* owner)
: scopes_(scopes),
consumer_(consumer),
owner_(owner) {}
MockOAuth2TokenService::Request::~Request() {
owner_->ClearRequest(this);
}
void MockOAuth2TokenService::Request::Succeed() {
base::Time expiration_date = base::Time::Now() +
base::TimeDelta::FromHours(1);
consumer_->OnGetTokenSuccess(this, kAccessToken, expiration_date);
}
void MockOAuth2TokenService::Request::Fail(
GoogleServiceAuthError::State error) {
consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(error));
}
MockOAuth2TokenService::MockOAuth2TokenService()
: OAuth2TokenService(NULL),
request_(NULL) {}
MockOAuth2TokenService::~MockOAuth2TokenService() {
EXPECT_FALSE(request_);
}
void MockOAuth2TokenService::ClearRequest(
MockOAuth2TokenService::Request* request) {
if (request_ == request)
request_ = NULL;
}
scoped_ptr<OAuth2TokenService::Request> MockOAuth2TokenService::StartRequest(
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer) {
scoped_ptr<Request> request(new Request(scopes, consumer, this));
request_ = request.get();
return request.PassAs<OAuth2TokenService::Request>();
}
std::string MockOAuth2TokenService::GetRefreshToken() {
NOTREACHED();
return std::string();
}
// Utility methods --------------------------------------------------
// Slightly hacky way to extract a value from a URL-encoded POST request body.
bool GetValueForKey(const std::string& encoded_string,
const std::string& key,
std::string* value) {
GURL url("http://example.com/?" + encoded_string);
return net::GetValueForKeyInQuery(url, key, value);
}
void SendResponse(net::TestURLFetcher* url_fetcher,
const std::string& response) {
url_fetcher->set_status(
net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
url_fetcher->set_response_code(net::HTTP_OK);
url_fetcher->SetResponseString(response);
url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
}
void SetNetworkError(net::TestURLFetcher* url_fetcher, int error) {
url_fetcher->set_status(
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
}
void SetHttpError(net::TestURLFetcher* url_fetcher, int error) {
url_fetcher->set_status(net::URLRequestStatus());
url_fetcher->set_response_code(error);
url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
}
} // namespace
class ManagedUserRefreshTokenFetcherTest : public testing::Test {
public:
ManagedUserRefreshTokenFetcherTest();
virtual ~ManagedUserRefreshTokenFetcherTest() {}
protected:
void StartFetching();
MockOAuth2TokenService::Request* GetOAuth2TokenServiceRequest();
net::TestURLFetcher* GetIssueTokenRequest();
net::TestURLFetcher* GetRefreshTokenRequest();
void MakeIssueTokenRequestSucceed();
void MakeRefreshTokenFetchSucceed();
void Reset();
const GoogleServiceAuthError& error() const { return error_; }
const std::string& token() const { return token_; }
private:
void OnTokenFetched(const GoogleServiceAuthError& error,
const std::string& token);
base::WeakPtrFactory<ManagedUserRefreshTokenFetcherTest> weak_ptr_factory_;
base::MessageLoop message_loop_;
content::TestBrowserThread ui_thread_;
TestingProfile profile_;
MockOAuth2TokenService oauth2_token_service_;
net::TestURLFetcherFactory url_fetcher_factory_;
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher_;
GoogleServiceAuthError error_;
std::string token_;
};
ManagedUserRefreshTokenFetcherTest::ManagedUserRefreshTokenFetcherTest()
: weak_ptr_factory_(this),
ui_thread_(content::BrowserThread::UI, &message_loop_),
token_fetcher_(
ManagedUserRefreshTokenFetcher::Create(&oauth2_token_service_,
profile_.GetRequestContext())),
error_(GoogleServiceAuthError::NONE) {}
void ManagedUserRefreshTokenFetcherTest::StartFetching() {
token_fetcher_->Start(kManagedUserId, UTF8ToUTF16(kName), kDeviceName,
base::Bind(
&ManagedUserRefreshTokenFetcherTest::OnTokenFetched,
weak_ptr_factory_.GetWeakPtr()));
}
MockOAuth2TokenService::Request*
ManagedUserRefreshTokenFetcherTest::GetOAuth2TokenServiceRequest() {
MockOAuth2TokenService::Request* request = oauth2_token_service_.request();
OAuth2TokenService::ScopeSet scopes = request->scopes();
EXPECT_EQ(1u, scopes.size());
EXPECT_EQ(1u, scopes.count(GaiaUrls::GetInstance()->oauth1_login_scope()));
return request;
}
net::TestURLFetcher*
ManagedUserRefreshTokenFetcherTest::GetIssueTokenRequest() {
net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(1);
if (!url_fetcher)
return NULL;
EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_issue_token_url(),
url_fetcher->GetOriginalURL().spec());
std::string access_token;
net::HttpRequestHeaders headers;
url_fetcher->GetExtraRequestHeaders(&headers);
EXPECT_TRUE(headers.GetHeader("Authorization", &access_token));
EXPECT_EQ(std::string("Bearer ") + kAccessToken, access_token);
const std::string upload_data = url_fetcher->upload_data();
std::string managed_user_id;
EXPECT_TRUE(GetValueForKey(upload_data, "profile_id", &managed_user_id));
EXPECT_EQ(kManagedUserId, managed_user_id);
std::string name;
EXPECT_TRUE(GetValueForKey(upload_data, "profile_name", &name));
EXPECT_EQ(kName, name);
std::string device_name;
EXPECT_TRUE(GetValueForKey(upload_data, "device_name", &device_name));
EXPECT_EQ(kDeviceName, device_name);
return url_fetcher;
}
net::TestURLFetcher*
ManagedUserRefreshTokenFetcherTest::GetRefreshTokenRequest() {
net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0);
if (!url_fetcher)
return NULL;
EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_token_url(),
url_fetcher->GetOriginalURL().spec());
std::string auth_code;
EXPECT_TRUE(GetValueForKey(url_fetcher->upload_data(), "code", &auth_code));
EXPECT_EQ(kAuthorizationCode, auth_code);
return url_fetcher;
}
void ManagedUserRefreshTokenFetcherTest::MakeIssueTokenRequestSucceed() {
SendResponse(GetIssueTokenRequest(),
base::StringPrintf(kIssueTokenResponseFormat,
kAuthorizationCode));
}
void ManagedUserRefreshTokenFetcherTest::MakeRefreshTokenFetchSucceed() {
SendResponse(GetRefreshTokenRequest(),
base::StringPrintf(kGetRefreshTokenResponseFormat,
kManagedUserToken));
}
void ManagedUserRefreshTokenFetcherTest::Reset() {
token_fetcher_.reset();
}
void ManagedUserRefreshTokenFetcherTest::OnTokenFetched(
const GoogleServiceAuthError& error,
const std::string& token) {
error_ = error;
token_ = token;
}
// Tests --------------------------------------------------------
TEST_F(ManagedUserRefreshTokenFetcherTest, Success) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
MakeIssueTokenRequestSucceed();
MakeRefreshTokenFetchSucceed();
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_EQ(kManagedUserToken, token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, ExpiredAccessToken) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
GetOAuth2TokenServiceRequest()->Succeed();
MakeIssueTokenRequestSucceed();
MakeRefreshTokenFetchSucceed();
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_EQ(kManagedUserToken, token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, ExpiredAccessTokenRetry) {
// If we get a 401 error for the second time, we should give up instead of
// retrying again.
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
GetOAuth2TokenServiceRequest()->Succeed();
SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
EXPECT_EQ(net::ERR_FAILED, error().network_error());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, MalformedIssueTokenResponse) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
SendResponse(GetIssueTokenRequest(), "choke");
EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
EXPECT_EQ(net::ERR_INVALID_RESPONSE, error().network_error());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, FetchAccessTokenFailure) {
StartFetching();
GetOAuth2TokenServiceRequest()->Fail(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, error().state());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, IssueTokenNetworkError) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
SetNetworkError(GetIssueTokenRequest(), net::ERR_SSL_PROTOCOL_ERROR);
EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, error().network_error());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenNetworkError) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
MakeIssueTokenRequestSucceed();
SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
EXPECT_EQ(net::ERR_FAILED, error().network_error());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest,
FetchRefreshTokenTransientNetworkError) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
MakeIssueTokenRequestSucceed();
SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
MakeRefreshTokenFetchSucceed();
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_EQ(kManagedUserToken, token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenBadRequest) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
MakeIssueTokenRequestSucceed();
SetHttpError(GetRefreshTokenRequest(), net::HTTP_BAD_REQUEST);
EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
EXPECT_EQ(net::ERR_FAILED, error().network_error());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileFetchingAccessToken) {
StartFetching();
Reset();
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileCallingIssueToken) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
Reset();
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_EQ(std::string(), token());
}
TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileFetchingRefreshToken) {
StartFetching();
GetOAuth2TokenServiceRequest()->Succeed();
MakeIssueTokenRequestSucceed();
Reset();
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_EQ(std::string(), token());
}
...@@ -9,11 +9,14 @@ ...@@ -9,11 +9,14 @@
#include "base/prefs/pref_service.h" #include "base/prefs/pref_service.h"
#include "base/rand_util.h" #include "base/rand_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
#include "chrome/browser/managed_mode/managed_user_service.h" #include "chrome/browser/managed_mode/managed_user_service.h"
#include "chrome/browser/managed_mode/managed_user_service_factory.h" #include "chrome/browser/managed_mode/managed_user_service_factory.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/sync/glue/device_info.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h" #include "components/user_prefs/pref_registry_syncable.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/google_service_auth_error.h"
#include "sync/api/sync_change.h" #include "sync/api/sync_change.h"
#include "sync/api/sync_error_factory.h" #include "sync/api/sync_error_factory.h"
...@@ -52,9 +55,11 @@ SyncData CreateLocalSyncData(const std::string& id, ...@@ -52,9 +55,11 @@ SyncData CreateLocalSyncData(const std::string& id,
} // namespace } // namespace
ManagedUserRegistrationService::ManagedUserRegistrationService( ManagedUserRegistrationService::ManagedUserRegistrationService(
PrefService* prefs) PrefService* prefs,
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher)
: weak_ptr_factory_(this), : weak_ptr_factory_(this),
prefs_(prefs), prefs_(prefs),
token_fetcher_(token_fetcher.Pass()),
pending_managed_user_acknowledged_(false) { pending_managed_user_acknowledged_(false) {
pref_change_registrar_.Init(prefs); pref_change_registrar_.Init(prefs);
pref_change_registrar_.Add( pref_change_registrar_.Add(
...@@ -103,7 +108,9 @@ void ManagedUserRegistrationService::Register( ...@@ -103,7 +108,9 @@ void ManagedUserRegistrationService::Register(
} }
callback_ = callback; callback_ = callback;
OnReceivedToken("abcdef"); // TODO(bauerb): This is a stub implementation. browser_sync::DeviceInfo::CreateLocalDeviceInfo(
base::Bind(&ManagedUserRegistrationService::FetchToken,
weak_ptr_factory_.GetWeakPtr(), name));
} }
ProfileManager::CreateCallback ProfileManager::CreateCallback
...@@ -268,8 +275,24 @@ void ManagedUserRegistrationService::OnManagedUserAcknowledged( ...@@ -268,8 +275,24 @@ void ManagedUserRegistrationService::OnManagedUserAcknowledged(
DispatchCallbackIfReady(); DispatchCallbackIfReady();
} }
void ManagedUserRegistrationService::OnReceivedToken(const std::string& token) { void ManagedUserRegistrationService::FetchToken(
DCHECK(pending_managed_user_token_.empty()); const string16& name,
const browser_sync::DeviceInfo& device_info) {
token_fetcher_->Start(
pending_managed_user_id_, name, device_info.client_name(),
base::Bind(&ManagedUserRegistrationService::OnReceivedToken,
weak_ptr_factory_.GetWeakPtr()));
}
void ManagedUserRegistrationService::OnReceivedToken(
const GoogleServiceAuthError& error,
const std::string& token) {
if (error.state() != GoogleServiceAuthError::NONE) {
DispatchCallback(error);
return;
}
DCHECK(!token.empty());
pending_managed_user_token_ = token; pending_managed_user_token_ = token;
DispatchCallbackIfReady(); DispatchCallbackIfReady();
} }
......
...@@ -17,8 +17,13 @@ ...@@ -17,8 +17,13 @@
#include "sync/api/syncable_service.h" #include "sync/api/syncable_service.h"
class GoogleServiceAuthError; class GoogleServiceAuthError;
class ManagedUserRefreshTokenFetcher;
class PrefService; class PrefService;
namespace browser_sync {
class DeviceInfo;
}
namespace user_prefs { namespace user_prefs {
class PrefRegistrySyncable; class PrefRegistrySyncable;
} }
...@@ -37,13 +42,17 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService, ...@@ -37,13 +42,17 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService,
const std::string& /* token */)> const std::string& /* token */)>
RegistrationCallback; RegistrationCallback;
explicit ManagedUserRegistrationService(PrefService* prefs); ManagedUserRegistrationService(
PrefService* prefs,
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher);
virtual ~ManagedUserRegistrationService(); virtual ~ManagedUserRegistrationService();
static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry); static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
// Registers a new managed user with the server. |name| is the display name of // Registers a new managed user with the server. |name| is the display name of
// the user. |callback| is called with the result of the registration. // the user. |callback| is called with the result of the registration.
// TODO(bauerb): There should be a way to cancel a pending managed user
// registration.
void Register(const string16& name, const RegistrationCallback& callback); void Register(const string16& name, const RegistrationCallback& callback);
// Convenience method that registers a new managed user with the server and // Convenience method that registers a new managed user with the server and
...@@ -77,8 +86,13 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService, ...@@ -77,8 +86,13 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService,
// Called when the Sync server has acknowledged a newly created managed user. // Called when the Sync server has acknowledged a newly created managed user.
void OnManagedUserAcknowledged(const std::string& managed_user_id); void OnManagedUserAcknowledged(const std::string& managed_user_id);
// Fetches the managed user token when we have the device info.
void FetchToken(const string16& name,
const browser_sync::DeviceInfo& device_info);
// Called when we have received a token for the managed user. // Called when we have received a token for the managed user.
void OnReceivedToken(const std::string& token); void OnReceivedToken(const GoogleServiceAuthError& error,
const std::string& token);
// Dispatches the callback if all the conditions have been met. // Dispatches the callback if all the conditions have been met.
void DispatchCallbackIfReady(); void DispatchCallbackIfReady();
...@@ -94,6 +108,7 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService, ...@@ -94,6 +108,7 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService,
base::WeakPtrFactory<ManagedUserRegistrationService> weak_ptr_factory_; base::WeakPtrFactory<ManagedUserRegistrationService> weak_ptr_factory_;
PrefService* prefs_; PrefService* prefs_;
PrefChangeRegistrar pref_change_registrar_; PrefChangeRegistrar pref_change_registrar_;
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher_;
scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
scoped_ptr<syncer::SyncErrorFactory> error_handler_; scoped_ptr<syncer::SyncErrorFactory> error_handler_;
......
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
#include "chrome/browser/managed_mode/managed_user_registration_service_factory.h" #include "chrome/browser/managed_mode/managed_user_registration_service_factory.h"
#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
#include "chrome/browser/managed_mode/managed_user_registration_service.h" #include "chrome/browser/managed_mode/managed_user_registration_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
// static // static
...@@ -23,13 +27,20 @@ ManagedUserRegistrationServiceFactory::GetInstance() { ...@@ -23,13 +27,20 @@ ManagedUserRegistrationServiceFactory::GetInstance() {
// static // static
BrowserContextKeyedService* BrowserContextKeyedService*
ManagedUserRegistrationServiceFactory::BuildInstanceFor(Profile* profile) { ManagedUserRegistrationServiceFactory::BuildInstanceFor(Profile* profile) {
return new ManagedUserRegistrationService(profile->GetPrefs()); OAuth2TokenService* oauth2_token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
return new ManagedUserRegistrationService(
profile->GetPrefs(),
ManagedUserRefreshTokenFetcher::Create(oauth2_token_service,
profile->GetRequestContext()));
} }
ManagedUserRegistrationServiceFactory::ManagedUserRegistrationServiceFactory() ManagedUserRegistrationServiceFactory::ManagedUserRegistrationServiceFactory()
: BrowserContextKeyedServiceFactory( : BrowserContextKeyedServiceFactory(
"ManagedUserRegistrationService", "ManagedUserRegistrationService",
BrowserContextDependencyManager::GetInstance()) {} BrowserContextDependencyManager::GetInstance()) {
DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
}
ManagedUserRegistrationServiceFactory:: ManagedUserRegistrationServiceFactory::
~ManagedUserRegistrationServiceFactory() {} ~ManagedUserRegistrationServiceFactory() {}
......
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
#include <string> #include <string>
#include "base/bind.h" #include "base/bind.h"
#include "base/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
#include "chrome/browser/managed_mode/managed_user_registration_service.h" #include "chrome/browser/managed_mode/managed_user_registration_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
...@@ -29,6 +32,8 @@ using syncer::SyncMergeResult; ...@@ -29,6 +32,8 @@ using syncer::SyncMergeResult;
namespace { namespace {
const char kManagedUserToken[] = "managedusertoken";
class MockChangeProcessor : public SyncChangeProcessor { class MockChangeProcessor : public SyncChangeProcessor {
public: public:
MockChangeProcessor() {} MockChangeProcessor() {}
...@@ -62,6 +67,22 @@ SyncChange MockChangeProcessor::GetChange(const std::string& id) const { ...@@ -62,6 +67,22 @@ SyncChange MockChangeProcessor::GetChange(const std::string& id) const {
return SyncChange(); return SyncChange();
} }
class MockManagedUserRefreshTokenFetcher
: public ManagedUserRefreshTokenFetcher {
public:
MockManagedUserRefreshTokenFetcher() {}
virtual ~MockManagedUserRefreshTokenFetcher() {}
// ManagedUserRefreshTokenFetcher implementation:
virtual void Start(const std::string& managed_user_id,
const string16& name,
const std::string& device_name,
const TokenCallback& callback) OVERRIDE {
GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
callback.Run(error, kManagedUserToken);
}
};
} // namespace } // namespace
class ManagedUserRegistrationServiceTest : public ::testing::Test { class ManagedUserRegistrationServiceTest : public ::testing::Test {
...@@ -94,6 +115,8 @@ class ManagedUserRegistrationServiceTest : public ::testing::Test { ...@@ -94,6 +115,8 @@ class ManagedUserRegistrationServiceTest : public ::testing::Test {
void OnManagedUserRegistered(const GoogleServiceAuthError& error, void OnManagedUserRegistered(const GoogleServiceAuthError& error,
const std::string& token); const std::string& token);
base::MessageLoop message_loop_;
base::RunLoop run_loop_;
base::WeakPtrFactory<ManagedUserRegistrationServiceTest> weak_ptr_factory_; base::WeakPtrFactory<ManagedUserRegistrationServiceTest> weak_ptr_factory_;
TestingPrefServiceSyncable prefs_; TestingPrefServiceSyncable prefs_;
scoped_ptr<ManagedUserRegistrationService> service_; scoped_ptr<ManagedUserRegistrationService> service_;
...@@ -114,12 +137,15 @@ class ManagedUserRegistrationServiceTest : public ::testing::Test { ...@@ -114,12 +137,15 @@ class ManagedUserRegistrationServiceTest : public ::testing::Test {
ManagedUserRegistrationServiceTest::ManagedUserRegistrationServiceTest() ManagedUserRegistrationServiceTest::ManagedUserRegistrationServiceTest()
: weak_ptr_factory_(this), : weak_ptr_factory_(this),
service_(new ManagedUserRegistrationService(&prefs_)),
change_processor_(NULL), change_processor_(NULL),
sync_data_id_(0), sync_data_id_(0),
received_callback_(false), received_callback_(false),
error_(GoogleServiceAuthError::NUM_STATES) { error_(GoogleServiceAuthError::NUM_STATES) {
ManagedUserRegistrationService::RegisterUserPrefs(prefs_.registry()); ManagedUserRegistrationService::RegisterUserPrefs(prefs_.registry());
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher(
new MockManagedUserRefreshTokenFetcher);
service_.reset(
new ManagedUserRegistrationService(&prefs_, token_fetcher.Pass()));
} }
ManagedUserRegistrationServiceTest::~ManagedUserRegistrationServiceTest() { ManagedUserRegistrationServiceTest::~ManagedUserRegistrationServiceTest() {
...@@ -180,6 +206,8 @@ void ManagedUserRegistrationServiceTest::Acknowledge() { ...@@ -180,6 +206,8 @@ void ManagedUserRegistrationServiceTest::Acknowledge() {
SyncData::CreateRemoteData(++sync_data_id_, specifics))); SyncData::CreateRemoteData(++sync_data_id_, specifics)));
} }
service()->ProcessSyncChanges(FROM_HERE, new_changes); service()->ProcessSyncChanges(FROM_HERE, new_changes);
run_loop_.Run();
} }
void ManagedUserRegistrationServiceTest::ResetService() { void ManagedUserRegistrationServiceTest::ResetService() {
...@@ -194,6 +222,7 @@ void ManagedUserRegistrationServiceTest::OnManagedUserRegistered( ...@@ -194,6 +222,7 @@ void ManagedUserRegistrationServiceTest::OnManagedUserRegistered(
received_callback_ = true; received_callback_ = true;
error_ = error; error_ = error;
token_ = token; token_ = token;
run_loop_.Quit();
} }
TEST_F(ManagedUserRegistrationServiceTest, MergeEmpty) { TEST_F(ManagedUserRegistrationServiceTest, MergeEmpty) {
......
...@@ -33,7 +33,7 @@ scoped_ptr<OAuth2TokenService::Request> ...@@ -33,7 +33,7 @@ scoped_ptr<OAuth2TokenService::Request>
ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid(); ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid();
sync_service->FetchOAuth2Token( sync_service->FetchOAuth2Token(
scope_list.front(), scope_list.front(),
base::Bind(&OAuth2TokenService::InformConsumer, base::Bind(&RequestImpl::InformConsumer,
request->AsWeakPtr())); request->AsWeakPtr()));
return request.PassAs<Request>(); return request.PassAs<Request>();
} }
......
...@@ -303,18 +303,6 @@ bool OAuth2TokenService::RefreshTokenIsAvailable() { ...@@ -303,18 +303,6 @@ bool OAuth2TokenService::RefreshTokenIsAvailable() {
return !GetRefreshToken().empty(); return !GetRefreshToken().empty();
} }
// static
void OAuth2TokenService::InformConsumer(
base::WeakPtr<OAuth2TokenService::RequestImpl> request,
const GoogleServiceAuthError& error,
const std::string& access_token,
const base::Time& expiration_date) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (request)
request->InformConsumer(error, access_token, expiration_date);
}
scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
const OAuth2TokenService::ScopeSet& scopes, const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer) { OAuth2TokenService::Consumer* consumer) {
...@@ -325,7 +313,7 @@ scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( ...@@ -325,7 +313,7 @@ scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
std::string refresh_token = GetRefreshToken(); std::string refresh_token = GetRefreshToken();
if (refresh_token.empty()) { if (refresh_token.empty()) {
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&OAuth2TokenService::InformConsumer, &RequestImpl::InformConsumer,
request->AsWeakPtr(), request->AsWeakPtr(),
GoogleServiceAuthError( GoogleServiceAuthError(
GoogleServiceAuthError::USER_NOT_SIGNED_UP), GoogleServiceAuthError::USER_NOT_SIGNED_UP),
...@@ -361,7 +349,7 @@ scoped_ptr<OAuth2TokenService::Request> ...@@ -361,7 +349,7 @@ scoped_ptr<OAuth2TokenService::Request>
const CacheEntry* cache_entry = GetCacheEntry(scopes); const CacheEntry* cache_entry = GetCacheEntry(scopes);
scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&OAuth2TokenService::InformConsumer, &RequestImpl::InformConsumer,
request->AsWeakPtr(), request->AsWeakPtr(),
GoogleServiceAuthError(GoogleServiceAuthError::NONE), GoogleServiceAuthError(GoogleServiceAuthError::NONE),
cache_entry->access_token, cache_entry->access_token,
...@@ -440,7 +428,7 @@ bool OAuth2TokenService::RemoveCacheEntry( ...@@ -440,7 +428,7 @@ bool OAuth2TokenService::RemoveCacheEntry(
const std::string& token_to_remove) { const std::string& token_to_remove) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
TokenCache::iterator token_iterator = token_cache_.find(scopes); TokenCache::iterator token_iterator = token_cache_.find(scopes);
if (token_iterator == token_cache_.end() && if (token_iterator != token_cache_.end() &&
token_iterator->second.access_token == token_to_remove) { token_iterator->second.access_token == token_to_remove) {
token_cache_.erase(token_iterator); token_cache_.erase(token_iterator);
return true; return true;
......
...@@ -148,12 +148,6 @@ class OAuth2TokenService { ...@@ -148,12 +148,6 @@ class OAuth2TokenService {
Consumer* const consumer_; Consumer* const consumer_;
}; };
// Informs the consumer of |request| fetch results.
static void InformConsumer(base::WeakPtr<RequestImpl> request,
const GoogleServiceAuthError& error,
const std::string& access_token,
const base::Time& expiration_date);
private: private:
// Class that fetches an OAuth2 access token for a given set of scopes and // Class that fetches an OAuth2 access token for a given set of scopes and
// OAuth2 refresh token. // OAuth2 refresh token.
......
...@@ -404,7 +404,7 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) { ...@@ -404,7 +404,7 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) {
EXPECT_EQ(0, consumer.number_of_errors_); EXPECT_EQ(0, consumer.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher); ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_UNAUTHORIZED); fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string()); fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher); fetcher->delegate()->OnURLFetchComplete(fetcher);
...@@ -412,10 +412,59 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) { ...@@ -412,10 +412,59 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) {
EXPECT_EQ(1, consumer.number_of_errors_); EXPECT_EQ(1, consumer.number_of_errors_);
fetcher = factory_.GetFetcherByID(0); fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher); ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_UNAUTHORIZED); fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string()); fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher); fetcher->delegate()->OnURLFetchComplete(fetcher);
EXPECT_EQ(0, consumer.number_of_successful_tokens_); EXPECT_EQ(0, consumer.number_of_successful_tokens_);
EXPECT_EQ(2, consumer.number_of_errors_); EXPECT_EQ(2, consumer.number_of_errors_);
} }
TEST_F(OAuth2TokenServiceTest, InvalidateToken) {
std::set<std::string> scopes;
oauth2_service_->set_refresh_token("refreshToken");
// First request.
scoped_ptr<OAuth2TokenService::Request> request(
oauth2_service_->StartRequest(scopes, &consumer_));
message_loop_.RunUntilIdle();
EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
// Second request, should return the same token without needing a network
// request.
scoped_ptr<OAuth2TokenService::Request> request2(
oauth2_service_->StartRequest(scopes, &consumer_));
message_loop_.RunUntilIdle();
// No new network fetcher.
EXPECT_EQ(fetcher, factory_.GetFetcherByID(0));
EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
// Invalidating the token should return a new token on the next request.
oauth2_service_->InvalidateToken(scopes, consumer_.last_token_);
scoped_ptr<OAuth2TokenService::Request> request3(
oauth2_service_->StartRequest(scopes, &consumer_));
message_loop_.RunUntilIdle();
EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token2", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
EXPECT_EQ(3, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token2", consumer_.last_token_);
}
...@@ -965,6 +965,8 @@ ...@@ -965,6 +965,8 @@
'browser/managed_mode/managed_user_service.h', 'browser/managed_mode/managed_user_service.h',
'browser/managed_mode/managed_user_service_factory.cc', 'browser/managed_mode/managed_user_service_factory.cc',
'browser/managed_mode/managed_user_service_factory.h', 'browser/managed_mode/managed_user_service_factory.h',
'browser/managed_mode/managed_user_refresh_token_fetcher.cc',
'browser/managed_mode/managed_user_refresh_token_fetcher.h',
'browser/media/audio_stream_indicator.cc', 'browser/media/audio_stream_indicator.cc',
'browser/media/audio_stream_indicator.h', 'browser/media/audio_stream_indicator.h',
'browser/media/media_capture_devices_dispatcher.cc', 'browser/media/media_capture_devices_dispatcher.cc',
......
...@@ -915,6 +915,7 @@ ...@@ -915,6 +915,7 @@
'browser/managed_mode/managed_user_passphrase_unittest.cc', 'browser/managed_mode/managed_user_passphrase_unittest.cc',
'browser/managed_mode/managed_user_registration_service_unittest.cc', 'browser/managed_mode/managed_user_registration_service_unittest.cc',
'browser/managed_mode/managed_user_service_unittest.cc', 'browser/managed_mode/managed_user_service_unittest.cc',
'browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc',
'browser/media_galleries/fileapi/itunes_finder_win_unittest.cc', 'browser/media_galleries/fileapi/itunes_finder_win_unittest.cc',
'browser/media_galleries/fileapi/native_media_file_util_unittest.cc', 'browser/media_galleries/fileapi/native_media_file_util_unittest.cc',
'browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc', 'browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc',
......
...@@ -203,7 +203,7 @@ void GaiaOAuthClient::Core::HandleResponse( ...@@ -203,7 +203,7 @@ void GaiaOAuthClient::Core::HandleResponse(
// If we don't have an access token yet and the the error was not // If we don't have an access token yet and the the error was not
// RC_BAD_REQUEST, we may need to retry. // RC_BAD_REQUEST, we may need to retry.
if ((source->GetMaxRetriesOn5xx() != -1) && if ((source->GetMaxRetriesOn5xx() != -1) &&
(num_retries_ > source->GetMaxRetriesOn5xx())) { (num_retries_ >= source->GetMaxRetriesOn5xx())) {
// Retry limit reached. Give up. // Retry limit reached. Give up.
delegate_->OnNetworkError(source->GetResponseCode()); delegate_->OnNetworkError(source->GetResponseCode());
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment