blob: d064796a2306e72f6719a0b049b3d0a5fdb9a64f [file] [log] [blame]
// Copyright (c) 2012 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.
//
// The TokenService will supply authentication tokens for any service that
// needs it, such as sync. Whenever the user logs in, a controller watching
// the token service is expected either to call ClientLogin to derive a new
// SID and LSID, or to use GAIA OAuth requests to derive an OAuth1 access
// token for the OAuthLogin scope. Whenever such credentials are available,
// the TokenService should be updated with new credentials. The controller
// should then start fetching tokens, which will be written to the database
// after retrieval, as well as provided to listeners.
//
// A token service controller like the ChromiumOS login is expected to:
//
// Initialize() // Soon as you can
// LoadTokensFromDB() // When it's OK to talk to the database
// UpdateCredentials() // When user logs in
// StartFetchingTokens() // When it's safe to start fetching
//
// Typically a user of the TokenService is expected just to call:
//
// if (token_service.HasTokenForService(servicename)) {
// SetMyToken(token_service.GetTokenForService(servicename));
// }
// RegisterSomeObserver(token_service);
//
// Whenever a token update occurs:
// OnTokenAvailable(...) {
// if (IsServiceICareAbout(notification.service())) {
// SetMyToken(notification.token())
// }
// }
//
// There is currently no easy way to create a fake TokenService. Tests that want
// to use TokenService to issue tokens without the use of fake GaiaAuthFetchers
// or persisting the tokens to disk via WebDataService can do this by
// creating a TokenService (skipping the Initialize() step to avoid interacting
// with WebDataService) and calling IssueAuthTokenForTest() to issue new tokens.
// This will result in the TokenService sending out the appropriate
// TOKEN_AVAILABLE notification and returning the correct response to future
// calls to Has/GetTokenForService().
#ifndef CHROME_BROWSER_SIGNIN_TOKEN_SERVICE_H_
#define CHROME_BROWSER_SIGNIN_TOKEN_SERVICE_H_
#include <map>
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "chrome/browser/signin/signin_internals_util.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "components/webdata/common/web_data_service_base.h"
#include "components/webdata/common/web_data_service_consumer.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/google_service_auth_error.h"
class Profile;
class TokenServiceTest;
class TokenWebData;
namespace net {
class URLRequestContextGetter;
}
// The TokenService is a Profile member, so all calls are expected
// from the UI thread.
class TokenService : public GaiaAuthConsumer,
public BrowserContextKeyedService,
public WebDataServiceConsumer {
public:
TokenService();
virtual ~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()
: error_(GoogleServiceAuthError::NONE) {}
TokenRequestFailedDetails(const std::string& service,
const GoogleServiceAuthError& error)
: service_(service), error_(error) {}
const std::string& service() const { return service_; }
const GoogleServiceAuthError& error() const { return error_; }
private:
std::string service_;
GoogleServiceAuthError error_;
};
// BrowserContextKeyedService implementation.
virtual void Shutdown() OVERRIDE;
// Methods to register or remove SigninDiagnosticObservers
void AddSigninDiagnosticsObserver(
signin_internals_util::SigninDiagnosticsObserver* observer);
void RemoveSigninDiagnosticsObserver(
signin_internals_util::SigninDiagnosticsObserver* observer);
// Initialize this token service with a request source
// (usually from a GaiaAuthConsumer constant), and the profile.
// Typically you'd then update the credentials.
void Initialize(const char* const source, Profile* profile);
// Used to determine whether Initialize() has been called.
bool Initialized() const { return !source_.empty(); }
// Add a token not supported by a fetcher.
void AddAuthTokenManually(const std::string& service,
const std::string& auth_token);
// Update ClientLogin credentials in the token service.
// Afterwards you can StartFetchingTokens.
void UpdateCredentials(
const GaiaAuthConsumer::ClientLoginResult& credentials);
// Update credentials in the token service with oauth2 tokens.
// Afterwards you can StartFetchingTokens.
void UpdateCredentialsWithOAuth2(
const GaiaAuthConsumer::ClientOAuthResult& credentials);
// Terminate any running requests and reset the TokenService to a clean
// slate. Resets in memory structures. Does not modify the DB.
// When this is done, no tokens will be left in memory and no
// user credentials will be left. Useful if a user is logging out.
// Initialize doesn't need to be called again but UpdateCredentials does.
void ResetCredentialsInMemory();
// Async load all tokens for services we know of from the DB.
// You should do this at startup. Optionally you can do it again
// after you reset in memory credentials.
virtual void LoadTokensFromDB();
// Clear all DB stored tokens for the current profile. Tokens may still be
// available in memory. If a DB load is pending it may still be serviced.
void EraseTokensFromDB();
// Returns true if tokens have been loaded from the DB. Set when
// LoadTokensFromDB() completes, unset when ResetCredentialsInMemory() is
// called.
bool TokensLoadedFromDB() const;
// Returns true if the token service has either GAIA credentials or OAuth2
// tokens needed to fetch other service tokens.
virtual bool AreCredentialsValid() const;
// Tokens will be fetched for all services(sync, talk) in the background.
// Results come back via event channel. Services can also poll before events
// are issued.
void StartFetchingTokens();
virtual bool HasTokenForService(const char* service) const;
const std::string& GetTokenForService(const char* const service) const;
// OAuth login token is an all-powerful token that allows creating OAuth2
// tokens for any other scope (i.e. down-scoping).
// Typical use is to create an OAuth2 token for appropriate scope and then
// use that token to call a Google API.
virtual bool HasOAuthLoginToken() const;
virtual const std::string& GetOAuth2LoginRefreshToken() const;
// For tests only. Doesn't save to the WebDB.
void IssueAuthTokenForTest(const std::string& service,
const std::string& auth_token);
// GaiaAuthConsumer implementation.
virtual void OnIssueAuthTokenSuccess(const std::string& service,
const std::string& auth_token) OVERRIDE;
virtual void OnIssueAuthTokenFailure(
const std::string& service,
const GoogleServiceAuthError& error) OVERRIDE;
virtual void OnClientOAuthSuccess(const ClientOAuthResult& result) OVERRIDE;
virtual void OnClientOAuthFailure(
const GoogleServiceAuthError& error) OVERRIDE;
// WebDataServiceConsumer implementation.
virtual void OnWebDataServiceRequestDone(
WebDataServiceBase::Handle h,
const WDTypedResult* result) OVERRIDE;
// Gets the list of all service names for which tokens will be retrieved.
static void GetServiceNames(std::vector<std::string>* names);
protected:
// Saves OAuth2 credentials.
void SaveOAuth2Credentials(const ClientOAuthResult& result);
void set_tokens_loaded(bool loaded) {
tokens_loaded_ = loaded;
}
private:
void FireTokenAvailableNotification(const std::string& service,
const std::string& auth_token);
void FireTokenRequestFailedNotification(const std::string& service,
const GoogleServiceAuthError& error);
void LoadTokensIntoMemory(
const std::map<std::string, std::string>& db_tokens,
std::map<std::string, std::string>* in_memory_tokens);
void LoadSingleTokenIntoMemory(
const std::map<std::string, std::string>& db_tokens,
std::map<std::string, std::string>* in_memory_tokens,
const std::string& service);
void SaveAuthTokenToDB(const std::string& service,
const std::string& auth_token);
// Returns the index of the given service.
static int GetServiceIndex(const std::string& service);
// The profile with which this instance was initialized, or NULL.
Profile* profile_;
// Web data service to access tokens from.
scoped_refptr<TokenWebData> token_web_data_;
// Getter to use for fetchers.
scoped_refptr<net::URLRequestContextGetter> getter_;
// Request handle to load Gaia tokens from DB.
WebDataServiceBase::Handle token_loading_query_;
// True if token loading has completed (regardless of success).
bool tokens_loaded_;
// Gaia request source for Gaia accounting.
std::string source_;
// Credentials from ClientLogin for Issuing auth tokens.
GaiaAuthConsumer::ClientLoginResult credentials_;
// A bunch of fetchers suitable for ClientLogin token issuing. We don't care
// about the ordering, nor do we care which is for which service. The
// number of entries in this array must match the number of entries in the
// kServices array declared in the cc file. If not, a compile time error
// will occur.
scoped_ptr<GaiaAuthFetcher> fetchers_[1];
// Map from service to token.
std::map<std::string, std::string> token_map_;
// The list of SigninDiagnosticObservers
ObserverList<signin_internals_util::SigninDiagnosticsObserver>
signin_diagnostics_observers_;
friend class TokenServiceTest;
FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryBasic);
FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryAdvanced);
FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, FullIntegrationNewServicesAdded);
DISALLOW_COPY_AND_ASSIGN(TokenService);
};
#endif // CHROME_BROWSER_SIGNIN_TOKEN_SERVICE_H_