Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / identity / identity_api.cc
index fbbdca0..df6fdbd 100644 (file)
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/policy/browser_policy_connector.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 "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/extensions/api/identity.h"
 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
-#include "chrome/common/extensions/extension.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_function_dispatcher.h"
+#include "extensions/common/extension.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -54,6 +55,7 @@ const char kInteractionRequired[] = "User interaction required.";
 const char kInvalidRedirect[] = "Did not redirect to the right URL.";
 const char kOffTheRecord[] = "Identity API is disabled in incognito windows.";
 const char kPageLoadFailure[] = "Authorization page could not be loaded.";
+const char kCanceled[] = "canceled";
 
 const int kCachedIssueAdviceTTLSeconds = 1;
 }  // namespace identity_constants
@@ -63,17 +65,172 @@ namespace {
 static const char kChromiumDomainRedirectUrlPattern[] =
     "https://%s.chromiumapp.org/";
 
+std::string GetPrimaryAccountId(content::BrowserContext* context) {
+  SigninManagerBase* signin_manager =
+      SigninManagerFactory::GetForProfile(Profile::FromBrowserContext(context));
+  return signin_manager->GetAuthenticatedAccountId();
+}
+
 }  // namespace
 
 namespace identity = api::identity;
 
+IdentityTokenCacheValue::IdentityTokenCacheValue()
+    : status_(CACHE_STATUS_NOTFOUND) {}
+
+IdentityTokenCacheValue::IdentityTokenCacheValue(
+    const IssueAdviceInfo& issue_advice)
+    : status_(CACHE_STATUS_ADVICE), issue_advice_(issue_advice) {
+  expiration_time_ =
+      base::Time::Now() + base::TimeDelta::FromSeconds(
+                              identity_constants::kCachedIssueAdviceTTLSeconds);
+}
+
+IdentityTokenCacheValue::IdentityTokenCacheValue(const std::string& token,
+                                                 base::TimeDelta time_to_live)
+    : status_(CACHE_STATUS_TOKEN), token_(token) {
+  // Remove 20 minutes from the ttl so cached tokens will have some time
+  // to live any time they are returned.
+  time_to_live -= base::TimeDelta::FromMinutes(20);
+
+  base::TimeDelta zero_delta;
+  if (time_to_live < zero_delta)
+    time_to_live = zero_delta;
+
+  expiration_time_ = base::Time::Now() + time_to_live;
+}
+
+IdentityTokenCacheValue::~IdentityTokenCacheValue() {}
+
+IdentityTokenCacheValue::CacheValueStatus IdentityTokenCacheValue::status()
+    const {
+  if (is_expired())
+    return IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND;
+  else
+    return status_;
+}
+
+const IssueAdviceInfo& IdentityTokenCacheValue::issue_advice() const {
+  return issue_advice_;
+}
+
+const std::string& IdentityTokenCacheValue::token() const { return token_; }
+
+bool IdentityTokenCacheValue::is_expired() const {
+  return status_ == CACHE_STATUS_NOTFOUND ||
+         expiration_time_ < base::Time::Now();
+}
+
+const base::Time& IdentityTokenCacheValue::expiration_time() const {
+  return expiration_time_;
+}
+
+IdentityAPI::IdentityAPI(content::BrowserContext* context)
+    : browser_context_(context),
+      account_tracker_(Profile::FromBrowserContext(context)) {
+  account_tracker_.AddObserver(this);
+}
+
+IdentityAPI::~IdentityAPI() {}
+
+IdentityMintRequestQueue* IdentityAPI::mint_queue() { return &mint_queue_; }
+
+void IdentityAPI::SetCachedToken(const ExtensionTokenKey& key,
+                                 const IdentityTokenCacheValue& token_data) {
+  CachedTokens::iterator it = token_cache_.find(key);
+  if (it != token_cache_.end() && it->second.status() <= token_data.status())
+    token_cache_.erase(it);
+
+  token_cache_.insert(std::make_pair(key, token_data));
+}
+
+void IdentityAPI::EraseCachedToken(const std::string& extension_id,
+                                   const std::string& token) {
+  CachedTokens::iterator it;
+  for (it = token_cache_.begin(); it != token_cache_.end(); ++it) {
+    if (it->first.extension_id == extension_id &&
+        it->second.status() == IdentityTokenCacheValue::CACHE_STATUS_TOKEN &&
+        it->second.token() == token) {
+      token_cache_.erase(it);
+      break;
+    }
+  }
+}
+
+void IdentityAPI::EraseAllCachedTokens() { token_cache_.clear(); }
+
+const IdentityTokenCacheValue& IdentityAPI::GetCachedToken(
+    const ExtensionTokenKey& key) {
+  return token_cache_[key];
+}
+
+const IdentityAPI::CachedTokens& IdentityAPI::GetAllCachedTokens() {
+  return token_cache_;
+}
+
+void IdentityAPI::ReportAuthError(const GoogleServiceAuthError& error) {
+  account_tracker_.ReportAuthError(GetPrimaryAccountId(browser_context_),
+                                   error);
+}
+
+GoogleServiceAuthError IdentityAPI::GetAuthStatusForTest() const {
+  return account_tracker_.GetAuthStatus();
+}
+
+void IdentityAPI::Shutdown() {
+  FOR_EACH_OBSERVER(ShutdownObserver, shutdown_observer_list_, OnShutdown());
+  account_tracker_.RemoveObserver(this);
+  account_tracker_.Shutdown();
+}
+
+static base::LazyInstance<BrowserContextKeyedAPIFactory<IdentityAPI> >
+    g_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+BrowserContextKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() {
+  return g_factory.Pointer();
+}
+
+void IdentityAPI::OnAccountAdded(const AccountIds& ids) {}
+
+void IdentityAPI::OnAccountRemoved(const AccountIds& ids) {}
+
+void IdentityAPI::OnAccountSignInChanged(const AccountIds& ids,
+                                         bool is_signed_in) {
+  api::identity::AccountInfo account_info;
+  account_info.id = ids.gaia;
+
+  scoped_ptr<base::ListValue> args =
+      api::identity::OnSignInChanged::Create(account_info, is_signed_in);
+  scoped_ptr<Event> event(new Event(api::identity::OnSignInChanged::kEventName,
+                                    args.Pass(),
+                                    browser_context_));
+
+  EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
+}
+
+void IdentityAPI::AddShutdownObserver(ShutdownObserver* observer) {
+  shutdown_observer_list_.AddObserver(observer);
+}
+
+void IdentityAPI::RemoveShutdownObserver(ShutdownObserver* observer) {
+  shutdown_observer_list_.RemoveObserver(observer);
+}
+
+template <>
+void BrowserContextKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() {
+  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
+  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
+}
+
 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction()
-    : should_prompt_for_scopes_(false),
+    : OAuth2TokenService::Consumer("extensions_identity_api"),
+      should_prompt_for_scopes_(false),
       should_prompt_for_signin_(false) {}
 
 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {}
 
-bool IdentityGetAuthTokenFunction::RunImpl() {
+bool IdentityGetAuthTokenFunction::RunAsync() {
   if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
@@ -103,12 +260,19 @@ bool IdentityGetAuthTokenFunction::RunImpl() {
     return false;
   }
 
-  // Balanced in CompleteFunctionWithResult|CompleteFunctionWithError
-  AddRef();
+  std::set<std::string> scopes(oauth2_info.scopes.begin(),
+                               oauth2_info.scopes.end());
+  token_key_.reset(new ExtensionTokenKey(
+      GetExtension()->id(), GetPrimaryAccountId(GetProfile()), scopes));
+
+  // From here on out, results must be returned asynchronously.
+  StartAsyncRun();
 
 #if defined(OS_CHROMEOS)
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
   if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp() &&
-      g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
+      connector->IsEnterpriseManaged()) {
     StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
     return true;
   }
@@ -116,9 +280,8 @@ bool IdentityGetAuthTokenFunction::RunImpl() {
 
   if (!HasLoginToken()) {
     if (!should_prompt_for_signin_) {
-      error_ = identity_constants::kUserNotSignedIn;
-      Release();
-      return false;
+      CompleteFunctionWithError(identity_constants::kUserNotSignedIn);
+      return true;
     }
     // Display a login prompt.
     StartSigninFlow();
@@ -129,25 +292,40 @@ bool IdentityGetAuthTokenFunction::RunImpl() {
   return true;
 }
 
+void IdentityGetAuthTokenFunction::StartAsyncRun() {
+  // Balanced in CompleteAsyncRun
+  AddRef();
+  extensions::IdentityAPI::GetFactoryInstance()
+      ->Get(GetProfile())
+      ->AddShutdownObserver(this);
+}
+
+void IdentityGetAuthTokenFunction::CompleteAsyncRun(bool success) {
+  extensions::IdentityAPI::GetFactoryInstance()
+      ->Get(GetProfile())
+      ->RemoveShutdownObserver(this);
+
+  SendResponse(success);
+  Release();  // Balanced in StartAsyncRun
+}
+
 void IdentityGetAuthTokenFunction::CompleteFunctionWithResult(
     const std::string& access_token) {
+
   SetResult(new base::StringValue(access_token));
-  SendResponse(true);
-  Release();  // Balanced in RunImpl.
+  CompleteAsyncRun(true);
 }
 
 void IdentityGetAuthTokenFunction::CompleteFunctionWithError(
     const std::string& error) {
   error_ = error;
-  SendResponse(false);
-  Release();  // Balanced in RunImpl.
+  CompleteAsyncRun(false);
 }
 
 void IdentityGetAuthTokenFunction::StartSigninFlow() {
   // All cached tokens are invalid because the user is not signed in.
   IdentityAPI* id_api =
-      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
-          GetProfile());
+      extensions::IdentityAPI::GetFactoryInstance()->Get(GetProfile());
   id_api->EraseAllCachedTokens();
   // Display a login prompt. If the subsequent mint fails, don't display the
   // login prompt again.
@@ -161,12 +339,8 @@ void IdentityGetAuthTokenFunction::StartMintTokenFlow(
 
   // Flows are serialized to prevent excessive traffic to GAIA, and
   // to consolidate UI pop-ups.
-  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
-  std::set<std::string> scopes(oauth2_info.scopes.begin(),
-                               oauth2_info.scopes.end());
   IdentityAPI* id_api =
-      extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
-          GetProfile());
+      extensions::IdentityAPI::GetFactoryInstance()->Get(GetProfile());
 
   if (!should_prompt_for_scopes_) {
     // Caller requested no interaction.
@@ -177,17 +351,13 @@ void IdentityGetAuthTokenFunction::StartMintTokenFlow(
       return;
     }
     if (!id_api->mint_queue()->empty(
-            IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE,
-            GetExtension()->id(), scopes)) {
+            IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE, *token_key_)) {
       // Another call is going through a consent UI.
       CompleteFunctionWithError(identity_constants::kNoGrant);
       return;
     }
   }
-  id_api->mint_queue()->RequestStart(type,
-                                     GetExtension()->id(),
-                                     scopes,
-                                     this);
+  id_api->mint_queue()->RequestStart(type, *token_key_, this);
 }
 
 void IdentityGetAuthTokenFunction::CompleteMintTokenFlow() {
@@ -198,18 +368,16 @@ void IdentityGetAuthTokenFunction::CompleteMintTokenFlow() {
                                oauth2_info.scopes.end());
 
   extensions::IdentityAPI::GetFactoryInstance()
-      ->GetForProfile(GetProfile())
+      ->Get(GetProfile())
       ->mint_queue()
-      ->RequestComplete(type, GetExtension()->id(), scopes, this);
+      ->RequestComplete(type, *token_key_, this);
 }
 
 void IdentityGetAuthTokenFunction::StartMintToken(
     IdentityMintRequestQueue::MintType type) {
   const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
-  IdentityAPI* id_api =
-      IdentityAPI::GetFactoryInstance()->GetForProfile(GetProfile());
-  IdentityTokenCacheValue cache_entry = id_api->GetCachedToken(
-      GetExtension()->id(), oauth2_info.scopes);
+  IdentityAPI* id_api = IdentityAPI::GetFactoryInstance()->Get(GetProfile());
+  IdentityTokenCacheValue cache_entry = id_api->GetCachedToken(*token_key_);
   IdentityTokenCacheValue::CacheValueStatus cache_status =
       cache_entry.status();
 
@@ -220,8 +388,10 @@ void IdentityGetAuthTokenFunction::StartMintToken(
         // Always force minting token for ChromeOS kiosk app.
         if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp()) {
           gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
-          if (g_browser_process->browser_policy_connector()->
-                  IsEnterpriseManaged()) {
+          policy::BrowserPolicyConnectorChromeOS* connector =
+              g_browser_process->platform_part()
+                  ->browser_policy_connector_chromeos();
+          if (connector->IsEnterpriseManaged()) {
             StartDeviceLoginAccessTokenRequest();
           } else {
             StartLoginAccessTokenRequest();
@@ -266,12 +436,10 @@ void IdentityGetAuthTokenFunction::StartMintToken(
 
 void IdentityGetAuthTokenFunction::OnMintTokenSuccess(
     const std::string& access_token, int time_to_live) {
-  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
   IdentityTokenCacheValue token(access_token,
                                 base::TimeDelta::FromSeconds(time_to_live));
-  IdentityAPI::GetFactoryInstance()
-      ->GetForProfile(GetProfile())
-      ->SetCachedToken(GetExtension()->id(), oauth2_info.scopes, token);
+  IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
+      *token_key_, token);
 
   CompleteMintTokenFlow();
   CompleteFunctionWithResult(access_token);
@@ -286,7 +454,7 @@ void IdentityGetAuthTokenFunction::OnMintTokenFailure(
     case GoogleServiceAuthError::ACCOUNT_DELETED:
     case GoogleServiceAuthError::ACCOUNT_DISABLED:
       extensions::IdentityAPI::GetFactoryInstance()
-          ->GetForProfile(GetProfile())
+          ->Get(GetProfile())
           ->ReportAuthError(error);
       if (should_prompt_for_signin_) {
         // Display a login prompt and try again (once).
@@ -305,12 +473,8 @@ void IdentityGetAuthTokenFunction::OnMintTokenFailure(
 
 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
     const IssueAdviceInfo& issue_advice) {
-  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
-  IdentityAPI::GetFactoryInstance()
-      ->GetForProfile(GetProfile())
-      ->SetCachedToken(GetExtension()->id(),
-                       oauth2_info.scopes,
-                       IdentityTokenCacheValue(issue_advice));
+  IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
+      *token_key_, IdentityTokenCacheValue(issue_advice));
   CompleteMintTokenFlow();
 
   should_prompt_for_signin_ = false;
@@ -372,12 +536,10 @@ void IdentityGetAuthTokenFunction::OnGaiaFlowCompleted(
 
   int time_to_live;
   if (!expiration.empty() && base::StringToInt(expiration, &time_to_live)) {
-    const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
     IdentityTokenCacheValue token_value(
         access_token, base::TimeDelta::FromSeconds(time_to_live));
-    IdentityAPI::GetFactoryInstance()
-        ->GetForProfile(GetProfile())
-        ->SetCachedToken(GetExtension()->id(), oauth2_info.scopes, token_value);
+    IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
+        *token_key_, token_value);
   }
 
   CompleteMintTokenFlow();
@@ -399,19 +561,21 @@ void IdentityGetAuthTokenFunction::OnGetTokenFailure(
   OnGaiaFlowFailure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error, std::string());
 }
 
-#if defined(OS_CHROMEOS)
-void IdentityGetAuthTokenFunction::StartDeviceLoginAccessTokenRequest() {
-  chromeos::DeviceOAuth2TokenServiceFactory::Get(
-      base::Bind(&IdentityGetAuthTokenFunction::DidGetTokenService,
-                 this));
+void IdentityGetAuthTokenFunction::OnShutdown() {
+  gaia_web_auth_flow_.reset();
+  signin_flow_.reset();
+  login_token_request_.reset();
+  extensions::IdentityAPI::GetFactoryInstance()
+      ->Get(GetProfile())
+      ->mint_queue()
+      ->RequestCancel(*token_key_, this);
+  CompleteFunctionWithError(identity_constants::kCanceled);
 }
 
-void IdentityGetAuthTokenFunction::DidGetTokenService(
-    chromeos::DeviceOAuth2TokenService* service) {
-  if (!service) {
-    CompleteFunctionWithError(identity_constants::kUserNotSignedIn);
-    return;
-  }
+#if defined(OS_CHROMEOS)
+void IdentityGetAuthTokenFunction::StartDeviceLoginAccessTokenRequest() {
+  chromeos::DeviceOAuth2TokenService* service =
+      chromeos::DeviceOAuth2TokenServiceFactory::Get();
   // Since robot account refresh tokens are scoped down to [any-api] only,
   // request access token for [any-api] instead of login.
   OAuth2TokenService::ScopeSet scopes;
@@ -426,6 +590,7 @@ void IdentityGetAuthTokenFunction::DidGetTokenService(
 void IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest() {
   ProfileOAuth2TokenService* service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
+  const std::string primary_account_id = GetPrimaryAccountId(GetProfile());
 #if defined(OS_CHROMEOS)
   if (chrome::IsRunningInForcedAppMode()) {
     std::string app_client_id;
@@ -433,7 +598,7 @@ void IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest() {
     if (chromeos::UserManager::Get()->GetAppModeChromeClientOAuthInfo(
            &app_client_id, &app_client_secret)) {
       login_token_request_ =
-          service->StartRequestForClient(service->GetPrimaryAccountId(),
+          service->StartRequestForClient(primary_account_id,
                                          app_client_id,
                                          app_client_secret,
                                          OAuth2TokenService::ScopeSet(),
@@ -443,7 +608,7 @@ void IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest() {
   }
 #endif
   login_token_request_ = service->StartRequest(
-      service->GetPrimaryAccountId(), OAuth2TokenService::ScopeSet(), this);
+      primary_account_id, OAuth2TokenService::ScopeSet(), this);
 }
 
 void IdentityGetAuthTokenFunction::StartGaiaRequest(
@@ -488,7 +653,7 @@ bool IdentityGetAuthTokenFunction::HasLoginToken() const {
   ProfileOAuth2TokenService* token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
   return token_service->RefreshTokenIsAvailable(
-      token_service->GetPrimaryAccountId());
+      GetPrimaryAccountId(GetProfile()));
 }
 
 std::string IdentityGetAuthTokenFunction::MapOAuth2ErrorToDescription(
@@ -524,7 +689,7 @@ IdentityRemoveCachedAuthTokenFunction::
     ~IdentityRemoveCachedAuthTokenFunction() {
 }
 
-bool IdentityRemoveCachedAuthTokenFunction::RunImpl() {
+bool IdentityRemoveCachedAuthTokenFunction::RunSync() {
   if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
@@ -533,9 +698,8 @@ bool IdentityRemoveCachedAuthTokenFunction::RunImpl() {
   scoped_ptr<identity::RemoveCachedAuthToken::Params> params(
       identity::RemoveCachedAuthToken::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  IdentityAPI::GetFactoryInstance()
-      ->GetForProfile(GetProfile())
-      ->EraseCachedToken(GetExtension()->id(), params->details.token);
+  IdentityAPI::GetFactoryInstance()->Get(GetProfile())->EraseCachedToken(
+      GetExtension()->id(), params->details.token);
   return true;
 }
 
@@ -546,7 +710,7 @@ IdentityLaunchWebAuthFlowFunction::~IdentityLaunchWebAuthFlowFunction() {
     auth_flow_.release()->DetachDelegateAndDelete();
 }
 
-bool IdentityLaunchWebAuthFlowFunction::RunImpl() {
+bool IdentityLaunchWebAuthFlowFunction::RunAsync() {
   if (GetProfile()->IsOffTheRecord()) {
     error_ = identity_constants::kOffTheRecord;
     return false;
@@ -603,7 +767,7 @@ void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure(
       break;
   }
   SendResponse(false);
-  Release();  // Balanced in RunImpl.
+  Release();  // Balanced in RunAsync.
 }
 
 void IdentityLaunchWebAuthFlowFunction::OnAuthFlowURLChange(
@@ -611,176 +775,8 @@ void IdentityLaunchWebAuthFlowFunction::OnAuthFlowURLChange(
   if (redirect_url.GetWithEmptyPath() == final_url_prefix_) {
     SetResult(new base::StringValue(redirect_url.spec()));
     SendResponse(true);
-    Release();  // Balanced in RunImpl.
+    Release();  // Balanced in RunAsync.
   }
 }
 
-IdentityTokenCacheValue::IdentityTokenCacheValue()
-    : status_(CACHE_STATUS_NOTFOUND) {
-}
-
-IdentityTokenCacheValue::IdentityTokenCacheValue(
-    const IssueAdviceInfo& issue_advice) : status_(CACHE_STATUS_ADVICE),
-                                           issue_advice_(issue_advice) {
-  expiration_time_ = base::Time::Now() + base::TimeDelta::FromSeconds(
-      identity_constants::kCachedIssueAdviceTTLSeconds);
-}
-
-IdentityTokenCacheValue::IdentityTokenCacheValue(
-    const std::string& token, base::TimeDelta time_to_live)
-    : status_(CACHE_STATUS_TOKEN),
-      token_(token) {
-  // Remove 20 minutes from the ttl so cached tokens will have some time
-  // to live any time they are returned.
-  time_to_live -= base::TimeDelta::FromMinutes(20);
-
-  base::TimeDelta zero_delta;
-  if (time_to_live < zero_delta)
-    time_to_live = zero_delta;
-
-  expiration_time_ = base::Time::Now() + time_to_live;
-}
-
-IdentityTokenCacheValue::~IdentityTokenCacheValue() {
-}
-
-IdentityTokenCacheValue::CacheValueStatus
-    IdentityTokenCacheValue::status() const {
-  if (is_expired())
-    return IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND;
-  else
-    return status_;
-}
-
-const IssueAdviceInfo& IdentityTokenCacheValue::issue_advice() const {
-  return issue_advice_;
-}
-
-const std::string& IdentityTokenCacheValue::token() const {
-  return token_;
-}
-
-bool IdentityTokenCacheValue::is_expired() const {
-  return status_ == CACHE_STATUS_NOTFOUND ||
-      expiration_time_ < base::Time::Now();
-}
-
-const base::Time& IdentityTokenCacheValue::expiration_time() const {
-  return expiration_time_;
-}
-
-IdentityAPI::IdentityAPI(Profile* profile)
-    : profile_(profile),
-      account_tracker_(profile) {
-  account_tracker_.AddObserver(this);
-}
-
-IdentityAPI::~IdentityAPI() {}
-
-IdentityMintRequestQueue* IdentityAPI::mint_queue() {
-    return &mint_queue_;
-}
-
-void IdentityAPI::SetCachedToken(const std::string& extension_id,
-                                 const std::vector<std::string> scopes,
-                                 const IdentityTokenCacheValue& token_data) {
-  std::set<std::string> scopeset(scopes.begin(), scopes.end());
-  TokenCacheKey key(extension_id, scopeset);
-
-  CachedTokens::iterator it = token_cache_.find(key);
-  if (it != token_cache_.end() && it->second.status() <= token_data.status())
-    token_cache_.erase(it);
-
-  token_cache_.insert(std::make_pair(key, token_data));
-}
-
-void IdentityAPI::EraseCachedToken(const std::string& extension_id,
-                                   const std::string& token) {
-  CachedTokens::iterator it;
-  for (it = token_cache_.begin(); it != token_cache_.end(); ++it) {
-    if (it->first.extension_id == extension_id &&
-        it->second.status() == IdentityTokenCacheValue::CACHE_STATUS_TOKEN &&
-        it->second.token() == token) {
-      token_cache_.erase(it);
-      break;
-    }
-  }
-}
-
-void IdentityAPI::EraseAllCachedTokens() {
-  token_cache_.clear();
-}
-
-const IdentityTokenCacheValue& IdentityAPI::GetCachedToken(
-    const std::string& extension_id, const std::vector<std::string> scopes) {
-  std::set<std::string> scopeset(scopes.begin(), scopes.end());
-  TokenCacheKey key(extension_id, scopeset);
-  return token_cache_[key];
-}
-
-const IdentityAPI::CachedTokens& IdentityAPI::GetAllCachedTokens() {
-  return token_cache_;
-}
-
-void IdentityAPI::ReportAuthError(const GoogleServiceAuthError& error) {
-  ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
-  account_tracker_.ReportAuthError(token_service->GetPrimaryAccountId(), error);
-}
-
-void IdentityAPI::Shutdown() {
-  account_tracker_.RemoveObserver(this);
-  account_tracker_.Shutdown();
-}
-
-static base::LazyInstance<ProfileKeyedAPIFactory<IdentityAPI> >
-    g_factory = LAZY_INSTANCE_INITIALIZER;
-
-// static
-ProfileKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() {
-  return &g_factory.Get();
-}
-
-void IdentityAPI::OnAccountAdded(const AccountIds& ids) {}
-
-void IdentityAPI::OnAccountRemoved(const AccountIds& ids) {}
-
-void IdentityAPI::OnAccountSignInChanged(const AccountIds& ids,
-                                         bool is_signed_in) {
-  api::identity::AccountInfo account_info;
-  account_info.id = ids.gaia;
-
-  scoped_ptr<base::ListValue> args =
-      api::identity::OnSignInChanged::Create(account_info, is_signed_in);
-  scoped_ptr<Event> event(new Event(
-      api::identity::OnSignInChanged::kEventName, args.Pass(), profile_));
-
-  ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
-}
-
-template <>
-void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() {
-  DependsOn(ExtensionSystemFactory::GetInstance());
-  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
-}
-
-IdentityAPI::TokenCacheKey::TokenCacheKey(const std::string& extension_id,
-                                          const std::set<std::string> scopes)
-    : extension_id(extension_id),
-      scopes(scopes) {
-}
-
-IdentityAPI::TokenCacheKey::~TokenCacheKey() {
-}
-
-bool IdentityAPI::TokenCacheKey::operator<(
-    const IdentityAPI::TokenCacheKey& rhs) const {
-  if (extension_id < rhs.extension_id)
-    return true;
-  else if (rhs.extension_id < extension_id)
-    return false;
-
-  return scopes < rhs.scopes;
-}
-
 }  // namespace extensions