OLD | NEW |
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 <set> |
| 8 #include <string> |
| 9 #include <vector> |
| 10 |
7 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
8 #include "base/stringprintf.h" | 12 #include "base/stringprintf.h" |
9 #include "base/values.h" | 13 #include "base/values.h" |
10 #include "chrome/browser/app_mode/app_mode_utils.h" | 14 #include "chrome/browser/app_mode/app_mode_utils.h" |
11 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 15 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
12 #include "chrome/browser/extensions/extension_install_prompt.h" | 16 #include "chrome/browser/extensions/extension_install_prompt.h" |
13 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
14 #include "chrome/browser/extensions/permissions_updater.h" | 18 #include "chrome/browser/extensions/permissions_updater.h" |
15 #include "chrome/browser/profiles/profile.h" | 19 #include "chrome/browser/profiles/profile.h" |
16 #include "chrome/browser/signin/signin_manager.h" | 20 #include "chrome/browser/signin/signin_manager.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 | 57 |
54 } // namespace | 58 } // namespace |
55 | 59 |
56 namespace GetAuthToken = api::experimental_identity::GetAuthToken; | 60 namespace GetAuthToken = api::experimental_identity::GetAuthToken; |
57 namespace LaunchWebAuthFlow = api::experimental_identity::LaunchWebAuthFlow; | 61 namespace LaunchWebAuthFlow = api::experimental_identity::LaunchWebAuthFlow; |
58 namespace identity = api::experimental_identity; | 62 namespace identity = api::experimental_identity; |
59 | 63 |
60 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction() | 64 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction() |
61 : should_prompt_for_scopes_(false), | 65 : should_prompt_for_scopes_(false), |
62 should_prompt_for_signin_(false) {} | 66 should_prompt_for_signin_(false) {} |
| 67 |
63 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {} | 68 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {} |
64 | 69 |
65 bool IdentityGetAuthTokenFunction::RunImpl() { | 70 bool IdentityGetAuthTokenFunction::RunImpl() { |
66 scoped_ptr<GetAuthToken::Params> params(GetAuthToken::Params::Create(*args_)); | 71 scoped_ptr<GetAuthToken::Params> params(GetAuthToken::Params::Create(*args_)); |
67 EXTENSION_FUNCTION_VALIDATE(params.get()); | 72 EXTENSION_FUNCTION_VALIDATE(params.get()); |
68 bool interactive = params->details.get() && | 73 bool interactive = params->details.get() && |
69 params->details->interactive.get() && | 74 params->details->interactive.get() && |
70 *params->details->interactive; | 75 *params->details->interactive; |
71 | 76 |
72 should_prompt_for_scopes_ = interactive; | 77 should_prompt_for_scopes_ = interactive; |
73 should_prompt_for_signin_ = interactive; | 78 should_prompt_for_signin_ = interactive; |
74 | 79 |
75 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); | 80 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); |
76 | 81 |
77 // Check that the necessary information is present in the manifest. | 82 // Check that the necessary information is present in the manifest. |
78 if (oauth2_info.client_id.empty()) { | 83 if (oauth2_info.client_id.empty()) { |
79 error_ = identity_constants::kInvalidClientId; | 84 error_ = identity_constants::kInvalidClientId; |
80 return false; | 85 return false; |
81 } | 86 } |
82 | 87 |
83 if (oauth2_info.scopes.size() == 0) { | 88 if (oauth2_info.scopes.size() == 0) { |
84 error_ = identity_constants::kInvalidScopes; | 89 error_ = identity_constants::kInvalidScopes; |
85 return false; | 90 return false; |
86 } | 91 } |
87 | 92 |
88 // Balanced in OnIssueAdviceSuccess|OnMintTokenSuccess|OnMintTokenFailure| | 93 // Balanced in CompleteFunctionWithResult|CompleteFunctionWithError |
89 // InstallUIAbort|SigninFailed. | |
90 AddRef(); | 94 AddRef(); |
91 | 95 |
92 if (!HasLoginToken()) { | 96 if (!HasLoginToken()) { |
93 if (!should_prompt_for_signin_) { | 97 if (!should_prompt_for_signin_) { |
94 error_ = identity_constants::kUserNotSignedIn; | 98 error_ = identity_constants::kUserNotSignedIn; |
95 Release(); | 99 Release(); |
96 return false; | 100 return false; |
97 } | 101 } |
98 // Display a login prompt. If the subsequent mint fails, don't display the | 102 // Display a login prompt. |
99 // prompt again. | 103 StartSigninFlow(); |
100 should_prompt_for_signin_ = false; | |
101 ShowLoginPopup(); | |
102 } else { | 104 } else { |
103 TokenService* token_service = TokenServiceFactory::GetForProfile(profile()); | 105 TokenService* token_service = TokenServiceFactory::GetForProfile(profile()); |
104 refresh_token_ = token_service->GetOAuth2LoginRefreshToken(); | 106 refresh_token_ = token_service->GetOAuth2LoginRefreshToken(); |
105 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE); | 107 StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE); |
106 } | 108 } |
107 | 109 |
108 return true; | 110 return true; |
109 } | 111 } |
110 | 112 |
111 void IdentityGetAuthTokenFunction::OnMintTokenSuccess( | 113 void IdentityGetAuthTokenFunction::CompleteFunctionWithResult( |
112 const std::string& access_token) { | 114 const std::string& access_token) { |
113 SetResult(Value::CreateStringValue(access_token)); | 115 SetResult(Value::CreateStringValue(access_token)); |
114 SendResponse(true); | 116 SendResponse(true); |
115 Release(); // Balanced in RunImpl. | 117 Release(); // Balanced in RunImpl. |
116 } | 118 } |
117 | 119 |
| 120 void IdentityGetAuthTokenFunction::CompleteFunctionWithError( |
| 121 const std::string& error) { |
| 122 error_ = error; |
| 123 SendResponse(false); |
| 124 Release(); // Balanced in RunImpl. |
| 125 } |
| 126 |
| 127 void IdentityGetAuthTokenFunction::StartSigninFlow() { |
| 128 // Display a login prompt. If the subsequent mint fails, don't display the |
| 129 // login prompt again. |
| 130 should_prompt_for_signin_ = false; |
| 131 ShowLoginPopup(); |
| 132 } |
| 133 |
| 134 void IdentityGetAuthTokenFunction::StartMintTokenFlow( |
| 135 IdentityMintRequestQueue::MintType type) { |
| 136 mint_token_flow_type_ = type; |
| 137 |
| 138 // Flows are serialized to prevent excessive traffic to GAIA, and |
| 139 // to consolidate UI pop-ups. |
| 140 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); |
| 141 std::set<std::string> scopes(oauth2_info.scopes.begin(), |
| 142 oauth2_info.scopes.end()); |
| 143 IdentityAPI* id_api = |
| 144 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(profile_); |
| 145 |
| 146 // If there is an interactive flow in progress, non-interactive |
| 147 // requests should complete immediately since a consent UI is |
| 148 // known to be required. |
| 149 if (!should_prompt_for_scopes_ && !id_api->mint_queue()->empty( |
| 150 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE, |
| 151 GetExtension()->id(), scopes)) { |
| 152 CompleteFunctionWithError(identity_constants::kNoGrant); |
| 153 return; |
| 154 } |
| 155 id_api->mint_queue()->RequestStart(type, |
| 156 GetExtension()->id(), |
| 157 scopes, |
| 158 this); |
| 159 } |
| 160 |
| 161 void IdentityGetAuthTokenFunction::CompleteMintTokenFlow() { |
| 162 IdentityMintRequestQueue::MintType type = mint_token_flow_type_; |
| 163 |
| 164 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension()); |
| 165 std::set<std::string> scopes(oauth2_info.scopes.begin(), |
| 166 oauth2_info.scopes.end()); |
| 167 |
| 168 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile( |
| 169 profile_)->mint_queue()->RequestComplete(type, |
| 170 GetExtension()->id(), |
| 171 scopes, |
| 172 this); |
| 173 } |
| 174 |
| 175 void IdentityGetAuthTokenFunction::StartMintToken( |
| 176 IdentityMintRequestQueue::MintType type) { |
| 177 switch (type) { |
| 178 case IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE: |
| 179 StartGaiaRequest(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE); |
| 180 break; |
| 181 |
| 182 case IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE: |
| 183 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); |
| 184 ShowOAuthApprovalDialog(issue_advice_); |
| 185 break; |
| 186 |
| 187 default: |
| 188 NOTREACHED() << "Unexepected mint type in StartMintToken: " << type; |
| 189 break; |
| 190 }; |
| 191 } |
| 192 |
| 193 void IdentityGetAuthTokenFunction::OnMintTokenSuccess( |
| 194 const std::string& access_token) { |
| 195 CompleteMintTokenFlow(); |
| 196 CompleteFunctionWithResult(access_token); |
| 197 } |
| 198 |
118 void IdentityGetAuthTokenFunction::OnMintTokenFailure( | 199 void IdentityGetAuthTokenFunction::OnMintTokenFailure( |
119 const GoogleServiceAuthError& error) { | 200 const GoogleServiceAuthError& error) { |
| 201 CompleteMintTokenFlow(); |
| 202 |
120 switch (error.state()) { | 203 switch (error.state()) { |
121 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: | 204 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: |
122 case GoogleServiceAuthError::ACCOUNT_DELETED: | 205 case GoogleServiceAuthError::ACCOUNT_DELETED: |
123 case GoogleServiceAuthError::ACCOUNT_DISABLED: | 206 case GoogleServiceAuthError::ACCOUNT_DISABLED: |
124 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile( | 207 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile( |
125 profile())->ReportAuthError(error); | 208 profile())->ReportAuthError(error); |
126 if (should_prompt_for_signin_) { | 209 if (should_prompt_for_signin_) { |
127 // Display a login prompt and try again (once). | 210 // Display a login prompt and try again (once). |
128 should_prompt_for_signin_ = false; | 211 StartSigninFlow(); |
129 ShowLoginPopup(); | |
130 return; | 212 return; |
131 } | 213 } |
132 break; | 214 break; |
133 default: | 215 default: |
134 // Return error to caller. | 216 // Return error to caller. |
135 break; | 217 break; |
136 } | 218 } |
137 | 219 |
138 error_ = std::string(identity_constants::kAuthFailure) + error.ToString(); | 220 CompleteFunctionWithError( |
139 SendResponse(false); | 221 std::string(identity_constants::kAuthFailure) + error.ToString()); |
140 Release(); // Balanced in RunImpl. | |
141 } | 222 } |
142 | 223 |
143 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess( | 224 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess( |
144 const IssueAdviceInfo& issue_advice) { | 225 const IssueAdviceInfo& issue_advice) { |
| 226 CompleteMintTokenFlow(); |
| 227 |
145 should_prompt_for_signin_ = false; | 228 should_prompt_for_signin_ = false; |
146 // Existing grant was revoked and we used NO_FORCE, so we got info back | 229 // Existing grant was revoked and we used NO_FORCE, so we got info back |
147 // instead. | 230 // instead. |
148 if (should_prompt_for_scopes_) { | 231 if (should_prompt_for_scopes_) { |
149 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); | 232 issue_advice_ = issue_advice; |
150 ShowOAuthApprovalDialog(issue_advice); | 233 StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE); |
151 } else { | 234 } else { |
152 error_ = identity_constants::kNoGrant; | 235 CompleteFunctionWithError(identity_constants::kNoGrant); |
153 SendResponse(false); | |
154 Release(); // Balanced in RunImpl. | |
155 } | 236 } |
156 } | 237 } |
157 | 238 |
158 void IdentityGetAuthTokenFunction::SigninSuccess(const std::string& token) { | 239 void IdentityGetAuthTokenFunction::SigninSuccess(const std::string& token) { |
159 refresh_token_ = token; | 240 refresh_token_ = token; |
160 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE); | 241 StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE); |
161 } | 242 } |
162 | 243 |
163 void IdentityGetAuthTokenFunction::SigninFailed() { | 244 void IdentityGetAuthTokenFunction::SigninFailed() { |
164 error_ = identity_constants::kUserNotSignedIn; | 245 CompleteFunctionWithError(identity_constants::kUserNotSignedIn); |
165 SendResponse(false); | |
166 Release(); | |
167 } | 246 } |
168 | 247 |
169 void IdentityGetAuthTokenFunction::InstallUIProceed() { | 248 void IdentityGetAuthTokenFunction::InstallUIProceed() { |
170 DCHECK(install_ui_->record_oauth2_grant()); | 249 DCHECK(install_ui_->record_oauth2_grant()); |
171 // The user has accepted the scopes, so we may now force (recording a grant | 250 // The user has accepted the scopes, so we may now force (recording a grant |
172 // and receiving a token). | 251 // and receiving a token). |
173 StartFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE); | 252 StartGaiaRequest(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE); |
174 } | 253 } |
175 | 254 |
176 void IdentityGetAuthTokenFunction::InstallUIAbort(bool user_initiated) { | 255 void IdentityGetAuthTokenFunction::InstallUIAbort(bool user_initiated) { |
177 error_ = identity_constants::kUserRejected; | 256 CompleteMintTokenFlow(); |
178 SendResponse(false); | 257 CompleteFunctionWithError(identity_constants::kUserRejected); |
179 Release(); // Balanced in RunImpl. | |
180 } | 258 } |
181 | 259 |
182 void IdentityGetAuthTokenFunction::StartFlow(OAuth2MintTokenFlow::Mode mode) { | 260 void IdentityGetAuthTokenFunction::StartGaiaRequest( |
183 signin_flow_.reset(NULL); | 261 OAuth2MintTokenFlow::Mode mode) { |
184 mint_token_flow_.reset(CreateMintTokenFlow(mode)); | 262 mint_token_flow_.reset(CreateMintTokenFlow(mode)); |
185 mint_token_flow_->Start(); | 263 mint_token_flow_->Start(); |
186 } | 264 } |
187 | 265 |
188 void IdentityGetAuthTokenFunction::ShowLoginPopup() { | 266 void IdentityGetAuthTokenFunction::ShowLoginPopup() { |
189 signin_flow_.reset(new IdentitySigninFlow(this, profile())); | 267 signin_flow_.reset(new IdentitySigninFlow(this, profile())); |
190 signin_flow_->Start(); | 268 signin_flow_->Start(); |
191 } | 269 } |
192 | 270 |
193 void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog( | 271 void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog( |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 void IdentityAPI::Initialize() { | 410 void IdentityAPI::Initialize() { |
333 signin_manager_ = SigninManagerFactory::GetForProfile(profile_); | 411 signin_manager_ = SigninManagerFactory::GetForProfile(profile_); |
334 signin_manager_->signin_global_error()->AddProvider(this); | 412 signin_manager_->signin_global_error()->AddProvider(this); |
335 | 413 |
336 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 414 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
337 registrar_.Add(this, | 415 registrar_.Add(this, |
338 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 416 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
339 content::Source<TokenService>(token_service)); | 417 content::Source<TokenService>(token_service)); |
340 } | 418 } |
341 | 419 |
| 420 IdentityMintRequestQueue* IdentityAPI::mint_queue() { |
| 421 return &mint_queue_; |
| 422 } |
| 423 |
342 void IdentityAPI::ReportAuthError(const GoogleServiceAuthError& error) { | 424 void IdentityAPI::ReportAuthError(const GoogleServiceAuthError& error) { |
343 if (!signin_manager_) | 425 if (!signin_manager_) |
344 Initialize(); | 426 Initialize(); |
345 | 427 |
346 error_ = error; | 428 error_ = error; |
347 signin_manager_->signin_global_error()->AuthStatusChanged(); | 429 signin_manager_->signin_global_error()->AuthStatusChanged(); |
348 } | 430 } |
349 | 431 |
350 void IdentityAPI::Shutdown() { | 432 void IdentityAPI::Shutdown() { |
351 if (signin_manager_) | 433 if (signin_manager_) |
(...skipping 26 matching lines...) Expand all Loading... |
378 } | 460 } |
379 | 461 |
380 template <> | 462 template <> |
381 void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() { | 463 void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() { |
382 DependsOn(ExtensionSystemFactory::GetInstance()); | 464 DependsOn(ExtensionSystemFactory::GetInstance()); |
383 DependsOn(TokenServiceFactory::GetInstance()); | 465 DependsOn(TokenServiceFactory::GetInstance()); |
384 DependsOn(SigninManagerFactory::GetInstance()); | 466 DependsOn(SigninManagerFactory::GetInstance()); |
385 } | 467 } |
386 | 468 |
387 } // namespace extensions | 469 } // namespace extensions |
OLD | NEW |