// Copyright (c) 2011 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 to call ClientLogin to derive a new SID and
// LSID. 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())
// }
// }
#ifndef CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
#define CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
#pragma once
#include <map>
#include <string>
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
class Profile;
namespace net {
class URLRequestContextGetter;
}
// The TokenService is a Profile member, so all calls are expected
// from the UI thread.
class TokenService : public GaiaAuthConsumer,
public WebDataServiceConsumer,
public NotificationObserver {
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_;
};
// 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);
// Update the credentials in the token service.
// Afterwards you can StartFetchingTokens.
void UpdateCredentials(
const GaiaAuthConsumer::ClientLoginResult& 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.
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();
// For legacy services with their own auth routines, they can just read
// the LSID out directly. Deprecated.
bool HasLsid() const;
const std::string& GetLsid() const;
// Did we get a proper LSID?
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();
bool HasTokenForService(const char* const service) const;
const std::string& GetTokenForService(const char* const service) 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);
virtual void OnIssueAuthTokenFailure(const std::string& service,
const GoogleServiceAuthError& error);
// WebDataServiceConsumer implementation.
virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
const WDTypedResult* result);
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
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>& in_toks,
std::map<std::string, std::string>* out_toks);
void SaveAuthTokenToDB(const std::string& service,
const std::string& auth_token);
// Web data service to access tokens from.
scoped_refptr<WebDataService> web_data_service_;
// Getter to use for fetchers.
scoped_refptr<net::URLRequestContextGetter> getter_;
// Request handle to load Gaia tokens from DB.
WebDataService::Handle token_loading_query_;
// Gaia request source for Gaia accounting.
std::string source_;
// Credentials from ClientLogin for Issuing auth tokens.
GaiaAuthConsumer::ClientLoginResult credentials_;
// Size of array of services (must be defined here).
static const int kNumServices = 4;
// List of services that we're performing operations for.
static const char* kServices[kNumServices];
// A bunch of fetchers suitable for token issuing. We don't care about
// the ordering, nor do we care which is for which service.
scoped_ptr<GaiaAuthFetcher> fetchers_[kNumServices];
// Map from service to token.
std::map<std::string, std::string> token_map_;
NotificationRegistrar registrar_;
FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryBasic);
FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryAdvanced);
DISALLOW_COPY_AND_ASSIGN(TokenService);
};
#endif // CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_