1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/gaia/token_service.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h"
114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/net/gaia/gaia_constants.h"
13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/url_request/url_request_context_getter.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Unfortunately kNumServices must be defined in the .h.
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(chron): Sync doesn't use the TalkToken anymore so we can stop
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick//              requesting it.
20513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst char* TokenService::kServices[] = {
21513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GaiaConstants::kGaiaService,
22513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GaiaConstants::kSyncService,
23513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GaiaConstants::kTalkService,
24513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GaiaConstants::kDeviceManagementService
25513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
26513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTokenService::TokenService()
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : token_loading_query_(0) {
29731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTokenService::~TokenService() {
33731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ResetCredentialsInMemory();
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::Initialize(const char* const source,
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              Profile* profile) {
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!source_.empty()) {
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Already initialized.
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  getter_ = profile->GetRequestContext();
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Since the user can create a bookmark in incognito, sync may be running.
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Thus we have to go for explicit access.
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  web_data_service_ = profile->GetWebDataService(Profile::EXPLICIT_ACCESS);
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  source_ = std::string(source);
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#ifndef NDEBUG
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Allow the token service to be cleared from the command line.
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (cmd_line->HasSwitch(switches::kClearTokenService))
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EraseTokensFromDB();
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Allow a token to be injected from the command line.
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (cmd_line->HasSwitch(switches::kSetToken)) {
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string value = cmd_line->GetSwitchValueASCII(switches::kSetToken);
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int separator = value.find(':');
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string service = value.substr(0, separator);
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string token = value.substr(separator + 1);
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    token_map_[service] = token;
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    SaveAuthTokenToDB(service, token);
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this,
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 NotificationType::TOKEN_UPDATED,
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 NotificationService::AllSources());
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::ResetCredentialsInMemory() {
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Terminate any running fetchers. Callbacks will not return.
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < kNumServices; i++) {
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    fetchers_[i].reset();
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Cancel pending loads. Callbacks will not return.
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (token_loading_query_) {
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    web_data_service_->CancelRequest(token_loading_query_);
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    token_loading_query_ = 0;
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  token_map_.clear();
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  credentials_ = GaiaAuthConsumer::ClientLoginResult();
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::UpdateCredentials(
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GaiaAuthConsumer::ClientLoginResult& credentials) {
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  credentials_ = credentials;
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Cancels any currently running requests.
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < kNumServices; i++) {
984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    fetchers_[i].reset(new GaiaAuthFetcher(this, source_, getter_));
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::LoadTokensFromDB() {
103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  token_loading_query_ = web_data_service_->GetAllTokens(this);
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::SaveAuthTokenToDB(const std::string& service,
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     const std::string& auth_token) {
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  web_data_service_->SetTokenForService(service, auth_token);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::EraseTokensFromDB() {
114731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  web_data_service_->RemoveAllTokens();
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool TokenService::AreCredentialsValid() const {
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return !credentials_.lsid.empty() && !credentials_.sid.empty();
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool TokenService::HasLsid() const {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return !credentials_.lsid.empty();
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst std::string& TokenService::GetLsid() const {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return credentials_.lsid;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::StartFetchingTokens() {
131731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(AreCredentialsValid());
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < kNumServices; i++) {
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    fetchers_[i]->StartIssueAuthToken(credentials_.sid,
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      credentials_.lsid,
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      kServices[i]);
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Services dependent on a token will check if a token is available.
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// If it isn't, they'll go to sleep until they get a token event.
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool TokenService::HasTokenForService(const char* const service) const {
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return token_map_.count(service) > 0;
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst std::string& TokenService::GetTokenForService(
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const char* const service) const {
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (token_map_.count(service) > 0) {
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Note map[key] is not const.
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return (*token_map_.find(service)).second;
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return EmptyString();
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Note that this can fire twice or more for any given service.
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// It can fire once from the DB read, and then once from the initial
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// fetcher. Future fetches can cause more notification firings.
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The DB read will not however fire a notification if the fetcher
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// returned first. So it's always safe to use the latest notification.
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::FireTokenAvailableNotification(
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string& service,
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string& auth_token) {
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TokenAvailableDetails details(service, auth_token);
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NotificationService::current()->Notify(
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NotificationType::TOKEN_AVAILABLE,
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Source<TokenService>(this),
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Details<const TokenAvailableDetails>(&details));
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::FireTokenRequestFailedNotification(
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string& service,
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const GoogleServiceAuthError& error) {
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TokenRequestFailedDetails details(service, error);
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NotificationService::current()->Notify(
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NotificationType::TOKEN_REQUEST_FAILED,
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Source<TokenService>(this),
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Details<const TokenRequestFailedDetails>(&details));
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::IssueAuthTokenForTest(const std::string& service,
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                         const std::string& auth_token) {
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  token_map_[service] = auth_token;
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FireTokenAvailableNotification(service, auth_token);
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::OnIssueAuthTokenSuccess(const std::string& service,
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                           const std::string& auth_token) {
191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  VLOG(1) << "Got an authorization token for " << service;
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  token_map_[service] = auth_token;
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FireTokenAvailableNotification(service, auth_token);
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SaveAuthTokenToDB(service, auth_token);
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::OnIssueAuthTokenFailure(const std::string& service,
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const GoogleServiceAuthError& error) {
200731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  LOG(WARNING) << "Auth token issuing failed for service:" << service;
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FireTokenRequestFailedNotification(service, error);
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::OnWebDataServiceRequestDone(WebDataService::Handle h,
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                               const WDTypedResult* result) {
207731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(token_loading_query_);
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  token_loading_query_ = 0;
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If the fetch failed, there will be no result. In that case, we just don't
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // load any tokens at all from the DB.
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result) {
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(result->GetType() == TOKEN_RESULT);
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const WDResult<std::map<std::string, std::string> > * token_result =
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        static_cast<const WDResult<std::map<std::string, std::string> > * > (
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            result);
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LoadTokensIntoMemory(token_result->GetValue(), &token_map_);
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NotificationService::current()->Notify(
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NotificationType::TOKEN_LOADING_FINISHED,
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Source<TokenService>(this),
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NotificationService::NoDetails());
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Load tokens from the db_token map into the in memory token map.
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::LoadTokensIntoMemory(
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::map<std::string, std::string>& db_tokens,
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::map<std::string, std::string>* in_memory_tokens) {
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < kNumServices; i++) {
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // OnIssueAuthTokenSuccess should come from the same thread.
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // If a token is already present in the map, it could only have
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // come from a DB read or from IssueAuthToken. Since we should never
2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // fetch from the DB twice in a browser session, it must be from
2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // OnIssueAuthTokenSuccess, which is a live fetcher.
2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    //
2393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Network fetched tokens take priority over DB tokens, so exclude tokens
2403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // which have already been loaded by the fetcher.
2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!in_memory_tokens->count(kServices[i]) &&
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        db_tokens.count(kServices[i])) {
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::string db_token = db_tokens.find(kServices[i])->second;
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (!db_token.empty()) {
245513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        VLOG(1) << "Loading " << kServices[i] << "token from DB: " << db_token;
2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        (*in_memory_tokens)[kServices[i]] = db_token;
2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        FireTokenAvailableNotification(kServices[i], db_token);
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        // Failures are only for network errors.
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TokenService::Observe(NotificationType type,
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                           const NotificationSource& source,
2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                           const NotificationDetails& details) {
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(type == NotificationType::TOKEN_UPDATED);
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TokenAvailableDetails* tok_details =
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Details<TokenAvailableDetails>(details).ptr();
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OnIssueAuthTokenSuccess(tok_details->service(), tok_details->token());
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
262