Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: chrome/browser/extensions/api/identity/identity_api.cc

Issue 12929014: Identity API: Pop-up a sign-in dialog if gaia credentials are bad (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: fix signin browser test for chromeos Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/identity/identity_api.h" 5 #include "chrome/browser/extensions/api/identity/identity_api.h"
6 6
7 #include "base/lazy_instance.h" 7 #include "base/lazy_instance.h"
8 #include "base/values.h" 8 #include "base/values.h"
9 #include "chrome/browser/app_mode/app_mode_utils.h" 9 #include "chrome/browser/app_mode/app_mode_utils.h"
10 #include "chrome/browser/extensions/extension_function_dispatcher.h" 10 #include "chrome/browser/extensions/extension_function_dispatcher.h"
11 #include "chrome/browser/extensions/extension_install_prompt.h" 11 #include "chrome/browser/extensions/extension_install_prompt.h"
12 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/permissions_updater.h" 13 #include "chrome/browser/extensions/permissions_updater.h"
14 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/signin/signin_manager.h"
16 #include "chrome/browser/signin/signin_manager_factory.h"
15 #include "chrome/browser/signin/token_service.h" 17 #include "chrome/browser/signin/token_service.h"
16 #include "chrome/browser/signin/token_service_factory.h" 18 #include "chrome/browser/signin/token_service_factory.h"
17 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_navigator.h"
19 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
20 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
21 #include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
22 #include "chrome/common/extensions/api/experimental_identity.h" 20 #include "chrome/common/extensions/api/experimental_identity.h"
23 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h" 21 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
24 #include "chrome/common/extensions/extension.h" 22 #include "chrome/common/extensions/extension.h"
25 #include "chrome/common/extensions/extension_manifest_constants.h" 23 #include "chrome/common/extensions/extension_manifest_constants.h"
26 #include "chrome/common/extensions/manifest_handler.h" 24 #include "chrome/common/extensions/manifest_handler.h"
27 #include "chrome/common/url_constants.h" 25 #include "chrome/common/url_constants.h"
28 #include "content/public/common/page_transition_types.h" 26 #include "content/public/common/page_transition_types.h"
27 #include "google_apis/gaia/gaia_constants.h"
29 #include "googleurl/src/gurl.h" 28 #include "googleurl/src/gurl.h"
30 #include "ui/base/window_open_disposition.h" 29 #include "ui/base/window_open_disposition.h"
31 30
32 #if defined(OS_CHROMEOS) 31 #if defined(OS_CHROMEOS)
33 #include "chrome/browser/chromeos/login/user_manager.h" 32 #include "chrome/browser/chromeos/login/user_manager.h"
34 #endif 33 #endif
35 34
36 namespace extensions { 35 namespace extensions {
37 36
38 namespace identity_constants { 37 namespace identity_constants {
39 const char kInvalidClientId[] = "Invalid OAuth2 Client ID."; 38 const char kInvalidClientId[] = "Invalid OAuth2 Client ID.";
40 const char kInvalidScopes[] = "Invalid OAuth2 scopes."; 39 const char kInvalidScopes[] = "Invalid OAuth2 scopes.";
41 const char kAuthFailure[] = "OAuth2 request failed: "; 40 const char kAuthFailure[] = "OAuth2 request failed: ";
42 const char kNoGrant[] = "OAuth2 not granted or revoked."; 41 const char kNoGrant[] = "OAuth2 not granted or revoked.";
43 const char kUserRejected[] = "The user did not approve access."; 42 const char kUserRejected[] = "The user did not approve access.";
44 const char kUserNotSignedIn[] = "The user is not signed in."; 43 const char kUserNotSignedIn[] = "The user is not signed in.";
45 const char kInvalidRedirect[] = "Did not redirect to the right URL."; 44 const char kInvalidRedirect[] = "Did not redirect to the right URL.";
46 } // namespace identity_constants 45 } // namespace identity_constants
47 46
48 namespace GetAuthToken = api::experimental_identity::GetAuthToken; 47 namespace GetAuthToken = api::experimental_identity::GetAuthToken;
49 namespace LaunchWebAuthFlow = api::experimental_identity::LaunchWebAuthFlow; 48 namespace LaunchWebAuthFlow = api::experimental_identity::LaunchWebAuthFlow;
50 namespace identity = api::experimental_identity; 49 namespace identity = api::experimental_identity;
51 50
52 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction() 51 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction()
53 : interactive_(false) {} 52 : should_prompt_for_scopes_(false),
53 should_prompt_for_signin_(false) {}
54 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {} 54 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {}
55 55
56 bool IdentityGetAuthTokenFunction::RunImpl() { 56 bool IdentityGetAuthTokenFunction::RunImpl() {
57 scoped_ptr<GetAuthToken::Params> params(GetAuthToken::Params::Create(*args_)); 57 scoped_ptr<GetAuthToken::Params> params(GetAuthToken::Params::Create(*args_));
58 EXTENSION_FUNCTION_VALIDATE(params.get()); 58 EXTENSION_FUNCTION_VALIDATE(params.get());
59 if (params->details.get() && params->details->interactive.get()) 59 bool interactive = params->details.get() &&
60 interactive_ = *params->details->interactive; 60 params->details->interactive.get() &&
61 *params->details->interactive;
62
63 should_prompt_for_scopes_ = interactive;
64 should_prompt_for_signin_ = interactive;
61 65
62 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); 66 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
63 67
64 // Check that the necessary information is present in the manfist. 68 // Check that the necessary information is present in the manifest.
65 if (oauth2_info.client_id.empty()) { 69 if (oauth2_info.client_id.empty()) {
66 error_ = identity_constants::kInvalidClientId; 70 error_ = identity_constants::kInvalidClientId;
67 return false; 71 return false;
68 } 72 }
69 73
70 if (oauth2_info.scopes.size() == 0) { 74 if (oauth2_info.scopes.size() == 0) {
71 error_ = identity_constants::kInvalidScopes; 75 error_ = identity_constants::kInvalidScopes;
72 return false; 76 return false;
73 } 77 }
74 78
75 // Balanced in OnIssueAdviceSuccess|OnMintTokenSuccess|OnMintTokenFailure| 79 // Balanced in OnIssueAdviceSuccess|OnMintTokenSuccess|OnMintTokenFailure|
76 // InstallUIAbort|OnLoginUIClosed. 80 // InstallUIAbort|SigninFailed.
77 AddRef(); 81 AddRef();
78 82
79 if (!HasLoginToken()) { 83 if (!HasLoginToken()) {
80 if (StartLogin()) { 84 if (!should_prompt_for_signin_) {
81 return true; 85 error_ = identity_constants::kUserNotSignedIn;
82 } else {
83 Release(); 86 Release();
84 return false; 87 return false;
85 } 88 }
89 // Display a login prompt. If the subsequent mint fails, don't display the
90 // prompt again.
91 should_prompt_for_signin_ = false;
92 ShowLoginPopup();
93 } else {
94 TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
95 refresh_token_ = token_service->GetOAuth2LoginRefreshToken();
96 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
86 } 97 }
87 98
88 if (StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE)) { 99 return true;
89 return true;
90 } else {
91 Release();
92 return false;
93 }
94 } 100 }
95 101
96 void IdentityGetAuthTokenFunction::OnMintTokenSuccess( 102 void IdentityGetAuthTokenFunction::OnMintTokenSuccess(
97 const std::string& access_token) { 103 const std::string& access_token) {
98 SetResult(Value::CreateStringValue(access_token)); 104 SetResult(Value::CreateStringValue(access_token));
99 SendResponse(true); 105 SendResponse(true);
100 Release(); // Balanced in RunImpl. 106 Release(); // Balanced in RunImpl.
101 } 107 }
102 108
103 void IdentityGetAuthTokenFunction::OnMintTokenFailure( 109 void IdentityGetAuthTokenFunction::OnMintTokenFailure(
104 const GoogleServiceAuthError& error) { 110 const GoogleServiceAuthError& error) {
111 switch (error.state()) {
112 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
113 case GoogleServiceAuthError::ACCOUNT_DELETED:
114 case GoogleServiceAuthError::ACCOUNT_DISABLED:
115 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
116 profile())->ReportAuthError(error);
117 if (should_prompt_for_signin_) {
118 // Display a login prompt and try again (once).
119 should_prompt_for_signin_ = false;
120 ShowLoginPopup();
121 return;
122 }
123 break;
124 default:
125 // Return error to caller.
126 break;
127 }
128
105 error_ = std::string(identity_constants::kAuthFailure) + error.ToString(); 129 error_ = std::string(identity_constants::kAuthFailure) + error.ToString();
106 SendResponse(false); 130 SendResponse(false);
107 Release(); // Balanced in RunImpl. 131 Release(); // Balanced in RunImpl.
108 } 132 }
109 133
110 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess( 134 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
111 const IssueAdviceInfo& issue_advice) { 135 const IssueAdviceInfo& issue_advice) {
136 should_prompt_for_signin_ = false;
112 // Existing grant was revoked and we used NO_FORCE, so we got info back 137 // Existing grant was revoked and we used NO_FORCE, so we got info back
113 // instead. 138 // instead.
114 if (interactive_) { 139 if (should_prompt_for_scopes_) {
115 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); 140 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents()));
116 ShowOAuthApprovalDialog(issue_advice); 141 ShowOAuthApprovalDialog(issue_advice);
117 } else { 142 } else {
118 error_ = identity_constants::kNoGrant; 143 error_ = identity_constants::kNoGrant;
119 SendResponse(false); 144 SendResponse(false);
120 Release(); // Balanced in RunImpl. 145 Release(); // Balanced in RunImpl.
121 } 146 }
122 } 147 }
123 148
124 void IdentityGetAuthTokenFunction::OnLoginUIClosed( 149 void IdentityGetAuthTokenFunction::SigninSuccess(const std::string& token) {
125 LoginUIService::LoginUI* ui) { 150 refresh_token_ = token;
126 StopObservingLoginService(); 151 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
127 if (!StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE)) { 152 }
128 SendResponse(false); 153
129 Release(); 154 void IdentityGetAuthTokenFunction::SigninFailed() {
130 } 155 error_ = identity_constants::kUserNotSignedIn;
156 SendResponse(false);
157 Release();
131 } 158 }
132 159
133 void IdentityGetAuthTokenFunction::InstallUIProceed() { 160 void IdentityGetAuthTokenFunction::InstallUIProceed() {
134 DCHECK(install_ui_->record_oauth2_grant()); 161 DCHECK(install_ui_->record_oauth2_grant());
135 // The user has accepted the scopes, so we may now force (recording a grant 162 // The user has accepted the scopes, so we may now force (recording a grant
136 // and receiving a token). 163 // and receiving a token).
137 bool success = StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE); 164 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE);
138 DCHECK(success);
139 } 165 }
140 166
141 void IdentityGetAuthTokenFunction::InstallUIAbort(bool user_initiated) { 167 void IdentityGetAuthTokenFunction::InstallUIAbort(bool user_initiated) {
142 error_ = identity_constants::kUserRejected; 168 error_ = identity_constants::kUserRejected;
143 SendResponse(false); 169 SendResponse(false);
144 Release(); // Balanced in RunImpl. 170 Release(); // Balanced in RunImpl.
145 } 171 }
146 172
147 bool IdentityGetAuthTokenFunction::StartFlow(OAuth2MintTokenFlow::Mode mode) { 173 void IdentityGetAuthTokenFunction::StartFlow(OAuth2MintTokenFlow::Mode mode) {
148 if (!HasLoginToken()) { 174 signin_flow_.reset(NULL);
149 error_ = identity_constants::kUserNotSignedIn; 175 mint_token_flow_.reset(CreateMintTokenFlow(mode));
150 return false; 176 mint_token_flow_->Start();
151 }
152
153 flow_.reset(CreateMintTokenFlow(mode));
154 flow_->Start();
155 return true;
156 }
157
158 bool IdentityGetAuthTokenFunction::StartLogin() {
159 if (!interactive_) {
160 error_ = identity_constants::kUserNotSignedIn;
161 return false;
162 }
163
164 ShowLoginPopup();
165 return true;
166 }
167
168 void IdentityGetAuthTokenFunction::StartObservingLoginService() {
169 LoginUIService* login_ui_service =
170 LoginUIServiceFactory::GetForProfile(profile());
171 login_ui_service->AddObserver(this);
172 }
173
174 void IdentityGetAuthTokenFunction::StopObservingLoginService() {
175 LoginUIService* login_ui_service =
176 LoginUIServiceFactory::GetForProfile(profile());
177 login_ui_service->RemoveObserver(this);
178 } 177 }
179 178
180 void IdentityGetAuthTokenFunction::ShowLoginPopup() { 179 void IdentityGetAuthTokenFunction::ShowLoginPopup() {
181 StartObservingLoginService(); 180 signin_flow_.reset(new IdentitySigninFlow(this, profile()));
182 181 signin_flow_->Start();
183 LoginUIService* login_ui_service =
184 LoginUIServiceFactory::GetForProfile(profile());
185 login_ui_service->ShowLoginPopup();
186 } 182 }
187 183
188 void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog( 184 void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog(
189 const IssueAdviceInfo& issue_advice) { 185 const IssueAdviceInfo& issue_advice) {
190 install_ui_->ConfirmIssueAdvice(this, GetExtension(), issue_advice); 186 install_ui_->ConfirmIssueAdvice(this, GetExtension(), issue_advice);
191 } 187 }
192 188
193 OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow( 189 OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow(
194 OAuth2MintTokenFlow::Mode mode) { 190 OAuth2MintTokenFlow::Mode mode) {
195 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); 191 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
196 TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
197 OAuth2MintTokenFlow* mint_token_flow = 192 OAuth2MintTokenFlow* mint_token_flow =
198 new OAuth2MintTokenFlow( 193 new OAuth2MintTokenFlow(
199 profile()->GetRequestContext(), 194 profile()->GetRequestContext(),
200 this, 195 this,
201 OAuth2MintTokenFlow::Parameters( 196 OAuth2MintTokenFlow::Parameters(
202 token_service->GetOAuth2LoginRefreshToken(), 197 refresh_token_,
203 GetExtension()->id(), 198 GetExtension()->id(),
204 oauth2_info.client_id, 199 oauth2_info.client_id,
205 oauth2_info.scopes, 200 oauth2_info.scopes,
206 mode)); 201 mode));
207 #if defined(OS_CHROMEOS) 202 #if defined(OS_CHROMEOS)
208 if (chrome::IsRunningInForcedAppMode()) { 203 if (chrome::IsRunningInForcedAppMode()) {
209 std::string chrome_client_id; 204 std::string chrome_client_id;
210 std::string chrome_client_secret; 205 std::string chrome_client_secret;
211 if (chromeos::UserManager::Get()->GetAppModeChromeClientOAuthInfo( 206 if (chromeos::UserManager::Get()->GetAppModeChromeClientOAuthInfo(
212 &chrome_client_id, &chrome_client_secret)) { 207 &chrome_client_id, &chrome_client_secret)) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 SendResponse(true); 262 SendResponse(true);
268 Release(); // Balanced in RunImpl. 263 Release(); // Balanced in RunImpl.
269 } 264 }
270 265
271 void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure() { 266 void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure() {
272 error_ = identity_constants::kInvalidRedirect; 267 error_ = identity_constants::kInvalidRedirect;
273 SendResponse(false); 268 SendResponse(false);
274 Release(); // Balanced in RunImpl. 269 Release(); // Balanced in RunImpl.
275 } 270 }
276 271
277 IdentityAPI::IdentityAPI(Profile* profile) { 272 IdentityAPI::IdentityAPI(Profile* profile)
273 : profile_(profile),
274 signin_manager_(NULL),
275 error_(GoogleServiceAuthError::NONE) {
278 (new OAuth2ManifestHandler)->Register(); 276 (new OAuth2ManifestHandler)->Register();
279 } 277 }
280 278
281 IdentityAPI::~IdentityAPI() { 279 IdentityAPI::~IdentityAPI() {
282 } 280 }
283 281
282 void IdentityAPI::Initialize() {
283 signin_manager_ = SigninManagerFactory::GetForProfile(profile_);
284 signin_manager_->signin_global_error()->AddProvider(this);
285
286 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
287 registrar_.Add(this,
288 chrome::NOTIFICATION_TOKEN_AVAILABLE,
289 content::Source<TokenService>(token_service));
290 }
291
292 void IdentityAPI::ReportAuthError(const GoogleServiceAuthError& error) {
293 if (!signin_manager_)
294 Initialize();
295
296 error_ = error;
297 signin_manager_->signin_global_error()->AuthStatusChanged();
298 }
299
300 void IdentityAPI::Shutdown() {
301 if (signin_manager_)
302 signin_manager_->signin_global_error()->RemoveProvider(this);
303 }
304
284 static base::LazyInstance<ProfileKeyedAPIFactory<IdentityAPI> > 305 static base::LazyInstance<ProfileKeyedAPIFactory<IdentityAPI> >
285 g_factory = LAZY_INSTANCE_INITIALIZER; 306 g_factory = LAZY_INSTANCE_INITIALIZER;
286 307
287 // static 308 // static
288 ProfileKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() { 309 ProfileKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() {
289 return &g_factory.Get(); 310 return &g_factory.Get();
290 } 311 }
291 312
313 GoogleServiceAuthError IdentityAPI::GetAuthStatus() const {
314 return error_;
315 }
316
317 void IdentityAPI::Observe(int type,
318 const content::NotificationSource& source,
319 const content::NotificationDetails& details) {
320 CHECK(type == chrome::NOTIFICATION_TOKEN_AVAILABLE);
321 TokenService::TokenAvailableDetails* token_details =
322 content::Details<TokenService::TokenAvailableDetails>(details).ptr();
323 if (token_details->service() ==
324 GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
325 error_ = GoogleServiceAuthError::AuthErrorNone();
326 signin_manager_->signin_global_error()->AuthStatusChanged();
327 }
328 }
329
330 template <>
331 void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() {
332 DependsOn(ExtensionSystemFactory::GetInstance());
333 DependsOn(TokenServiceFactory::GetInstance());
334 DependsOn(SigninManagerFactory::GetInstance());
335 }
336
292 } // namespace extensions 337 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/identity/identity_api.h ('k') | chrome/browser/extensions/api/identity/identity_apitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698