This source file includes following definitions.
- GetPrimaryAccountId
- issue_advice_
- token_
- status
- issue_advice
- token
- is_expired
- expiration_time
- account_tracker_
- mint_queue
- SetCachedToken
- EraseCachedToken
- EraseAllCachedTokens
- GetCachedToken
- GetAllCachedTokens
- ReportAuthError
- GetAuthStatusForTest
- Shutdown
- GetFactoryInstance
- OnAccountAdded
- OnAccountRemoved
- OnAccountSignInChanged
- AddShutdownObserver
- RemoveShutdownObserver
- DeclareFactoryDependencies
- should_prompt_for_signin_
- RunImpl
- StartAsyncRun
- CompleteAsyncRun
- CompleteFunctionWithResult
- CompleteFunctionWithError
- StartSigninFlow
- StartMintTokenFlow
- CompleteMintTokenFlow
- StartMintToken
- OnMintTokenSuccess
- OnMintTokenFailure
- OnIssueAdviceSuccess
- SigninSuccess
- SigninFailed
- OnGaiaFlowFailure
- OnGaiaFlowCompleted
- OnGetTokenSuccess
- OnGetTokenFailure
- OnShutdown
- StartDeviceLoginAccessTokenRequest
- StartLoginAccessTokenRequest
- StartGaiaRequest
- ShowLoginPopup
- ShowOAuthApprovalDialog
- CreateMintTokenFlow
- HasLoginToken
- MapOAuth2ErrorToDescription
- GetOAuth2ClientId
- IdentityRemoveCachedAuthTokenFunction
- RunImpl
- RunImpl
- InitFinalRedirectURLPrefixForTest
- InitFinalRedirectURLPrefix
- OnAuthFlowFailure
- OnAuthFlowURLChange
#include "chrome/browser/extensions/api/identity/identity_api.h"
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/lazy_instance.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#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/extension_service.h"
#include "chrome/browser/profiles/profile.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/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/browser/extension_system.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"
#endif
namespace extensions {
namespace identity_constants {
const char kInvalidClientId[] = "Invalid OAuth2 Client ID.";
const char kInvalidScopes[] = "Invalid OAuth2 scopes.";
const char kAuthFailure[] = "OAuth2 request failed: ";
const char kNoGrant[] = "OAuth2 not granted or revoked.";
const char kUserRejected[] = "The user did not approve access.";
const char kUserNotSignedIn[] = "The user is not signed in.";
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 {
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 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) {
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;
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_));
ExtensionSystem::Get(browser_context_)->event_router()->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()
: OAuth2TokenService::Consumer("extensions_identity_api"),
should_prompt_for_scopes_(false),
should_prompt_for_signin_(false) {}
IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {}
bool IdentityGetAuthTokenFunction::RunImpl() {
if (GetProfile()->IsOffTheRecord()) {
error_ = identity_constants::kOffTheRecord;
return false;
}
scoped_ptr<identity::GetAuthToken::Params> params(
identity::GetAuthToken::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
bool interactive = params->details.get() &&
params->details->interactive.get() &&
*params->details->interactive;
should_prompt_for_scopes_ = interactive;
should_prompt_for_signin_ = interactive;
const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
oauth2_client_id_ = GetOAuth2ClientId();
if (oauth2_client_id_.empty()) {
error_ = identity_constants::kInvalidClientId;
return false;
}
if (oauth2_info.scopes.size() == 0) {
error_ = identity_constants::kInvalidScopes;
return false;
}
std::set<std::string> scopes(oauth2_info.scopes.begin(),
oauth2_info.scopes.end());
token_key_.reset(new ExtensionTokenKey(
GetExtension()->id(), GetPrimaryAccountId(GetProfile()), scopes));
StartAsyncRun();
#if defined(OS_CHROMEOS)
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp() &&
connector->IsEnterpriseManaged()) {
StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
return true;
}
#endif
if (!HasLoginToken()) {
if (!should_prompt_for_signin_) {
CompleteFunctionWithError(identity_constants::kUserNotSignedIn);
return true;
}
StartSigninFlow();
} else {
StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
}
return true;
}
void IdentityGetAuthTokenFunction::StartAsyncRun() {
AddRef();
extensions::IdentityAPI::GetFactoryInstance()
->Get(GetProfile())
->AddShutdownObserver(this);
}
void IdentityGetAuthTokenFunction::CompleteAsyncRun(bool success) {
extensions::IdentityAPI::GetFactoryInstance()
->Get(GetProfile())
->RemoveShutdownObserver(this);
SendResponse(success);
Release();
}
void IdentityGetAuthTokenFunction::CompleteFunctionWithResult(
const std::string& access_token) {
SetResult(new base::StringValue(access_token));
CompleteAsyncRun(true);
}
void IdentityGetAuthTokenFunction::CompleteFunctionWithError(
const std::string& error) {
error_ = error;
CompleteAsyncRun(false);
}
void IdentityGetAuthTokenFunction::StartSigninFlow() {
IdentityAPI* id_api =
extensions::IdentityAPI::GetFactoryInstance()->Get(GetProfile());
id_api->EraseAllCachedTokens();
should_prompt_for_signin_ = false;
ShowLoginPopup();
}
void IdentityGetAuthTokenFunction::StartMintTokenFlow(
IdentityMintRequestQueue::MintType type) {
mint_token_flow_type_ = type;
IdentityAPI* id_api =
extensions::IdentityAPI::GetFactoryInstance()->Get(GetProfile());
if (!should_prompt_for_scopes_) {
if (type == IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE) {
CompleteFunctionWithError(identity_constants::kNoGrant);
return;
}
if (!id_api->mint_queue()->empty(
IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE, *token_key_)) {
CompleteFunctionWithError(identity_constants::kNoGrant);
return;
}
}
id_api->mint_queue()->RequestStart(type, *token_key_, this);
}
void IdentityGetAuthTokenFunction::CompleteMintTokenFlow() {
IdentityMintRequestQueue::MintType type = mint_token_flow_type_;
const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
std::set<std::string> scopes(oauth2_info.scopes.begin(),
oauth2_info.scopes.end());
extensions::IdentityAPI::GetFactoryInstance()
->Get(GetProfile())
->mint_queue()
->RequestComplete(type, *token_key_, this);
}
void IdentityGetAuthTokenFunction::StartMintToken(
IdentityMintRequestQueue::MintType type) {
const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
IdentityAPI* id_api = IdentityAPI::GetFactoryInstance()->Get(GetProfile());
IdentityTokenCacheValue cache_entry = id_api->GetCachedToken(*token_key_);
IdentityTokenCacheValue::CacheValueStatus cache_status =
cache_entry.status();
if (type == IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE) {
switch (cache_status) {
case IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND:
#if defined(OS_CHROMEOS)
if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp()) {
gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()
->browser_policy_connector_chromeos();
if (connector->IsEnterpriseManaged()) {
StartDeviceLoginAccessTokenRequest();
} else {
StartLoginAccessTokenRequest();
}
return;
}
#endif
if (oauth2_info.auto_approve)
gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
else
gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE;
StartLoginAccessTokenRequest();
break;
case IdentityTokenCacheValue::CACHE_STATUS_TOKEN:
CompleteMintTokenFlow();
CompleteFunctionWithResult(cache_entry.token());
break;
case IdentityTokenCacheValue::CACHE_STATUS_ADVICE:
CompleteMintTokenFlow();
should_prompt_for_signin_ = false;
issue_advice_ = cache_entry.issue_advice();
StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE);
break;
}
} else {
DCHECK(type == IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE);
if (cache_status == IdentityTokenCacheValue::CACHE_STATUS_TOKEN) {
CompleteMintTokenFlow();
CompleteFunctionWithResult(cache_entry.token());
} else {
ShowOAuthApprovalDialog(issue_advice_);
}
}
}
void IdentityGetAuthTokenFunction::OnMintTokenSuccess(
const std::string& access_token, int time_to_live) {
IdentityTokenCacheValue token(access_token,
base::TimeDelta::FromSeconds(time_to_live));
IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
*token_key_, token);
CompleteMintTokenFlow();
CompleteFunctionWithResult(access_token);
}
void IdentityGetAuthTokenFunction::OnMintTokenFailure(
const GoogleServiceAuthError& error) {
CompleteMintTokenFlow();
switch (error.state()) {
case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
case GoogleServiceAuthError::ACCOUNT_DELETED:
case GoogleServiceAuthError::ACCOUNT_DISABLED:
extensions::IdentityAPI::GetFactoryInstance()
->Get(GetProfile())
->ReportAuthError(error);
if (should_prompt_for_signin_) {
StartSigninFlow();
return;
}
break;
default:
break;
}
CompleteFunctionWithError(
std::string(identity_constants::kAuthFailure) + error.ToString());
}
void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
const IssueAdviceInfo& issue_advice) {
IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
*token_key_, IdentityTokenCacheValue(issue_advice));
CompleteMintTokenFlow();
should_prompt_for_signin_ = false;
issue_advice_ = issue_advice;
StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE);
}
void IdentityGetAuthTokenFunction::SigninSuccess() {
StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
}
void IdentityGetAuthTokenFunction::SigninFailed() {
CompleteFunctionWithError(identity_constants::kUserNotSignedIn);
}
void IdentityGetAuthTokenFunction::OnGaiaFlowFailure(
GaiaWebAuthFlow::Failure failure,
GoogleServiceAuthError service_error,
const std::string& oauth_error) {
CompleteMintTokenFlow();
std::string error;
switch (failure) {
case GaiaWebAuthFlow::WINDOW_CLOSED:
error = identity_constants::kUserRejected;
break;
case GaiaWebAuthFlow::INVALID_REDIRECT:
error = identity_constants::kInvalidRedirect;
break;
case GaiaWebAuthFlow::SERVICE_AUTH_ERROR:
error = std::string(identity_constants::kAuthFailure) +
service_error.ToString();
break;
case GaiaWebAuthFlow::OAUTH_ERROR:
error = MapOAuth2ErrorToDescription(oauth_error);
break;
case GaiaWebAuthFlow::LOAD_FAILED:
error = identity_constants::kPageLoadFailure;
break;
default:
NOTREACHED() << "Unexpected error from gaia web auth flow: " << failure;
error = identity_constants::kInvalidRedirect;
break;
}
CompleteFunctionWithError(error);
}
void IdentityGetAuthTokenFunction::OnGaiaFlowCompleted(
const std::string& access_token,
const std::string& expiration) {
int time_to_live;
if (!expiration.empty() && base::StringToInt(expiration, &time_to_live)) {
IdentityTokenCacheValue token_value(
access_token, base::TimeDelta::FromSeconds(time_to_live));
IdentityAPI::GetFactoryInstance()->Get(GetProfile())->SetCachedToken(
*token_key_, token_value);
}
CompleteMintTokenFlow();
CompleteFunctionWithResult(access_token);
}
void IdentityGetAuthTokenFunction::OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
const std::string& access_token,
const base::Time& expiration_time) {
login_token_request_.reset();
StartGaiaRequest(access_token);
}
void IdentityGetAuthTokenFunction::OnGetTokenFailure(
const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) {
login_token_request_.reset();
OnGaiaFlowFailure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error, std::string());
}
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);
}
#if defined(OS_CHROMEOS)
void IdentityGetAuthTokenFunction::StartDeviceLoginAccessTokenRequest() {
chromeos::DeviceOAuth2TokenService* service =
chromeos::DeviceOAuth2TokenServiceFactory::Get();
OAuth2TokenService::ScopeSet scopes;
scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
login_token_request_ =
service->StartRequest(service->GetRobotAccountId(),
scopes,
this);
}
#endif
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;
std::string app_client_secret;
if (chromeos::UserManager::Get()->GetAppModeChromeClientOAuthInfo(
&app_client_id, &app_client_secret)) {
login_token_request_ =
service->StartRequestForClient(primary_account_id,
app_client_id,
app_client_secret,
OAuth2TokenService::ScopeSet(),
this);
return;
}
}
#endif
login_token_request_ = service->StartRequest(
primary_account_id, OAuth2TokenService::ScopeSet(), this);
}
void IdentityGetAuthTokenFunction::StartGaiaRequest(
const std::string& login_access_token) {
DCHECK(!login_access_token.empty());
mint_token_flow_.reset(CreateMintTokenFlow(login_access_token));
mint_token_flow_->Start();
}
void IdentityGetAuthTokenFunction::ShowLoginPopup() {
signin_flow_.reset(new IdentitySigninFlow(this, GetProfile()));
signin_flow_->Start();
}
void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog(
const IssueAdviceInfo& issue_advice) {
const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
const std::string locale = g_browser_process->local_state()->GetString(
prefs::kApplicationLocale);
gaia_web_auth_flow_.reset(new GaiaWebAuthFlow(
this, GetProfile(), GetExtension()->id(), oauth2_info, locale));
gaia_web_auth_flow_->Start();
}
OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow(
const std::string& login_access_token) {
const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
OAuth2MintTokenFlow* mint_token_flow = new OAuth2MintTokenFlow(
GetProfile()->GetRequestContext(),
this,
OAuth2MintTokenFlow::Parameters(login_access_token,
GetExtension()->id(),
oauth2_client_id_,
oauth2_info.scopes,
gaia_mint_token_mode_));
return mint_token_flow;
}
bool IdentityGetAuthTokenFunction::HasLoginToken() const {
ProfileOAuth2TokenService* token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
return token_service->RefreshTokenIsAvailable(
GetPrimaryAccountId(GetProfile()));
}
std::string IdentityGetAuthTokenFunction::MapOAuth2ErrorToDescription(
const std::string& error) {
const char kOAuth2ErrorAccessDenied[] = "access_denied";
const char kOAuth2ErrorInvalidScope[] = "invalid_scope";
if (error == kOAuth2ErrorAccessDenied)
return std::string(identity_constants::kUserRejected);
else if (error == kOAuth2ErrorInvalidScope)
return std::string(identity_constants::kInvalidScopes);
else
return std::string(identity_constants::kAuthFailure) + error;
}
std::string IdentityGetAuthTokenFunction::GetOAuth2ClientId() const {
const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
std::string client_id = oauth2_info.client_id;
if (client_id.empty() && GetExtension()->location() == Manifest::COMPONENT &&
oauth2_info.auto_approve) {
client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
}
return client_id;
}
IdentityRemoveCachedAuthTokenFunction::IdentityRemoveCachedAuthTokenFunction() {
}
IdentityRemoveCachedAuthTokenFunction::
~IdentityRemoveCachedAuthTokenFunction() {
}
bool IdentityRemoveCachedAuthTokenFunction::RunImpl() {
if (GetProfile()->IsOffTheRecord()) {
error_ = identity_constants::kOffTheRecord;
return false;
}
scoped_ptr<identity::RemoveCachedAuthToken::Params> params(
identity::RemoveCachedAuthToken::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
IdentityAPI::GetFactoryInstance()->Get(GetProfile())->EraseCachedToken(
GetExtension()->id(), params->details.token);
return true;
}
IdentityLaunchWebAuthFlowFunction::IdentityLaunchWebAuthFlowFunction() {}
IdentityLaunchWebAuthFlowFunction::~IdentityLaunchWebAuthFlowFunction() {
if (auth_flow_)
auth_flow_.release()->DetachDelegateAndDelete();
}
bool IdentityLaunchWebAuthFlowFunction::RunImpl() {
if (GetProfile()->IsOffTheRecord()) {
error_ = identity_constants::kOffTheRecord;
return false;
}
scoped_ptr<identity::LaunchWebAuthFlow::Params> params(
identity::LaunchWebAuthFlow::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
GURL auth_url(params->details.url);
WebAuthFlow::Mode mode =
params->details.interactive && *params->details.interactive ?
WebAuthFlow::INTERACTIVE : WebAuthFlow::SILENT;
InitFinalRedirectURLPrefix(GetExtension()->id());
AddRef();
auth_flow_.reset(new WebAuthFlow(this, GetProfile(), auth_url, mode));
auth_flow_->Start();
return true;
}
void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLPrefixForTest(
const std::string& extension_id) {
InitFinalRedirectURLPrefix(extension_id);
}
void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLPrefix(
const std::string& extension_id) {
if (final_url_prefix_.is_empty()) {
final_url_prefix_ = GURL(base::StringPrintf(
kChromiumDomainRedirectUrlPattern, extension_id.c_str()));
}
}
void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure(
WebAuthFlow::Failure failure) {
switch (failure) {
case WebAuthFlow::WINDOW_CLOSED:
error_ = identity_constants::kUserRejected;
break;
case WebAuthFlow::INTERACTION_REQUIRED:
error_ = identity_constants::kInteractionRequired;
break;
case WebAuthFlow::LOAD_FAILED:
error_ = identity_constants::kPageLoadFailure;
break;
default:
NOTREACHED() << "Unexpected error from web auth flow: " << failure;
error_ = identity_constants::kInvalidRedirect;
break;
}
SendResponse(false);
Release();
}
void IdentityLaunchWebAuthFlowFunction::OnAuthFlowURLChange(
const GURL& redirect_url) {
if (redirect_url.GetWithEmptyPath() == final_url_prefix_) {
SetResult(new base::StringValue(redirect_url.spec()));
SendResponse(true);
Release();
}
}
}