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

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: improve interactive flag clarity 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/extensions/extension_function_dispatcher.h" 9 #include "chrome/browser/extensions/extension_function_dispatcher.h"
10 #include "chrome/browser/extensions/extension_install_prompt.h" 10 #include "chrome/browser/extensions/extension_install_prompt.h"
11 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/permissions_updater.h" 12 #include "chrome/browser/extensions/permissions_updater.h"
13 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/signin/signin_manager.h"
15 #include "chrome/browser/signin/signin_manager_factory.h"
14 #include "chrome/browser/signin/token_service.h" 16 #include "chrome/browser/signin/token_service.h"
15 #include "chrome/browser/signin/token_service_factory.h" 17 #include "chrome/browser/signin/token_service_factory.h"
16 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_navigator.h"
18 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
19 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
20 #include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
21 #include "chrome/common/extensions/api/experimental_identity.h" 19 #include "chrome/common/extensions/api/experimental_identity.h"
22 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h" 20 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
23 #include "chrome/common/extensions/extension.h" 21 #include "chrome/common/extensions/extension.h"
24 #include "chrome/common/extensions/extension_manifest_constants.h" 22 #include "chrome/common/extensions/extension_manifest_constants.h"
25 #include "chrome/common/extensions/manifest_handler.h" 23 #include "chrome/common/extensions/manifest_handler.h"
26 #include "chrome/common/url_constants.h" 24 #include "chrome/common/url_constants.h"
27 #include "content/public/common/page_transition_types.h" 25 #include "content/public/common/page_transition_types.h"
26 #include "google_apis/gaia/gaia_constants.h"
28 #include "googleurl/src/gurl.h" 27 #include "googleurl/src/gurl.h"
29 #include "ui/base/window_open_disposition.h" 28 #include "ui/base/window_open_disposition.h"
30 29
31 namespace extensions { 30 namespace extensions {
32 31
33 namespace identity_constants { 32 namespace identity_constants {
34 const char kInvalidClientId[] = "Invalid OAuth2 Client ID."; 33 const char kInvalidClientId[] = "Invalid OAuth2 Client ID.";
35 const char kInvalidScopes[] = "Invalid OAuth2 scopes."; 34 const char kInvalidScopes[] = "Invalid OAuth2 scopes.";
36 const char kAuthFailure[] = "OAuth2 request failed: "; 35 const char kAuthFailure[] = "OAuth2 request failed: ";
37 const char kNoGrant[] = "OAuth2 not granted or revoked."; 36 const char kNoGrant[] = "OAuth2 not granted or revoked.";
38 const char kUserRejected[] = "The user did not approve access."; 37 const char kUserRejected[] = "The user did not approve access.";
39 const char kUserNotSignedIn[] = "The user is not signed in."; 38 const char kUserNotSignedIn[] = "The user is not signed in.";
40 const char kInvalidRedirect[] = "Did not redirect to the right URL."; 39 const char kInvalidRedirect[] = "Did not redirect to the right URL.";
41 } // namespace identity_constants 40 } // namespace identity_constants
42 41
43 namespace GetAuthToken = api::experimental_identity::GetAuthToken; 42 namespace GetAuthToken = api::experimental_identity::GetAuthToken;
44 namespace LaunchWebAuthFlow = api::experimental_identity::LaunchWebAuthFlow; 43 namespace LaunchWebAuthFlow = api::experimental_identity::LaunchWebAuthFlow;
45 namespace identity = api::experimental_identity; 44 namespace identity = api::experimental_identity;
46 45
47 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction() 46 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction()
48 : interactive_(false) {} 47 : should_prompt_for_scopes_(false),
48 should_prompt_for_signin_(false) {}
49 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {} 49 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {}
50 50
51 bool IdentityGetAuthTokenFunction::RunImpl() { 51 bool IdentityGetAuthTokenFunction::RunImpl() {
52 scoped_ptr<GetAuthToken::Params> params(GetAuthToken::Params::Create(*args_)); 52 scoped_ptr<GetAuthToken::Params> params(GetAuthToken::Params::Create(*args_));
53 EXTENSION_FUNCTION_VALIDATE(params.get()); 53 EXTENSION_FUNCTION_VALIDATE(params.get());
54 if (params->details.get() && params->details->interactive.get()) 54 bool interactive = params->details.get() &&
55 interactive_ = *params->details->interactive; 55 params->details->interactive.get() &&
56 *params->details->interactive;
57
58 should_prompt_for_scopes_ = interactive;
59 should_prompt_for_signin_ = interactive;
56 60
57 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); 61 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
58 62
59 // Check that the necessary information is present in the manfist. 63 // Check that the necessary information is present in the manfist.
60 if (oauth2_info.client_id.empty()) { 64 if (oauth2_info.client_id.empty()) {
61 error_ = identity_constants::kInvalidClientId; 65 error_ = identity_constants::kInvalidClientId;
62 return false; 66 return false;
63 } 67 }
64 68
65 if (oauth2_info.scopes.size() == 0) { 69 if (oauth2_info.scopes.size() == 0) {
66 error_ = identity_constants::kInvalidScopes; 70 error_ = identity_constants::kInvalidScopes;
67 return false; 71 return false;
68 } 72 }
69 73
70 // Balanced in OnIssueAdviceSuccess|OnMintTokenSuccess|OnMintTokenFailure| 74 // Balanced in OnIssueAdviceSuccess|OnMintTokenSuccess|OnMintTokenFailure|
71 // InstallUIAbort|OnLoginUIClosed. 75 // InstallUIAbort|SigninFailed.
72 AddRef(); 76 AddRef();
73 77
74 if (!HasLoginToken()) { 78 if (!HasLoginToken()) {
75 if (StartLogin()) { 79 if (!should_prompt_for_signin_) {
76 return true; 80 error_ = identity_constants::kUserNotSignedIn;
77 } else {
78 Release(); 81 Release();
79 return false; 82 return false;
80 } 83 }
84 // Display a login prompt. If the subsequent mint fails, don't display the
85 // prompt again.
86 should_prompt_for_signin_ = false;
87 ShowLoginPopup();
88 } else {
89 TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
90 refresh_token_ = token_service->GetOAuth2LoginRefreshToken();
91 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
81 } 92 }
82 93
83 if (StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE)) { 94 return true;
84 return true;
85 } else {
86 Release();
87 return false;
88 }
89 } 95 }
90 96
91 void IdentityGetAuthTokenFunction::OnMintTokenSuccess( 97 void IdentityGetAuthTokenFunction::OnMintTokenSuccess(
92 const std::string& access_token) { 98 const std::string& access_token) {
93 SetResult(Value::CreateStringValue(access_token)); 99 SetResult(Value::CreateStringValue(access_token));
94 SendResponse(true); 100 SendResponse(true);
95 Release(); // Balanced in RunImpl. 101 Release(); // Balanced in RunImpl.
96 } 102 }
97 103
98 void IdentityGetAuthTokenFunction::OnMintTokenFailure( 104 void IdentityGetAuthTokenFunction::OnMintTokenFailure(
99 const GoogleServiceAuthError& error) { 105 const GoogleServiceAuthError& error) {
106 switch (error.state()) {
107 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
108 case GoogleServiceAuthError::ACCOUNT_DELETED:
109 case GoogleServiceAuthError::ACCOUNT_DISABLED:
110 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
111 profile())->ReportAuthError(error);
112 if (should_prompt_for_signin_) {
113 // Display a login prompt and try again (once).
114 should_prompt_for_signin_ = false;
115 ShowLoginPopup();
116 return;
117 }
118 break;
119 default:
120 // Return error to caller.
121 break;
122 }
123
100 error_ = std::string(identity_constants::kAuthFailure) + error.ToString(); 124 error_ = std::string(identity_constants::kAuthFailure) + error.ToString();
101 SendResponse(false); 125 SendResponse(false);
102 Release(); // Balanced in RunImpl. 126 Release(); // Balanced in RunImpl.
103 } 127 }
104 128
105 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess( 129 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
106 const IssueAdviceInfo& issue_advice) { 130 const IssueAdviceInfo& issue_advice) {
131 should_prompt_for_signin_ = false;
107 // Existing grant was revoked and we used NO_FORCE, so we got info back 132 // Existing grant was revoked and we used NO_FORCE, so we got info back
108 // instead. 133 // instead.
109 if (interactive_) { 134 if (should_prompt_for_scopes_) {
110 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); 135 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents()));
111 ShowOAuthApprovalDialog(issue_advice); 136 ShowOAuthApprovalDialog(issue_advice);
112 } else { 137 } else {
113 error_ = identity_constants::kNoGrant; 138 error_ = identity_constants::kNoGrant;
114 SendResponse(false); 139 SendResponse(false);
115 Release(); // Balanced in RunImpl. 140 Release(); // Balanced in RunImpl.
116 } 141 }
117 } 142 }
118 143
119 void IdentityGetAuthTokenFunction::OnLoginUIClosed( 144 void IdentityGetAuthTokenFunction::SigninSuccess(const std::string& token) {
120 LoginUIService::LoginUI* ui) { 145 refresh_token_ = token;
121 StopObservingLoginService(); 146 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
122 if (!StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE)) { 147 }
123 SendResponse(false); 148
124 Release(); 149 void IdentityGetAuthTokenFunction::SigninFailed() {
125 } 150 error_ = identity_constants::kUserNotSignedIn;
151 SendResponse(false);
152 Release();
126 } 153 }
127 154
128 void IdentityGetAuthTokenFunction::InstallUIProceed() { 155 void IdentityGetAuthTokenFunction::InstallUIProceed() {
129 DCHECK(install_ui_->record_oauth2_grant()); 156 DCHECK(install_ui_->record_oauth2_grant());
130 // The user has accepted the scopes, so we may now force (recording a grant 157 // The user has accepted the scopes, so we may now force (recording a grant
131 // and receiving a token). 158 // and receiving a token).
132 bool success = StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE); 159 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE);
133 DCHECK(success);
134 } 160 }
135 161
136 void IdentityGetAuthTokenFunction::InstallUIAbort(bool user_initiated) { 162 void IdentityGetAuthTokenFunction::InstallUIAbort(bool user_initiated) {
137 error_ = identity_constants::kUserRejected; 163 error_ = identity_constants::kUserRejected;
138 SendResponse(false); 164 SendResponse(false);
139 Release(); // Balanced in RunImpl. 165 Release(); // Balanced in RunImpl.
140 } 166 }
141 167
142 bool IdentityGetAuthTokenFunction::StartFlow(OAuth2MintTokenFlow::Mode mode) { 168 void IdentityGetAuthTokenFunction::StartFlow(OAuth2MintTokenFlow::Mode mode) {
143 if (!HasLoginToken()) { 169 signin_flow_.reset(NULL);
144 error_ = identity_constants::kUserNotSignedIn; 170 mint_token_flow_.reset(CreateMintTokenFlow(mode));
145 return false; 171 mint_token_flow_->Start();
146 }
147
148 flow_.reset(CreateMintTokenFlow(mode));
149 flow_->Start();
150 return true;
151 }
152
153 bool IdentityGetAuthTokenFunction::StartLogin() {
154 if (!interactive_) {
155 error_ = identity_constants::kUserNotSignedIn;
156 return false;
157 }
158
159 ShowLoginPopup();
160 return true;
161 }
162
163 void IdentityGetAuthTokenFunction::StartObservingLoginService() {
164 LoginUIService* login_ui_service =
165 LoginUIServiceFactory::GetForProfile(profile());
166 login_ui_service->AddObserver(this);
167 }
168
169 void IdentityGetAuthTokenFunction::StopObservingLoginService() {
170 LoginUIService* login_ui_service =
171 LoginUIServiceFactory::GetForProfile(profile());
172 login_ui_service->RemoveObserver(this);
173 } 172 }
174 173
175 void IdentityGetAuthTokenFunction::ShowLoginPopup() { 174 void IdentityGetAuthTokenFunction::ShowLoginPopup() {
176 StartObservingLoginService(); 175 signin_flow_.reset(new IdentitySigninFlow(this, profile()));
177 176 signin_flow_->Start();
178 LoginUIService* login_ui_service =
179 LoginUIServiceFactory::GetForProfile(profile());
180 login_ui_service->ShowLoginPopup();
181 } 177 }
182 178
183 void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog( 179 void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog(
184 const IssueAdviceInfo& issue_advice) { 180 const IssueAdviceInfo& issue_advice) {
185 install_ui_->ConfirmIssueAdvice(this, GetExtension(), issue_advice); 181 install_ui_->ConfirmIssueAdvice(this, GetExtension(), issue_advice);
186 } 182 }
187 183
188 OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow( 184 OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow(
189 OAuth2MintTokenFlow::Mode mode) { 185 OAuth2MintTokenFlow::Mode mode) {
190 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); 186 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
191 TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
192 return new OAuth2MintTokenFlow( 187 return new OAuth2MintTokenFlow(
193 profile()->GetRequestContext(), 188 profile()->GetRequestContext(),
194 this, 189 this,
195 OAuth2MintTokenFlow::Parameters( 190 OAuth2MintTokenFlow::Parameters(
196 token_service->GetOAuth2LoginRefreshToken(), 191 refresh_token_,
197 GetExtension()->id(), 192 GetExtension()->id(),
198 oauth2_info.client_id, 193 oauth2_info.client_id,
199 oauth2_info.scopes, 194 oauth2_info.scopes,
200 mode)); 195 mode));
201 } 196 }
202 197
203 bool IdentityGetAuthTokenFunction::HasLoginToken() const { 198 bool IdentityGetAuthTokenFunction::HasLoginToken() const {
204 TokenService* token_service = TokenServiceFactory::GetForProfile(profile()); 199 TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
205 return token_service->HasOAuthLoginToken(); 200 return token_service->HasOAuthLoginToken();
206 } 201 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 SendResponse(true); 244 SendResponse(true);
250 Release(); // Balanced in RunImpl. 245 Release(); // Balanced in RunImpl.
251 } 246 }
252 247
253 void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure() { 248 void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure() {
254 error_ = identity_constants::kInvalidRedirect; 249 error_ = identity_constants::kInvalidRedirect;
255 SendResponse(false); 250 SendResponse(false);
256 Release(); // Balanced in RunImpl. 251 Release(); // Balanced in RunImpl.
257 } 252 }
258 253
259 IdentityAPI::IdentityAPI(Profile* profile) { 254 IdentityAPI::IdentityAPI(Profile* profile)
255 : profile_(profile),
256 signin_manager_(NULL),
257 error_(GoogleServiceAuthError::NONE) {
260 (new OAuth2ManifestHandler)->Register(); 258 (new OAuth2ManifestHandler)->Register();
261 } 259 }
262 260
263 IdentityAPI::~IdentityAPI() { 261 IdentityAPI::~IdentityAPI() {
264 } 262 }
265 263
264 void IdentityAPI::Initialize() {
265 signin_manager_ = SigninManagerFactory::GetForProfile(profile_);
266 signin_manager_->signin_global_error()->AddProvider(this);
267
268 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
269 registrar_.Add(this,
270 chrome::NOTIFICATION_TOKEN_AVAILABLE,
271 content::Source<TokenService>(token_service));
272 }
273
274 void IdentityAPI::ReportAuthError(const GoogleServiceAuthError& error) {
275 if (!signin_manager_)
276 Initialize();
277
278 error_ = error;
279 signin_manager_->signin_global_error()->AuthStatusChanged();
280 }
281
282 void IdentityAPI::Shutdown() {
283 if (signin_manager_)
284 signin_manager_->signin_global_error()->RemoveProvider(this);
285 }
286
266 static base::LazyInstance<ProfileKeyedAPIFactory<IdentityAPI> > 287 static base::LazyInstance<ProfileKeyedAPIFactory<IdentityAPI> >
267 g_factory = LAZY_INSTANCE_INITIALIZER; 288 g_factory = LAZY_INSTANCE_INITIALIZER;
268 289
269 // static 290 // static
270 ProfileKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() { 291 ProfileKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() {
271 return &g_factory.Get(); 292 return &g_factory.Get();
272 } 293 }
273 294
295 GoogleServiceAuthError IdentityAPI::GetAuthStatus() const {
296 return error_;
297 }
298
299 void IdentityAPI::Observe(int type,
300 const content::NotificationSource& source,
miket_OOO 2013/03/29 22:06:22 indentation got weird here, maybe a rename gone wi
Michael Courage 2013/03/30 00:18:30 Done.
301 const content::NotificationDetails& details) {
302 if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) {
303 TokenService::TokenAvailableDetails* token_details =
304 content::Details<TokenService::TokenAvailableDetails>(details).ptr();
305 if (token_details->service() ==
306 GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
307 error_ = GoogleServiceAuthError::AuthErrorNone();
308 signin_manager_->signin_global_error()->AuthStatusChanged();
309 }
310 } else {
311 NOTREACHED();
miket_OOO 2013/03/29 22:06:22 Not a huge deal, but this seems like an odd way to
Michael Courage 2013/03/30 00:18:30 Done. I prefer the CHECK(type) approach, but I've
312 }
313 }
314
315 template <>
316 void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() {
317 DependsOn(ExtensionSystemFactory::GetInstance());
318 DependsOn(TokenServiceFactory::GetInstance());
319 DependsOn(SigninManagerFactory::GetInstance());
320 }
321
274 } // namespace extensions 322 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698