summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorchron@chromium.org <chron@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-28 21:44:43 +0000
committerchron@chromium.org <chron@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-28 21:44:43 +0000
commit5de3c6834b77d8b3eeec7b5d7175a2ab246ea234 (patch)
treed07b8ff32badac7913311f67bf1354403fea0f35 /chrome/browser
parentc9206275ca3f57888fcf9da96c647d8fcf67ff3f (diff)
downloadchromium_src-5de3c6834b77d8b3eeec7b5d7175a2ab246ea234.zip
chromium_src-5de3c6834b77d8b3eeec7b5d7175a2ab246ea234.tar.gz
chromium_src-5de3c6834b77d8b3eeec7b5d7175a2ab246ea234.tar.bz2
The token service should now support issuing auth tokens.
The service will fetch tokens in the background and broadcast notifications after it's done. Move some common constants out into a new file. Modify TestNotificationTracker to support subclassing as it doesn't properly make a deep copy of notifications on the stack. TEST=unit tests included BUG=47093 Review URL: http://codereview.chromium.org/3024002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54028 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.cc5
-rw-r--r--chrome/browser/chromeos/login/google_authenticator_unittest.cc1
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc5
-rw-r--r--chrome/browser/net/gaia/token_service.cc67
-rw-r--r--chrome/browser/net/gaia/token_service.h87
-rw-r--r--chrome/browser/net/gaia/token_service_unittest.cc172
-rw-r--r--chrome/browser/sync/profile_sync_service_startup_unittest.cc5
7 files changed, 324 insertions, 18 deletions
diff --git a/chrome/browser/chromeos/login/google_authenticator.cc b/chrome/browser/chromeos/login/google_authenticator.cc
index fe8de56..bd4c027 100644
--- a/chrome/browser/chromeos/login/google_authenticator.cc
+++ b/chrome/browser/chromeos/login/google_authenticator.cc
@@ -26,6 +26,7 @@
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/gaia/gaia_authenticator2.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_service.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -79,7 +80,7 @@ void GoogleAuthenticator::CancelClientLogin() {
void GoogleAuthenticator::TryClientLogin() {
gaia_authenticator_->StartClientLogin(username_,
password_,
- GaiaAuthenticator2::kContactsService,
+ GaiaConstants::kContactsService,
login_token_,
login_captcha_);
ChromeThread::PostDelayedTask(
@@ -122,7 +123,7 @@ bool GoogleAuthenticator::AuthenticateToLogin(
gaia_authenticator_.reset(
new GaiaAuthenticator2(this,
- GaiaAuthenticator2::kChromeOSSource,
+ GaiaConstants::kChromeOSSource,
profile->GetRequestContext()));
// Will be used for retries.
PrepareClientLoginAttempt(password, login_token, login_captcha);
diff --git a/chrome/browser/chromeos/login/google_authenticator_unittest.cc b/chrome/browser/chromeos/login/google_authenticator_unittest.cc
index 4676ff0..9f372b6 100644
--- a/chrome/browser/chromeos/login/google_authenticator_unittest.cc
+++ b/chrome/browser/chromeos/login/google_authenticator_unittest.cc
@@ -56,6 +56,7 @@ class ExpectCanceledFetcher : public URLFetcher {
public:
ExpectCanceledFetcher(bool success,
const GURL& url,
+ const std::string& results,
URLFetcher::RequestType request_type,
URLFetcher::Delegate* d)
: URLFetcher(url, request_type, d) {
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index 6e80423..5b0b284 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -29,6 +29,7 @@
#include "chrome/common/logging_chrome.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -153,7 +154,9 @@ void LoginUtilsImpl::CompleteLogin(const std::string& username,
logging::DELETE_OLD_LOG_FILE);
// Supply credentials for sync and others to use
- profile->GetTokenService()->SetClientLoginResult(credentials);
+ profile->GetTokenService()->Initialize(GaiaConstants::kChromeOSSource,
+ profile->GetRequestContext(),
+ credentials);
// Take the credentials passed in and try to exchange them for
// full-fledged Google authentication cookies. This is
diff --git a/chrome/browser/net/gaia/token_service.cc b/chrome/browser/net/gaia/token_service.cc
index f514bf7..8420fb2 100644
--- a/chrome/browser/net/gaia/token_service.cc
+++ b/chrome/browser/net/gaia/token_service.cc
@@ -4,15 +4,76 @@
#include "chrome/browser/net/gaia/token_service.h"
-void TokenService::SetClientLoginResult(
+#include "base/string_util.h"
+#include "chrome/common/net/gaia/gaia_authenticator2.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
+#include "chrome/common/notification_service.h"
+
+void TokenService::Initialize(
+ const char* const source,
+ URLRequestContextGetter* getter,
const GaiaAuthConsumer::ClientLoginResult& credentials) {
+
credentials_ = credentials;
+ source_ = std::string(source);
+ sync_token_fetcher_.reset(new GaiaAuthenticator2(this, source_, getter));
+ talk_token_fetcher_.reset(new GaiaAuthenticator2(this, source_, getter));
+}
+
+const bool TokenService::AreCredentialsValid() const {
+ return !credentials_.lsid.empty() && !credentials_.sid.empty();
}
-bool TokenService::HasLsid() {
+const bool TokenService::HasLsid() const {
return !credentials_.lsid.empty();
}
-const std::string& TokenService::GetLsid() {
+const std::string& TokenService::GetLsid() const {
return credentials_.lsid;
}
+
+void TokenService::StartFetchingTokens() {
+ DCHECK(AreCredentialsValid());
+ sync_token_fetcher_->StartIssueAuthToken(credentials_.sid,
+ credentials_.lsid,
+ GaiaConstants::kSyncService);
+ talk_token_fetcher_->StartIssueAuthToken(credentials_.sid,
+ credentials_.lsid,
+ GaiaConstants::kTalkService);
+}
+
+// Services dependent on a token will check if a token is available.
+// If it isn't, they'll go to sleep until they get a token event.
+const bool TokenService::HasTokenForService(const char* const service) const {
+ return token_map_.count(service) > 0;
+}
+
+const std::string& TokenService::GetTokenForService(
+ const char* const service) const {
+
+ if (token_map_.count(service) > 0) {
+ // map[key] is not const
+ return (*token_map_.find(service)).second;
+ }
+ return EmptyString();
+}
+
+void TokenService::OnIssueAuthTokenSuccess(const std::string& service,
+ const std::string& auth_token) {
+ LOG(INFO) << "Got an authorization token for " << service;
+ token_map_[service] = auth_token;
+ TokenAvailableDetails details(service, auth_token);
+ NotificationService::current()->Notify(
+ NotificationType::TOKEN_AVAILABLE,
+ Source<TokenService>(this),
+ Details<const TokenAvailableDetails>(&details));
+}
+void TokenService::OnIssueAuthTokenFailure(const std::string& service,
+ const GaiaAuthError& error) {
+ LOG(WARNING) << "Auth token issuing failed for service:" << service;
+ TokenRequestFailedDetails details(service, error);
+ NotificationService::current()->Notify(
+ NotificationType::TOKEN_REQUEST_FAILED,
+ Source<TokenService>(this),
+ Details<const TokenRequestFailedDetails>(&details));
+}
diff --git a/chrome/browser/net/gaia/token_service.h b/chrome/browser/net/gaia/token_service.h
index 4705e69..bad80f5 100644
--- a/chrome/browser/net/gaia/token_service.h
+++ b/chrome/browser/net/gaia/token_service.h
@@ -3,30 +3,95 @@
// found in the LICENSE file.
//
// The TokenService will supply authentication tokens for any service that
-// needs it. One such service is Sync.
-// For the time being, the Token Service just supplies the LSID from the
-// ChromiumOS login. In the future, it'll have a bit more logic and supply
-// only AuthTokens from Gaia, and not LSIDs.
+// needs it, such as sync.
#ifndef CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
#define CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
#pragma once
+#include <map>
+#include <string>
+#include "base/scoped_ptr.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/net/gaia/gaia_authenticator2.h"
+#include "chrome/test/testing_profile.h"
-class TokenService {
+class URLRequestContextGetter;
+
+// The TokenService is a Profile member, so all calls are expected
+// from the UI thread.
+class TokenService : public GaiaAuthConsumer {
public:
- void SetClientLoginResult(
- const GaiaAuthConsumer::ClientLoginResult& credentials);
+ TokenService() {}
+
+ // Notification classes
+ class TokenAvailableDetails {
+ public:
+ TokenAvailableDetails() {}
+ TokenAvailableDetails(const std::string& service,
+ const std::string& token)
+ : service_(service), token_(token) {}
+ const std::string& service() const { return service_; }
+ const std::string& token() const { return token_; }
+ private:
+ std::string service_;
+ std::string token_;
+ };
+
+ class TokenRequestFailedDetails {
+ public:
+ TokenRequestFailedDetails() {}
+ TokenRequestFailedDetails(const std::string& service,
+ const GaiaAuthError& error)
+ : service_(service), error_(error) {}
+ const std::string& service() const { return service_; }
+ const GaiaAuthError& error() const { return error_; }
+ private:
+ std::string service_;
+ GaiaAuthError error_;
+ };
+
+ // Initialize this token service with a request source
+ // (usually from a GaiaAuthConsumer constant), a getter and
+ // results from ClientLogin.
+ void Initialize(
+ const char* const source,
+ URLRequestContextGetter* getter,
+ const GaiaAuthConsumer::ClientLoginResult& credentials);
- bool HasLsid();
- const std::string& GetLsid();
+ // For legacy services with their own auth routines, they can just read
+ // the LSID out directly. Deprecated.
+ const bool HasLsid() const;
+ const std::string& GetLsid() const;
- // TODO(chron): Token broadcast will require removing a lot of auth code
- // from sync. For the time being we'll start with LSID passing.
+ // On login, StartFetchingTokens() should be called to kick off token
+ // fetching.
+ // Tokens will be fetched for all services(sync, talk) in the background.
+ // Results come back via event channel. Services can also poll.
+ void StartFetchingTokens();
+ const bool HasTokenForService(const char* const service) const;
+ const std::string& GetTokenForService(const char* const service) const;
+
+ // Callbacks from the fetchers.
+ void OnIssueAuthTokenSuccess(const std::string& service,
+ const std::string& auth_token);
+ void OnIssueAuthTokenFailure(const std::string& service,
+ const GaiaAuthError& error);
private:
+ // Did we get a proper LSID?
+ const bool AreCredentialsValid() const;
+
+ // Gaia request source for Gaia accounting.
+ std::string source_;
+ // Credentials from ClientLogin for Issuing auth tokens.
GaiaAuthConsumer::ClientLoginResult credentials_;
+ scoped_ptr<GaiaAuthenticator2> sync_token_fetcher_;
+ scoped_ptr<GaiaAuthenticator2> talk_token_fetcher_;
+ // Map from service to token.
+ std::map<std::string, std::string> token_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(TokenService);
};
#endif // CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
diff --git a/chrome/browser/net/gaia/token_service_unittest.cc b/chrome/browser/net/gaia/token_service_unittest.cc
new file mode 100644
index 0000000..0bd7e56
--- /dev/null
+++ b/chrome/browser/net/gaia/token_service_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2010 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.
+//
+// This file defines a unit test for the profile's token service.
+
+#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/common/net/gaia/gaia_authenticator2_unittest.h"
+#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "chrome/test/test_notification_tracker.h"
+
+// TestNotificationTracker doesn't do a deep copy on the notification details.
+// We have to in order to read it out, or we have a bad ptr, since the details
+// are a reference on the stack.
+class TokenAvailableTracker : public TestNotificationTracker {
+ public:
+ const TokenService::TokenAvailableDetails& get_last_token_details() {
+ return details_;
+ }
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ TestNotificationTracker::Observe(type, source, details);
+ if (type == NotificationType::TOKEN_AVAILABLE) {
+ Details<const TokenService::TokenAvailableDetails> full = details;
+ details_ = *full.ptr();
+ }
+ }
+
+ TokenService::TokenAvailableDetails details_;
+};
+
+class TokenFailedTracker : public TestNotificationTracker {
+ public:
+ const TokenService::TokenRequestFailedDetails& get_last_token_details() {
+ return details_;
+ }
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ TestNotificationTracker::Observe(type, source, details);
+ if (type == NotificationType::TOKEN_REQUEST_FAILED) {
+ Details<const TokenService::TokenRequestFailedDetails> full = details;
+ details_ = *full.ptr();
+ }
+ }
+
+ TokenService::TokenRequestFailedDetails details_;
+};
+
+class TokenServiceTest : public testing::Test {
+ public:
+ TokenServiceTest() {
+ credentials_.sid = "sid";
+ credentials_.lsid = "lsid";
+ credentials_.token = "token";
+ credentials_.data = "data";
+
+ success_tracker_.ListenFor(NotificationType::TOKEN_AVAILABLE,
+ Source<TokenService>(&service_));
+ failure_tracker_.ListenFor(NotificationType::TOKEN_REQUEST_FAILED,
+ Source<TokenService>(&service_));
+
+ service_.Initialize("test", profile_.GetRequestContext(), credentials_);
+ }
+
+ TokenService service_;
+ TokenAvailableTracker success_tracker_;
+ TokenFailedTracker failure_tracker_;
+ GaiaAuthConsumer::ClientLoginResult credentials_;
+
+ private:
+ TestingProfile profile_;
+};
+
+TEST_F(TokenServiceTest, SanityCheck) {
+ EXPECT_TRUE(service_.HasLsid());
+ EXPECT_EQ(service_.GetLsid(), "lsid");
+ EXPECT_FALSE(service_.HasTokenForService("nonexistant service"));
+}
+
+TEST_F(TokenServiceTest, NoToken) {
+ EXPECT_FALSE(service_.HasTokenForService("nonexistant service"));
+ EXPECT_EQ(service_.GetTokenForService("nonexistant service"), std::string());
+}
+
+TEST_F(TokenServiceTest, NotificationSuccess) {
+ EXPECT_EQ(0U, success_tracker_.size());
+ EXPECT_EQ(0U, failure_tracker_.size());
+ service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
+ EXPECT_EQ(1U, success_tracker_.size());
+ EXPECT_EQ(0U, failure_tracker_.size());
+
+ TokenService::TokenAvailableDetails details =
+ success_tracker_.get_last_token_details();
+ // MSVC doesn't like this comparison as EQ
+ EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
+ EXPECT_EQ(details.token(), "token");
+}
+
+TEST_F(TokenServiceTest, NotificationFailed) {
+ EXPECT_EQ(0U, success_tracker_.size());
+ EXPECT_EQ(0U, failure_tracker_.size());
+ GaiaAuthConsumer::GaiaAuthError error;
+ error.code = GaiaAuthConsumer::REQUEST_CANCELED;
+ service_.OnIssueAuthTokenFailure(GaiaConstants::kSyncService, error);
+ EXPECT_EQ(0U, success_tracker_.size());
+ EXPECT_EQ(1U, failure_tracker_.size());
+
+ TokenService::TokenRequestFailedDetails details =
+ failure_tracker_.get_last_token_details();
+
+ // MSVC doesn't like this comparison as EQ
+ EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
+ EXPECT_TRUE(details.error() == error); // Struct has no print function
+}
+
+TEST_F(TokenServiceTest, OnTokenSuccessUpdate) {
+ service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
+ EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token");
+
+ service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token2");
+ EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token2");
+
+ service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "");
+ EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "");
+}
+
+TEST_F(TokenServiceTest, OnTokenSuccess) {
+ // Don't "start fetching", just go ahead and issue the callback.
+ service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
+ EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
+ EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
+ // Gaia returns the entire result as the token so while this is a shared
+ // result with ClientLogin, it doesn't matter, we should still get it back.
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token");
+
+ // Check 2nd service
+ service_.OnIssueAuthTokenSuccess(GaiaConstants::kTalkService, "token2");
+ EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kTalkService));
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kTalkService), "token2");
+
+ // Didn't change
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token");
+}
+
+TEST_F(TokenServiceTest, FullIntegration) {
+ MockFactory<MockFetcher> factory;
+ std::string result = "SID=sid\nLSID=lsid\nAuth=auth\n";
+ factory.set_results(result);
+ URLFetcher::set_factory(&factory);
+ EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kSyncService));
+ EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
+ service_.StartFetchingTokens();
+ URLFetcher::set_factory(NULL);
+
+ EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
+ EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kTalkService));
+ // Gaia returns the entire result as the token so while this is a shared
+ // result with ClientLogin, it doesn't matter, we should still get it back.
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), result);
+ EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kTalkService), result);
+}
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index a9d7944..f49354d 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -203,7 +203,10 @@ TEST_F(ProfileSyncServiceStartupBootstrapTest, SKIP_MACOSX(StartFirstTime)) {
GaiaAuthConsumer::ClientLoginResult result;
result.sid = "sid";
result.lsid = "lsid";
- profile_.GetTokenService()->SetClientLoginResult(result);
+ profile_.GetTokenService()->Initialize("test",
+ profile_.GetRequestContext(),
+ result);
+
// Will start sync even though setup hasn't been completed (since
// setup is bypassed when bootstrapping is enabled).
service_->Initialize();