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
if (robot_auth_fetch_status_ == DM_STATUS_SUCCESS) {
net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0);
ASSERT_TRUE(url_fetcher);
// The logic in GaiaOAuthClient seems broken, it always retries 1x on
// 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->SetMaxRetriesOn5xx(0);
url_fetcher->set_status(net::URLRequestStatus());
url_fetcher->set_response_code(url_fetcher_response_code_);
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.
#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_
......@@ -9,11 +9,14 @@
#include "base/prefs/pref_service.h"
#include "base/rand_util.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_factory.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 "components/user_prefs/pref_registry_syncable.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "sync/api/sync_change.h"
#include "sync/api/sync_error_factory.h"
......@@ -52,9 +55,11 @@ SyncData CreateLocalSyncData(const std::string& id,
} // namespace
ManagedUserRegistrationService::ManagedUserRegistrationService(
PrefService* prefs)
PrefService* prefs,
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher)
: weak_ptr_factory_(this),
prefs_(prefs),
token_fetcher_(token_fetcher.Pass()),
pending_managed_user_acknowledged_(false) {
pref_change_registrar_.Init(prefs);
pref_change_registrar_.Add(
......@@ -103,7 +108,9 @@ void ManagedUserRegistrationService::Register(
}
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
......@@ -268,8 +275,24 @@ void ManagedUserRegistrationService::OnManagedUserAcknowledged(
DispatchCallbackIfReady();
}
void ManagedUserRegistrationService::OnReceivedToken(const std::string& token) {
DCHECK(pending_managed_user_token_.empty());
void ManagedUserRegistrationService::FetchToken(
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;
DispatchCallbackIfReady();
}
......
......@@ -17,8 +17,13 @@
#include "sync/api/syncable_service.h"
class GoogleServiceAuthError;
class ManagedUserRefreshTokenFetcher;
class PrefService;
namespace browser_sync {
class DeviceInfo;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
......@@ -37,13 +42,17 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService,
const std::string& /* token */)>
RegistrationCallback;
explicit ManagedUserRegistrationService(PrefService* prefs);
ManagedUserRegistrationService(
PrefService* prefs,
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher);
virtual ~ManagedUserRegistrationService();
static void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry);
// 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.
// TODO(bauerb): There should be a way to cancel a pending managed user
// registration.
void Register(const string16& name, const RegistrationCallback& callback);
// Convenience method that registers a new managed user with the server and
......@@ -77,8 +86,13 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService,
// Called when the Sync server has acknowledged a newly created managed user.
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.
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.
void DispatchCallbackIfReady();
......@@ -94,6 +108,7 @@ class ManagedUserRegistrationService : public BrowserContextKeyedService,
base::WeakPtrFactory<ManagedUserRegistrationService> weak_ptr_factory_;
PrefService* prefs_;
PrefChangeRegistrar pref_change_registrar_;
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher_;
scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
scoped_ptr<syncer::SyncErrorFactory> error_handler_;
......
......@@ -4,7 +4,11 @@
#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/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"
// static
......@@ -23,13 +27,20 @@ ManagedUserRegistrationServiceFactory::GetInstance() {
// static
BrowserContextKeyedService*
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()
: BrowserContextKeyedServiceFactory(
"ManagedUserRegistrationService",
BrowserContextDependencyManager::GetInstance()) {}
BrowserContextDependencyManager::GetInstance()) {
DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
}
ManagedUserRegistrationServiceFactory::
~ManagedUserRegistrationServiceFactory() {}
......
......@@ -5,7 +5,10 @@
#include <string>
#include "base/bind.h"
#include "base/message_loop.h"
#include "base/run_loop.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/prefs/scoped_user_pref_update.h"
#include "chrome/common/pref_names.h"
......@@ -29,6 +32,8 @@ using syncer::SyncMergeResult;
namespace {
const char kManagedUserToken[] = "managedusertoken";
class MockChangeProcessor : public SyncChangeProcessor {
public:
MockChangeProcessor() {}
......@@ -62,6 +67,22 @@ SyncChange MockChangeProcessor::GetChange(const std::string& id) const {
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
class ManagedUserRegistrationServiceTest : public ::testing::Test {
......@@ -94,6 +115,8 @@ class ManagedUserRegistrationServiceTest : public ::testing::Test {
void OnManagedUserRegistered(const GoogleServiceAuthError& error,
const std::string& token);
base::MessageLoop message_loop_;
base::RunLoop run_loop_;
base::WeakPtrFactory<ManagedUserRegistrationServiceTest> weak_ptr_factory_;
TestingPrefServiceSyncable prefs_;
scoped_ptr<ManagedUserRegistrationService> service_;
......@@ -114,12 +137,15 @@ class ManagedUserRegistrationServiceTest : public ::testing::Test {
ManagedUserRegistrationServiceTest::ManagedUserRegistrationServiceTest()
: weak_ptr_factory_(this),
service_(new ManagedUserRegistrationService(&prefs_)),
change_processor_(NULL),
sync_data_id_(0),
received_callback_(false),
error_(GoogleServiceAuthError::NUM_STATES) {
ManagedUserRegistrationService::RegisterUserPrefs(prefs_.registry());
scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher(
new MockManagedUserRefreshTokenFetcher);
service_.reset(
new ManagedUserRegistrationService(&prefs_, token_fetcher.Pass()));
}
ManagedUserRegistrationServiceTest::~ManagedUserRegistrationServiceTest() {
......@@ -180,6 +206,8 @@ void ManagedUserRegistrationServiceTest::Acknowledge() {
SyncData::CreateRemoteData(++sync_data_id_, specifics)));
}
service()->ProcessSyncChanges(FROM_HERE, new_changes);
run_loop_.Run();
}
void ManagedUserRegistrationServiceTest::ResetService() {
......@@ -194,6 +222,7 @@ void ManagedUserRegistrationServiceTest::OnManagedUserRegistered(
received_callback_ = true;
error_ = error;
token_ = token;
run_loop_.Quit();
}
TEST_F(ManagedUserRegistrationServiceTest, MergeEmpty) {
......
......@@ -33,7 +33,7 @@ scoped_ptr<OAuth2TokenService::Request>
ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid();
sync_service->FetchOAuth2Token(
scope_list.front(),
base::Bind(&OAuth2TokenService::InformConsumer,
base::Bind(&RequestImpl::InformConsumer,
request->AsWeakPtr()));
return request.PassAs<Request>();
}
......
......@@ -303,18 +303,6 @@ bool OAuth2TokenService::RefreshTokenIsAvailable() {
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(
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer) {
......@@ -325,7 +313,7 @@ scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
std::string refresh_token = GetRefreshToken();
if (refresh_token.empty()) {
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&OAuth2TokenService::InformConsumer,
&RequestImpl::InformConsumer,
request->AsWeakPtr(),
GoogleServiceAuthError(
GoogleServiceAuthError::USER_NOT_SIGNED_UP),
......@@ -361,7 +349,7 @@ scoped_ptr<OAuth2TokenService::Request>
const CacheEntry* cache_entry = GetCacheEntry(scopes);
scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&OAuth2TokenService::InformConsumer,
&RequestImpl::InformConsumer,
request->AsWeakPtr(),
GoogleServiceAuthError(GoogleServiceAuthError::NONE),
cache_entry->access_token,
......@@ -440,7 +428,7 @@ bool OAuth2TokenService::RemoveCacheEntry(
const std::string& token_to_remove) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
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_cache_.erase(token_iterator);
return true;
......
......@@ -148,12 +148,6 @@ class OAuth2TokenService {
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:
// Class that fetches an OAuth2 access token for a given set of scopes and
// OAuth2 refresh token.
......
......@@ -404,7 +404,7 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) {
EXPECT_EQ(0, consumer.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher);
......@@ -412,10 +412,59 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) {
EXPECT_EQ(1, consumer.number_of_errors_);
fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher);
EXPECT_EQ(0, consumer.number_of_successful_tokens_);
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 @@
'browser/managed_mode/managed_user_service.h',
'browser/managed_mode/managed_user_service_factory.cc',
'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.h',
'browser/media/media_capture_devices_dispatcher.cc',
......
......@@ -915,6 +915,7 @@
'browser/managed_mode/managed_user_passphrase_unittest.cc',
'browser/managed_mode/managed_user_registration_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/native_media_file_util_unittest.cc',
'browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc',
......
......@@ -203,7 +203,7 @@ void GaiaOAuthClient::Core::HandleResponse(
// If we don't have an access token yet and the the error was not
// RC_BAD_REQUEST, we may need to retry.
if ((source->GetMaxRetriesOn5xx() != -1) &&
(num_retries_ > source->GetMaxRetriesOn5xx())) {
(num_retries_ >= source->GetMaxRetriesOn5xx())) {
// Retry limit reached. Give up.
delegate_->OnNetworkError(source->GetResponseCode());
} 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