identity_api.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/extensions/api/identity/identity_api.h" 6 7#include "base/values.h" 8#include "chrome/common/extensions/api/experimental_identity.h" 9#include "chrome/browser/extensions/extension_install_prompt.h" 10#include "chrome/browser/extensions/extension_function_dispatcher.h" 11#include "chrome/browser/extensions/extension_service.h" 12#include "chrome/browser/extensions/permissions_updater.h" 13#include "chrome/browser/signin/token_service.h" 14#include "chrome/browser/signin/token_service_factory.h" 15#include "chrome/browser/ui/browser.h" 16#include "chrome/browser/ui/browser_navigator.h" 17#include "chrome/browser/ui/webui/signin/login_ui_service.h" 18#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" 19#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h" 20#include "chrome/common/extensions/extension.h" 21#include "chrome/common/url_constants.h" 22#include "content/public/common/page_transition_types.h" 23#include "googleurl/src/gurl.h" 24#include "webkit/glue/window_open_disposition.h" 25 26namespace extensions { 27 28namespace identity_constants { 29const char kInvalidClientId[] = "Invalid OAuth2 Client ID."; 30const char kInvalidScopes[] = "Invalid OAuth2 scopes."; 31const char kAuthFailure[] = "OAuth2 request failed: "; 32const char kNoGrant[] = "OAuth2 not granted or revoked."; 33const char kUserRejected[] = "The user did not approve access."; 34const char kUserNotSignedIn[] = "The user is not signed in."; 35const char kInvalidRedirect[] = "Did not redirect to the right URL."; 36} 37 38namespace GetAuthToken = extensions::api::experimental_identity::GetAuthToken; 39namespace LaunchWebAuthFlow = 40 extensions::api::experimental_identity::LaunchWebAuthFlow; 41namespace identity = extensions::api::experimental_identity; 42 43IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction() 44 : interactive_(false) {} 45IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {} 46 47bool IdentityGetAuthTokenFunction::RunImpl() { 48 scoped_ptr<GetAuthToken::Params> params(GetAuthToken::Params::Create(*args_)); 49 EXTENSION_FUNCTION_VALIDATE(params.get()); 50 if (params->details.get() && params->details->interactive.get()) 51 interactive_ = *params->details->interactive; 52 53 const Extension::OAuth2Info& oauth2_info = GetExtension()->oauth2_info(); 54 55 // Check that the necessary information is present in the manfist. 56 if (oauth2_info.client_id.empty()) { 57 error_ = identity_constants::kInvalidClientId; 58 return false; 59 } 60 61 if (oauth2_info.scopes.size() == 0) { 62 error_ = identity_constants::kInvalidScopes; 63 return false; 64 } 65 66 // Balanced in OnIssueAdviceSuccess|OnMintTokenSuccess|OnMintTokenFailure| 67 // InstallUIAbort|OnLoginUIClosed. 68 AddRef(); 69 70 if (!HasLoginToken()) { 71 if (StartLogin()) { 72 return true; 73 } else { 74 Release(); 75 return false; 76 } 77 } 78 79 if (StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE)) { 80 return true; 81 } else { 82 Release(); 83 return false; 84 } 85} 86 87void IdentityGetAuthTokenFunction::OnMintTokenSuccess( 88 const std::string& access_token) { 89 SetResult(Value::CreateStringValue(access_token)); 90 SendResponse(true); 91 Release(); // Balanced in RunImpl. 92} 93 94void IdentityGetAuthTokenFunction::OnMintTokenFailure( 95 const GoogleServiceAuthError& error) { 96 error_ = std::string(identity_constants::kAuthFailure) + error.ToString(); 97 SendResponse(false); 98 Release(); // Balanced in RunImpl. 99} 100 101void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess( 102 const IssueAdviceInfo& issue_advice) { 103 // Existing grant was revoked and we used NO_FORCE, so we got info back 104 // instead. 105 if (interactive_) { 106 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); 107 ShowOAuthApprovalDialog(issue_advice); 108 } else { 109 error_ = identity_constants::kNoGrant; 110 SendResponse(false); 111 Release(); // Balanced in RunImpl. 112 } 113} 114 115void IdentityGetAuthTokenFunction::OnLoginUIClosed( 116 LoginUIService::LoginUI* ui) { 117 StopObservingLoginService(); 118 if (!StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE)) { 119 SendResponse(false); 120 Release(); 121 } 122} 123 124void IdentityGetAuthTokenFunction::InstallUIProceed() { 125 DCHECK(install_ui_->record_oauth2_grant()); 126 // The user has accepted the scopes, so we may now force (recording a grant 127 // and receiving a token). 128 bool success = StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE); 129 DCHECK(success); 130} 131 132void IdentityGetAuthTokenFunction::InstallUIAbort(bool user_initiated) { 133 error_ = identity_constants::kUserRejected; 134 SendResponse(false); 135 Release(); // Balanced in RunImpl. 136} 137 138bool IdentityGetAuthTokenFunction::StartFlow(OAuth2MintTokenFlow::Mode mode) { 139 if (!HasLoginToken()) { 140 error_ = identity_constants::kUserNotSignedIn; 141 return false; 142 } 143 144 flow_.reset(CreateMintTokenFlow(mode)); 145 flow_->Start(); 146 return true; 147} 148 149bool IdentityGetAuthTokenFunction::StartLogin() { 150 if (!interactive_) { 151 error_ = identity_constants::kUserNotSignedIn; 152 return false; 153 } 154 155 ShowLoginPopup(); 156 return true; 157} 158 159void IdentityGetAuthTokenFunction::StartObservingLoginService() { 160 LoginUIService* login_ui_service = 161 LoginUIServiceFactory::GetForProfile(profile()); 162 login_ui_service->AddObserver(this); 163} 164 165void IdentityGetAuthTokenFunction::StopObservingLoginService() { 166 LoginUIService* login_ui_service = 167 LoginUIServiceFactory::GetForProfile(profile()); 168 login_ui_service->RemoveObserver(this); 169} 170 171void IdentityGetAuthTokenFunction::ShowLoginPopup() { 172 StartObservingLoginService(); 173 174 LoginUIService* login_ui_service = 175 LoginUIServiceFactory::GetForProfile(profile()); 176 login_ui_service->ShowLoginPopup(); 177} 178 179void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog( 180 const IssueAdviceInfo& issue_advice) { 181 install_ui_->ConfirmIssueAdvice(this, GetExtension(), issue_advice); 182} 183 184OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow( 185 OAuth2MintTokenFlow::Mode mode) { 186 const Extension::OAuth2Info& oauth2_info = GetExtension()->oauth2_info(); 187 TokenService* token_service = TokenServiceFactory::GetForProfile(profile()); 188 return new OAuth2MintTokenFlow( 189 profile()->GetRequestContext(), 190 this, 191 OAuth2MintTokenFlow::Parameters( 192 token_service->GetOAuth2LoginRefreshToken(), 193 GetExtension()->id(), 194 oauth2_info.client_id, 195 oauth2_info.scopes, 196 mode)); 197} 198 199bool IdentityGetAuthTokenFunction::HasLoginToken() const { 200 TokenService* token_service = TokenServiceFactory::GetForProfile(profile()); 201 return token_service->HasOAuthLoginToken(); 202} 203 204IdentityLaunchWebAuthFlowFunction::IdentityLaunchWebAuthFlowFunction() {} 205IdentityLaunchWebAuthFlowFunction::~IdentityLaunchWebAuthFlowFunction() {} 206 207bool IdentityLaunchWebAuthFlowFunction::RunImpl() { 208 scoped_ptr<LaunchWebAuthFlow::Params> params( 209 LaunchWebAuthFlow::Params::Create(*args_)); 210 EXTENSION_FUNCTION_VALIDATE(params.get()); 211 const identity::WebAuthFlowDetails& details = params->details; 212 213 GURL auth_url(details.url); 214 WebAuthFlow::Mode mode = 215 details.interactive && *details.interactive ? 216 WebAuthFlow::INTERACTIVE : WebAuthFlow::SILENT; 217 218 // The bounds attributes are optional, but using 0 when they're not available 219 // does the right thing. 220 gfx::Rect initial_bounds; 221 if (details.width) 222 initial_bounds.set_width(*details.width); 223 if (details.height) 224 initial_bounds.set_height(*details.height); 225 if (details.left) 226 initial_bounds.set_x(*details.left); 227 if (details.top) 228 initial_bounds.set_y(*details.top); 229 230 AddRef(); // Balanced in OnAuthFlowSuccess/Failure. 231 auth_flow_.reset(new WebAuthFlow( 232 this, profile(), GetExtension()->id(), auth_url, mode, initial_bounds)); 233 auth_flow_->Start(); 234 return true; 235} 236 237void IdentityLaunchWebAuthFlowFunction::OnAuthFlowSuccess( 238 const std::string& redirect_url) { 239 SetResult(Value::CreateStringValue(redirect_url)); 240 SendResponse(true); 241 Release(); // Balanced in RunImpl. 242} 243 244void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure() { 245 error_ = identity_constants::kInvalidRedirect; 246 SendResponse(false); 247 Release(); // Balanced in RunImpl. 248} 249 250} // namespace extensions 251