identity_api.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/identity/identity_api.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <set>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string>
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <utility>
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <vector>
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/debug/trace_event.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/prefs/pref_service.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
165e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/app_mode/app_mode_utils.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/browser_process.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/api/identity.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/pref_names.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
31e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_manager.h"
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/signin/core/common/profile_management_switches.h"
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_function_dispatcher.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/extension_l10n_util.h"
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/permissions/permission_set.h"
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/permissions/permissions_data.h"
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "google_apis/gaia/gaia_urls.h"
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_CHROMEOS)
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/chromeos/login/session/user_session_manager.h"
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/user_manager/user_manager.h"
488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace identity_constants {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidClientId[] = "Invalid OAuth2 Client ID.";
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidScopes[] = "Invalid OAuth2 scopes.";
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kAuthFailure[] = "OAuth2 request failed: ";
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNoGrant[] = "OAuth2 not granted or revoked.";
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUserRejected[] = "The user did not approve access.";
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUserNotSignedIn[] = "The user is not signed in.";
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kInteractionRequired[] = "User interaction required.";
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidRedirect[] = "Did not redirect to the right URL.";
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kOffTheRecord[] = "Identity API is disabled in incognito windows.";
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kPageLoadFailure[] = "Authorization page could not be loaded.";
64e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst char kCanceled[] = "canceled";
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kCachedIssueAdviceTTLSeconds = 1;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace identity_constants
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static const char kChromiumDomainRedirectUrlPattern[] =
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "https://%s.chromiumapp.org/";
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string GetPrimaryAccountId(content::BrowserContext* context) {
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SigninManagerBase* signin_manager =
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      SigninManagerFactory::GetForProfile(Profile::FromBrowserContext(context));
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return signin_manager->GetAuthenticatedAccountId();
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace identity = api::identity;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
84e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityTokenCacheValue::IdentityTokenCacheValue()
85e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : status_(CACHE_STATUS_NOTFOUND) {}
86e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
87e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityTokenCacheValue::IdentityTokenCacheValue(
88e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const IssueAdviceInfo& issue_advice)
89e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : status_(CACHE_STATUS_ADVICE), issue_advice_(issue_advice) {
90e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  expiration_time_ =
91e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::Time::Now() + base::TimeDelta::FromSeconds(
92e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                              identity_constants::kCachedIssueAdviceTTLSeconds);
93e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
95e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityTokenCacheValue::IdentityTokenCacheValue(const std::string& token,
96e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                                 base::TimeDelta time_to_live)
97e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : status_(CACHE_STATUS_TOKEN), token_(token) {
98e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Remove 20 minutes from the ttl so cached tokens will have some time
99e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // to live any time they are returned.
100e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  time_to_live -= base::TimeDelta::FromMinutes(20);
101e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
102e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  base::TimeDelta zero_delta;
103e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (time_to_live < zero_delta)
104e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    time_to_live = zero_delta;
105e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
106e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  expiration_time_ = base::Time::Now() + time_to_live;
107e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
108e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
109e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityTokenCacheValue::~IdentityTokenCacheValue() {}
110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityTokenCacheValue::CacheValueStatus IdentityTokenCacheValue::status()
112e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const {
113e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (is_expired())
114e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND;
115e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  else
116e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return status_;
117e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
118e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
119e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst IssueAdviceInfo& IdentityTokenCacheValue::issue_advice() const {
120e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return issue_advice_;
121e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
122e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
123e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst std::string& IdentityTokenCacheValue::token() const { return token_; }
124e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
125e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochbool IdentityTokenCacheValue::is_expired() const {
126e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return status_ == CACHE_STATUS_NOTFOUND ||
127e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch         expiration_time_ < base::Time::Now();
128e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
129e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
130e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst base::Time& IdentityTokenCacheValue::expiration_time() const {
131e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return expiration_time_;
132e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
133e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
134e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityAPI::IdentityAPI(content::BrowserContext* context)
135e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : browser_context_(context),
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      profile_identity_provider_(
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          SigninManagerFactory::GetForProfile(
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              Profile::FromBrowserContext(context)),
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          ProfileOAuth2TokenServiceFactory::GetForProfile(
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              Profile::FromBrowserContext(context)),
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          LoginUIServiceFactory::GetForProfile(
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              Profile::FromBrowserContext(context))),
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      account_tracker_(&profile_identity_provider_,
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       g_browser_process->system_request_context()) {
145e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  account_tracker_.AddObserver(this);
146e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
147e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
148e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityAPI::~IdentityAPI() {}
149e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
150e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochIdentityMintRequestQueue* IdentityAPI::mint_queue() { return &mint_queue_; }
151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
152e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityAPI::SetCachedToken(const ExtensionTokenKey& key,
153e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                 const IdentityTokenCacheValue& token_data) {
154e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CachedTokens::iterator it = token_cache_.find(key);
155e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (it != token_cache_.end() && it->second.status() <= token_data.status())
156e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    token_cache_.erase(it);
157e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
158e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  token_cache_.insert(std::make_pair(key, token_data));
159e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
160e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
161e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityAPI::EraseCachedToken(const std::string& extension_id,
162e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                   const std::string& token) {
163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CachedTokens::iterator it;
164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (it = token_cache_.begin(); it != token_cache_.end(); ++it) {
165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (it->first.extension_id == extension_id &&
166e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        it->second.status() == IdentityTokenCacheValue::CACHE_STATUS_TOKEN &&
167e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        it->second.token() == token) {
168e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      token_cache_.erase(it);
169e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      break;
170e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
171e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
172e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
173e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
174e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityAPI::EraseAllCachedTokens() { token_cache_.clear(); }
175e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
176e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst IdentityTokenCacheValue& IdentityAPI::GetCachedToken(
177e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const ExtensionTokenKey& key) {
178e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return token_cache_[key];
179e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
180e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
181e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst IdentityAPI::CachedTokens& IdentityAPI::GetAllCachedTokens() {
182e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return token_cache_;
183e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
184e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)std::vector<std::string> IdentityAPI::GetAccounts() const {
18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const std::string primary_account_id = GetPrimaryAccountId(browser_context_);
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<gaia::AccountIds> ids = account_tracker_.GetAccounts();
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<std::string> gaia_ids;
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (switches::IsExtensionsMultiAccount()) {
191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (std::vector<gaia::AccountIds>::const_iterator it = ids.begin();
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)         it != ids.end();
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)         ++it) {
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      gaia_ids.push_back(it->gaia);
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (ids.size() >= 1) {
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    gaia_ids.push_back(ids[0].gaia);
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return gaia_ids;
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
20346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)std::string IdentityAPI::FindAccountKeyByGaiaId(const std::string& gaia_id) {
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return account_tracker_.FindAccountIdsByGaiaId(gaia_id).account_key;
205e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
206e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
207e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityAPI::Shutdown() {
208e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  FOR_EACH_OBSERVER(ShutdownObserver, shutdown_observer_list_, OnShutdown());
209e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  account_tracker_.RemoveObserver(this);
210e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  account_tracker_.Shutdown();
211e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
212e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
213e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochstatic base::LazyInstance<BrowserContextKeyedAPIFactory<IdentityAPI> >
214e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    g_factory = LAZY_INSTANCE_INITIALIZER;
215e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
216e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// static
217e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochBrowserContextKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() {
218e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return g_factory.Pointer();
219e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
220e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IdentityAPI::OnAccountAdded(const gaia::AccountIds& ids) {
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
223e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IdentityAPI::OnAccountRemoved(const gaia::AccountIds& ids) {
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
226e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IdentityAPI::OnAccountSignInChanged(const gaia::AccountIds& ids,
228e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                         bool is_signed_in) {
229e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  api::identity::AccountInfo account_info;
230e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  account_info.id = ids.gaia;
231e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
232e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  scoped_ptr<base::ListValue> args =
233e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      api::identity::OnSignInChanged::Create(account_info, is_signed_in);
234e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  scoped_ptr<Event> event(new Event(api::identity::OnSignInChanged::kEventName,
235e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                    args.Pass(),
236e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                    browser_context_));
237e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
2380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
239e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
240e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
241e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityAPI::AddShutdownObserver(ShutdownObserver* observer) {
242e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shutdown_observer_list_.AddObserver(observer);
243e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
244e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
245e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityAPI::RemoveShutdownObserver(ShutdownObserver* observer) {
246e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shutdown_observer_list_.RemoveObserver(observer);
247e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
248e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IdentityAPI::SetAccountStateForTest(gaia::AccountIds ids,
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                         bool is_signed_in) {
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  account_tracker_.SetAccountStateForTest(ids, is_signed_in);
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
254e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochtemplate <>
255e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid BrowserContextKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() {
256e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
257e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
258e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
259e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)IdentityGetAccountsFunction::IdentityGetAccountsFunction() {
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)IdentityGetAccountsFunction::~IdentityGetAccountsFunction() {
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ExtensionFunction::ResponseAction IdentityGetAccountsFunction::Run() {
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (GetProfile()->IsOffTheRecord()) {
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return RespondNow(Error(identity_constants::kOffTheRecord));
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<std::string> gaia_ids =
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      IdentityAPI::GetFactoryInstance()->Get(GetProfile())->GetAccounts();
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(gaia_ids.size() < 2 || switches::IsExtensionsMultiAccount());
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::ListValue* infos = new base::ListValue();
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (std::vector<std::string>::const_iterator it = gaia_ids.begin();
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       it != gaia_ids.end();
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       ++it) {
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    api::identity::AccountInfo account_info;
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    account_info.id = *it;
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    infos->Append(account_info.ToValue().release());
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return RespondNow(OneArgument(infos));
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction()
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : OAuth2TokenService::Consumer("extensions_identity_api"),
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      should_prompt_for_scopes_(false),
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      should_prompt_for_signin_(false) {
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_END0("identity", "IdentityGetAuthTokenFunction", this);
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
298010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool IdentityGetAuthTokenFunction::RunAsync() {
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  TRACE_EVENT_ASYNC_BEGIN1("identity",
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           "IdentityGetAuthTokenFunction",
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           this,
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           "extension",
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           extension()->id());
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (GetProfile()->IsOffTheRecord()) {
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_ = identity_constants::kOffTheRecord;
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<identity::GetAuthToken::Params> params(
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      identity::GetAuthToken::Params::Create(*args_));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool interactive = params->details.get() &&
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      params->details->interactive.get() &&
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      *params->details->interactive;
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  should_prompt_for_scopes_ = interactive;
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  should_prompt_for_signin_ = interactive;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension());
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check that the necessary information is present in the manifest.
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  oauth2_client_id_ = GetOAuth2ClientId();
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (oauth2_client_id_.empty()) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = identity_constants::kInvalidClientId;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::set<std::string> scopes(oauth2_info.scopes.begin(),
330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                               oauth2_info.scopes.end());
33146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
33246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::string account_key = GetPrimaryAccountId(GetProfile());
33346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (params->details.get()) {
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (params->details->account.get()) {
336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      std::string detail_key =
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          extensions::IdentityAPI::GetFactoryInstance()
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              ->Get(GetProfile())
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              ->FindAccountKeyByGaiaId(params->details->account->id);
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (detail_key != account_key) {
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (detail_key.empty() || !switches::IsExtensionsMultiAccount()) {
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          // TODO(courage): should this be a different error?
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          error_ = identity_constants::kUserNotSignedIn;
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          return false;
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        }
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        account_key = detail_key;
34946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
35146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (params->details->scopes.get()) {
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      scopes = std::set<std::string>(params->details->scopes->begin(),
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                     params->details->scopes->end());
35546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
35646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
35746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (scopes.size() == 0) {
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error_ = identity_constants::kInvalidScopes;
360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
36346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  token_key_.reset(
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new ExtensionTokenKey(extension()->id(), account_key, scopes));
365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
366e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // From here on out, results must be returned asynchronously.
367e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  StartAsyncRun();
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_CHROMEOS)
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  policy::BrowserPolicyConnectorChromeOS* connector =
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_browser_process->platform_part()->browser_policy_connector_chromeos();
3726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (user_manager::UserManager::Get()->IsLoggedInAsKioskApp() &&
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      connector->IsEnterpriseManaged()) {
374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return true;
376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!HasLoginToken()) {
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_prompt_for_signin_) {
381e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      CompleteFunctionWithError(identity_constants::kUserNotSignedIn);
382e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return true;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Display a login prompt.
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    StartSigninFlow();
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
393e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityGetAuthTokenFunction::StartAsyncRun() {
394e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Balanced in CompleteAsyncRun
395e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  AddRef();
396e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  extensions::IdentityAPI::GetFactoryInstance()
397e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ->Get(GetProfile())
398e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ->AddShutdownObserver(this);
399e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
400e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
401e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityGetAuthTokenFunction::CompleteAsyncRun(bool success) {
402e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  extensions::IdentityAPI::GetFactoryInstance()
403e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ->Get(GetProfile())
404e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ->RemoveShutdownObserver(this);
405e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
406e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  SendResponse(success);
407e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  Release();  // Balanced in StartAsyncRun
408e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
409e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::CompleteFunctionWithResult(
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& access_token) {
412e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
4133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  SetResult(new base::StringValue(access_token));
414e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CompleteAsyncRun(true);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::CompleteFunctionWithError(
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error) {
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST1("identity",
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "CompleteFunctionWithError",
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "error",
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               error);
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_ = error;
426e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CompleteAsyncRun(false);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::StartSigninFlow() {
430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // All cached tokens are invalid because the user is not signed in.
431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IdentityAPI* id_api =
432a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::IdentityAPI::GetFactoryInstance()->Get(GetProfile());
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  id_api->EraseAllCachedTokens();
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Display a login prompt. If the subsequent mint fails, don't display the
435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // login prompt again.
436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  should_prompt_for_signin_ = false;
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ShowLoginPopup();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::StartMintTokenFlow(
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IdentityMintRequestQueue::MintType type) {
442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  mint_token_flow_type_ = type;
443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Flows are serialized to prevent excessive traffic to GAIA, and
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // to consolidate UI pop-ups.
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IdentityAPI* id_api =
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::IdentityAPI::GetFactoryInstance()->Get(GetProfile());
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!should_prompt_for_scopes_) {
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Caller requested no interaction.
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (type == IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE) {
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // GAIA told us to do a consent UI.
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CompleteFunctionWithError(identity_constants::kNoGrant);
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!id_api->mint_queue()->empty(
458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE, *token_key_)) {
459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Another call is going through a consent UI.
460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CompleteFunctionWithError(identity_constants::kNoGrant);
461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  id_api->mint_queue()->RequestStart(type, *token_key_, this);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::CompleteMintTokenFlow() {
468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IdentityMintRequestQueue::MintType type = mint_token_flow_type_;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  extensions::IdentityAPI::GetFactoryInstance()
471a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ->Get(GetProfile())
4721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      ->mint_queue()
473a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ->RequestComplete(type, *token_key_, this);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::StartMintToken(
477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IdentityMintRequestQueue::MintType type) {
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST1("identity",
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "StartMintToken",
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "type",
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               type);
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension());
486a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  IdentityAPI* id_api = IdentityAPI::GetFactoryInstance()->Get(GetProfile());
487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  IdentityTokenCacheValue cache_entry = id_api->GetCachedToken(*token_key_);
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IdentityTokenCacheValue::CacheValueStatus cache_status =
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cache_entry.status();
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (type == IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE) {
492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    switch (cache_status) {
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      case IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND:
494868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(OS_CHROMEOS)
495868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // Always force minting token for ChromeOS kiosk app.
4966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if (user_manager::UserManager::Get()->IsLoggedInAsKioskApp()) {
4978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          policy::BrowserPolicyConnectorChromeOS* connector =
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              g_browser_process->platform_part()
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  ->browser_policy_connector_chromeos();
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (connector->IsEnterpriseManaged()) {
5028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            StartDeviceLoginAccessTokenRequest();
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          } else {
5047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            StartLoginAccessTokenRequest();
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          }
506868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          return;
507868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        if (oauth2_info.auto_approve)
5117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          // oauth2_info.auto_approve is protected by a whitelist in
5127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          // _manifest_features.json hence only selected extensions take
5137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          // advantage of forcefully minting the token.
5147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
5157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        else
5167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE;
5177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        StartLoginAccessTokenRequest();
518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      case IdentityTokenCacheValue::CACHE_STATUS_TOKEN:
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        CompleteMintTokenFlow();
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        CompleteFunctionWithResult(cache_entry.token());
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      case IdentityTokenCacheValue::CACHE_STATUS_ADVICE:
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        CompleteMintTokenFlow();
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        should_prompt_for_signin_ = false;
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        issue_advice_ = cache_entry.issue_advice();
529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE);
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(type == IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE);
534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (cache_status == IdentityTokenCacheValue::CACHE_STATUS_TOKEN) {
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CompleteMintTokenFlow();
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CompleteFunctionWithResult(cache_entry.token());
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ShowOAuthApprovalDialog(issue_advice_);
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::OnMintTokenSuccess(
545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& access_token, int time_to_live) {
5465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST0("identity",
5475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
5485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
5495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnMintTokenSuccess");
5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IdentityTokenCacheValue token(access_token,
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                base::TimeDelta::FromSeconds(time_to_live));
553a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
554a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *token_key_, token);
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteMintTokenFlow();
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteFunctionWithResult(access_token);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
560c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::OnMintTokenFailure(
561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GoogleServiceAuthError& error) {
5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST1("identity",
5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
5655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnMintTokenFailure",
5665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "error",
5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               error.ToString());
568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteMintTokenFlow();
569c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (error.state()) {
571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DELETED:
573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DISABLED:
574116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // TODO(courage): flush ticket and retry once
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (should_prompt_for_signin_) {
576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Display a login prompt and try again (once).
577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        StartSigninFlow();
578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return;
579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Return error to caller.
583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteFunctionWithError(
587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string(identity_constants::kAuthFailure) + error.ToString());
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const IssueAdviceInfo& issue_advice) {
5925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST0("identity",
5935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
5945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
5955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnIssueAdviceSuccess");
5965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
597a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
598a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *token_key_, IdentityTokenCacheValue(issue_advice));
599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteMintTokenFlow();
600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  should_prompt_for_signin_ = false;
602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Existing grant was revoked and we used NO_FORCE, so we got info back
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // instead. Start a consent UI if we can.
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  issue_advice_ = issue_advice;
605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE);
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid IdentityGetAuthTokenFunction::SigninSuccess() {
6095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST0("identity",
6105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
6115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "SigninSuccess");
6135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If there was no account associated this profile before the
6155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // sign-in, we may not have an account_id in the token_key yet.
6165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (token_key_->account_id.empty()) {
6175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    token_key_->account_id = GetPrimaryAccountId(GetProfile());
6185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
620c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::SigninFailed() {
6245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST0("identity",
6255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
6265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
6275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "SigninFailed");
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteFunctionWithError(identity_constants::kUserNotSignedIn);
629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
63190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void IdentityGetAuthTokenFunction::OnGaiaFlowFailure(
63290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GaiaWebAuthFlow::Failure failure,
63390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GoogleServiceAuthError service_error,
63490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& oauth_error) {
63590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CompleteMintTokenFlow();
63690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string error;
63790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
63890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (failure) {
63990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case GaiaWebAuthFlow::WINDOW_CLOSED:
64090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      error = identity_constants::kUserRejected;
64190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
64290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
64390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case GaiaWebAuthFlow::INVALID_REDIRECT:
64490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      error = identity_constants::kInvalidRedirect;
64590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
64690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
64790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case GaiaWebAuthFlow::SERVICE_AUTH_ERROR:
64890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      error = std::string(identity_constants::kAuthFailure) +
64990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          service_error.ToString();
65090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
65190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
65290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case GaiaWebAuthFlow::OAUTH_ERROR:
65390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      error = MapOAuth2ErrorToDescription(oauth_error);
65490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
65590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
656868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case GaiaWebAuthFlow::LOAD_FAILED:
657868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      error = identity_constants::kPageLoadFailure;
658868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
659868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
66090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    default:
66190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      NOTREACHED() << "Unexpected error from gaia web auth flow: " << failure;
66290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      error = identity_constants::kInvalidRedirect;
66390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
66490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
66590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
66690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CompleteFunctionWithError(error);
667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
66990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void IdentityGetAuthTokenFunction::OnGaiaFlowCompleted(
67090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& access_token,
67190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& expiration) {
6725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST0("identity",
6735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
6745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
6755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnGaiaFlowCompleted");
67690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int time_to_live;
67790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!expiration.empty() && base::StringToInt(expiration, &time_to_live)) {
67890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    IdentityTokenCacheValue token_value(
67990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        access_token, base::TimeDelta::FromSeconds(time_to_live));
680a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
681a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        *token_key_, token_value);
68290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
68390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
684c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CompleteMintTokenFlow();
68590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CompleteFunctionWithResult(access_token);
686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
688eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid IdentityGetAuthTokenFunction::OnGetTokenSuccess(
689eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const OAuth2TokenService::Request* request,
690eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& access_token,
691eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::Time& expiration_time) {
6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST1("identity",
6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
6945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
6955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnGetTokenSuccess",
6965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "account",
6975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               request->GetAccountId());
6988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  login_token_request_.reset();
6998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  StartGaiaRequest(access_token);
700eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
701eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
702eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid IdentityGetAuthTokenFunction::OnGetTokenFailure(
703eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const OAuth2TokenService::Request* request,
704eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const GoogleServiceAuthError& error) {
7055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST1("identity",
7065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "IdentityGetAuthTokenFunction",
7075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
7085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnGetTokenFailure",
7095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "error",
7105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               error.ToString());
7118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  login_token_request_.reset();
712eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  OnGaiaFlowFailure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error, std::string());
713eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
714eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
715e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid IdentityGetAuthTokenFunction::OnShutdown() {
716e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  gaia_web_auth_flow_.reset();
717e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  signin_flow_.reset();
718e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  login_token_request_.reset();
719e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  extensions::IdentityAPI::GetFactoryInstance()
720e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ->Get(GetProfile())
721e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ->mint_queue()
722e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ->RequestCancel(*token_key_, this);
723e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CompleteFunctionWithError(identity_constants::kCanceled);
724e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
725e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
7268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(OS_CHROMEOS)
7278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void IdentityGetAuthTokenFunction::StartDeviceLoginAccessTokenRequest() {
728a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  chromeos::DeviceOAuth2TokenService* service =
729a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      chromeos::DeviceOAuth2TokenServiceFactory::Get();
7308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Since robot account refresh tokens are scoped down to [any-api] only,
7318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // request access token for [any-api] instead of login.
7328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  OAuth2TokenService::ScopeSet scopes;
7338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
7348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  login_token_request_ =
7358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      service->StartRequest(service->GetRobotAccountId(),
7368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            scopes,
7378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                            this);
7388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
7398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
7408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
7417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest() {
742a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ProfileOAuth2TokenService* service =
7431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
744a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#if defined(OS_CHROMEOS)
745a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (chrome::IsRunningInForcedAppMode()) {
746a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::string app_client_id;
747a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::string app_client_secret;
748116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (chromeos::UserSessionManager::GetInstance()->
749116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            GetAppModeChromeClientOAuthInfo(&app_client_id,
750116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                            &app_client_secret)) {
751a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      login_token_request_ =
75246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          service->StartRequestForClient(token_key_->account_id,
75368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                         app_client_id,
754a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                         app_client_secret,
755a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                         OAuth2TokenService::ScopeSet(),
756a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                         this);
757a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return;
758a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
759a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
760a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif
76168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  login_token_request_ = service->StartRequest(
76246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      token_key_->account_id, OAuth2TokenService::ScopeSet(), this);
7637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
7647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
765c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::StartGaiaRequest(
7667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& login_access_token) {
7677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!login_access_token.empty());
7687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  mint_token_flow_.reset(CreateMintTokenFlow(login_access_token));
769c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  mint_token_flow_->Start();
770c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
771c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
772c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityGetAuthTokenFunction::ShowLoginPopup() {
7731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  signin_flow_.reset(new IdentitySigninFlow(this, GetProfile()));
774c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  signin_flow_->Start();
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog(
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const IssueAdviceInfo& issue_advice) {
7791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const std::string locale = extension_l10n_util::CurrentLocaleOrDefault();
78090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
781f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gaia_web_auth_flow_.reset(new GaiaWebAuthFlow(
782f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      this, GetProfile(), token_key_.get(), oauth2_client_id_, locale));
78390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gaia_web_auth_flow_->Start();
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow(
7877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& login_access_token) {
7881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  OAuth2MintTokenFlow* mint_token_flow = new OAuth2MintTokenFlow(
7891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      GetProfile()->GetRequestContext(),
7901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      this,
791f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      OAuth2MintTokenFlow::Parameters(
792f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          login_access_token,
7935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          extension()->id(),
794f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          oauth2_client_id_,
795f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          std::vector<std::string>(token_key_->scopes.begin(),
796f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   token_key_->scopes.end()),
797f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          gaia_mint_token_mode_));
798c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return mint_token_flow;
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IdentityGetAuthTokenFunction::HasLoginToken() const {
80268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ProfileOAuth2TokenService* token_service =
8031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
80446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return token_service->RefreshTokenIsAvailable(token_key_->account_id);
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
80790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string IdentityGetAuthTokenFunction::MapOAuth2ErrorToDescription(
80890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& error) {
80990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kOAuth2ErrorAccessDenied[] = "access_denied";
81090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kOAuth2ErrorInvalidScope[] = "invalid_scope";
81190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
81290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (error == kOAuth2ErrorAccessDenied)
81390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return std::string(identity_constants::kUserRejected);
81490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  else if (error == kOAuth2ErrorInvalidScope)
81590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return std::string(identity_constants::kInvalidScopes);
81690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  else
81790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return std::string(identity_constants::kAuthFailure) + error;
81890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
81990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
820eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstd::string IdentityGetAuthTokenFunction::GetOAuth2ClientId() const {
8215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension());
822eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string client_id = oauth2_info.client_id;
823eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
824eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Component apps using auto_approve may use Chrome's client ID by
825eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // omitting the field.
8265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (client_id.empty() && extension()->location() == Manifest::COMPONENT &&
827eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      oauth2_info.auto_approve) {
828eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
829eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
830eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return client_id;
831eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
832eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
833f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IdentityGetProfileUserInfoFunction::IdentityGetProfileUserInfoFunction() {
834f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
835f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
836f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IdentityGetProfileUserInfoFunction::~IdentityGetProfileUserInfoFunction() {
837f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
838f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
839f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ExtensionFunction::ResponseAction IdentityGetProfileUserInfoFunction::Run() {
840f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (GetProfile()->IsOffTheRecord()) {
841f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return RespondNow(Error(identity_constants::kOffTheRecord));
842f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
843f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
844f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  api::identity::ProfileUserInfo profile_user_info;
8455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (extension()->permissions_data()->HasAPIPermission(
846116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          APIPermission::kIdentityEmail)) {
847116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    profile_user_info.email =
848116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        GetProfile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername);
849116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
850f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  profile_user_info.id =
851f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      GetProfile()->GetPrefs()->GetString(prefs::kGoogleServicesUserAccountId);
852f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
853f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return RespondNow(OneArgument(profile_user_info.ToValue().release()));
854f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
855f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IdentityRemoveCachedAuthTokenFunction::IdentityRemoveCachedAuthTokenFunction() {
857c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IdentityRemoveCachedAuthTokenFunction::
860c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ~IdentityRemoveCachedAuthTokenFunction() {
861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
862c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool IdentityRemoveCachedAuthTokenFunction::RunSync() {
8641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (GetProfile()->IsOffTheRecord()) {
865c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_ = identity_constants::kOffTheRecord;
866c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
867c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
868c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
869c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<identity::RemoveCachedAuthToken::Params> params(
870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      identity::RemoveCachedAuthToken::Params::Create(*args_));
871c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
872a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  IdentityAPI::GetFactoryInstance()->Get(GetProfile())->EraseCachedToken(
8735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extension()->id(), params->details.token);
874c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
876c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IdentityLaunchWebAuthFlowFunction::IdentityLaunchWebAuthFlowFunction() {}
87890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
87990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)IdentityLaunchWebAuthFlowFunction::~IdentityLaunchWebAuthFlowFunction() {
88090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (auth_flow_)
88190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    auth_flow_.release()->DetachDelegateAndDelete();
88290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
884010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool IdentityLaunchWebAuthFlowFunction::RunAsync() {
8851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (GetProfile()->IsOffTheRecord()) {
886c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_ = identity_constants::kOffTheRecord;
887c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
888c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
889c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
890c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<identity::LaunchWebAuthFlow::Params> params(
891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      identity::LaunchWebAuthFlow::Params::Create(*args_));
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
894c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL auth_url(params->details.url);
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebAuthFlow::Mode mode =
896c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      params->details.interactive && *params->details.interactive ?
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WebAuthFlow::INTERACTIVE : WebAuthFlow::SILENT;
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
899c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set up acceptable target URLs. (Does not include chrome-extension
900c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // scheme for this version of the API.)
9015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  InitFinalRedirectURLPrefix(extension()->id());
902c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();  // Balanced in OnAuthFlowSuccess/Failure.
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  auth_flow_.reset(new WebAuthFlow(this, GetProfile(), auth_url, mode));
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_flow_->Start();
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
910b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLPrefixForTest(
911c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& extension_id) {
912b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  InitFinalRedirectURLPrefix(extension_id);
913c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
914c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
915b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLPrefix(
916c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& extension_id) {
917b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (final_url_prefix_.is_empty()) {
918b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    final_url_prefix_ = GURL(base::StringPrintf(
919b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        kChromiumDomainRedirectUrlPattern, extension_id.c_str()));
920b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
921c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
922c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
923c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure(
924c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    WebAuthFlow::Failure failure) {
925c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (failure) {
926c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case WebAuthFlow::WINDOW_CLOSED:
927c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      error_ = identity_constants::kUserRejected;
928c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
929c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case WebAuthFlow::INTERACTION_REQUIRED:
930c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      error_ = identity_constants::kInteractionRequired;
931c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
932868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case WebAuthFlow::LOAD_FAILED:
933868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      error_ = identity_constants::kPageLoadFailure;
934868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
935c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
936c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NOTREACHED() << "Unexpected error from web auth flow: " << failure;
937c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      error_ = identity_constants::kInvalidRedirect;
938c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
939c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendResponse(false);
941010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Release();  // Balanced in RunAsync.
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
944c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IdentityLaunchWebAuthFlowFunction::OnAuthFlowURLChange(
945c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& redirect_url) {
946b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (redirect_url.GetWithEmptyPath() == final_url_prefix_) {
9473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    SetResult(new base::StringValue(redirect_url.spec()));
948c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SendResponse(true);
949010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Release();  // Balanced in RunAsync.
950c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
951c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
952c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
954