Chromium Code Reviews| 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/signin/signin_manager.h" | 5 #include "chrome/browser/signin/signin_manager.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/string_split.h" | 11 #include "base/string_split.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "chrome/browser/prefs/pref_service.h" | 13 #include "chrome/browser/prefs/pref_service.h" |
| 14 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/signin/token_service.h" | 15 #include "chrome/browser/signin/token_service.h" |
| 16 #include "chrome/browser/sync/profile_sync_service.h" | 16 #include "chrome/browser/sync/profile_sync_service.h" |
| 17 #include "chrome/common/chrome_notification_types.h" | 17 #include "chrome/common/chrome_notification_types.h" |
| 18 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" |
| 19 #include "chrome/common/net/gaia/gaia_constants.h" | 19 #include "chrome/common/net/gaia/gaia_constants.h" |
| 20 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
| 21 #include "content/public/browser/notification_service.h" | 21 #include "content/public/browser/notification_service.h" |
| 22 #include "net/base/cookie_monster.h" | |
| 22 | 23 |
| 23 const char kGetInfoEmailKey[] = "email"; | 24 const char kGetInfoEmailKey[] = "email"; |
| 24 const char kGetInfoServicesKey[] = "allServices"; | 25 const char kGetInfoServicesKey[] = "allServices"; |
| 25 const char kGooglePlusServiceKey[] = "googleme"; | 26 const char kGooglePlusServiceKey[] = "googleme"; |
| 26 | 27 |
| 27 SigninManager::SigninManager() | 28 SigninManager::SigninManager() |
| 28 : profile_(NULL), | 29 : profile_(NULL), |
| 29 had_two_factor_error_(false), | 30 had_two_factor_error_(false), |
| 30 last_login_auth_error_(GoogleServiceAuthError::None()) { | 31 last_login_auth_error_(GoogleServiceAuthError::None()) { |
| 31 } | 32 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 GaiaConstants::kChromeSource, | 136 GaiaConstants::kChromeSource, |
| 136 profile_->GetRequestContext())); | 137 profile_->GetRequestContext())); |
| 137 client_login_->StartClientLogin(possibly_invalid_username_, | 138 client_login_->StartClientLogin(possibly_invalid_username_, |
| 138 access_code, | 139 access_code, |
| 139 "", | 140 "", |
| 140 std::string(), | 141 std::string(), |
| 141 std::string(), | 142 std::string(), |
| 142 GaiaAuthFetcher::HostedAccountsNotAllowed); | 143 GaiaAuthFetcher::HostedAccountsNotAllowed); |
| 143 } | 144 } |
| 144 | 145 |
| 146 void SigninManager::StartSignInWithCredentials(const std::string& username, | |
| 147 const std::string& password) { | |
| 148 DCHECK(authenticated_username_.empty()); | |
| 149 PrepareForSignin(); | |
| 150 possibly_invalid_username_.assign(username); | |
| 151 password_.assign(password); | |
| 152 | |
| 153 client_login_.reset(new GaiaAuthFetcher(this, | |
| 154 GaiaConstants::kChromeSource, | |
| 155 profile_->GetRequestContext())); | |
| 156 | |
| 157 // This function starts with the current state of the web session's cookie | |
| 158 // jar and mints a new ClientLogin-style SID/LSID pair. This involves going | |
| 159 // throug the follow process or requests to GAIA and LSO: | |
| 160 // | |
| 161 // - call /o/oauth2/programmatic_auth with the returned token to get oauth2 | |
| 162 // access and refresh tokens | |
| 163 // - call /accounts/OAuthLogin with the oauth2 access token and get an uber | |
| 164 // auth token | |
| 165 // - call /TokenAuth with the uber auth token to get a SID/LSID pair for use | |
| 166 // by the token service | |
| 167 // | |
| 168 // The resulting SID/LSID can then be used just as if | |
| 169 // client_login_->StartClientLogin() had completed successfully. | |
| 170 client_login_->StartOAuthLoginTokenFetch(""); | |
| 171 } | |
| 172 | |
| 145 void SigninManager::ClearTransientSigninData() { | 173 void SigninManager::ClearTransientSigninData() { |
| 146 DCHECK(IsInitialized()); | 174 DCHECK(IsInitialized()); |
| 147 | 175 |
| 148 CleanupNotificationRegistration(); | 176 CleanupNotificationRegistration(); |
| 149 client_login_.reset(); | 177 client_login_.reset(); |
| 150 last_result_ = ClientLoginResult(); | 178 last_result_ = ClientLoginResult(); |
| 151 possibly_invalid_username_.clear(); | 179 possibly_invalid_username_.clear(); |
| 152 password_.clear(); | 180 password_.clear(); |
| 153 had_two_factor_error_ = false; | 181 had_two_factor_error_ = false; |
| 154 } | 182 } |
| 155 | 183 |
| 184 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error) { | |
| 185 last_login_auth_error_ = error; | |
| 186 content::NotificationService::current()->Notify( | |
| 187 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | |
| 188 content::Source<Profile>(profile_), | |
| 189 content::Details<const GoogleServiceAuthError>(&last_login_auth_error_)); | |
| 190 | |
| 191 ClearTransientSigninData(); | |
| 192 } | |
| 193 | |
| 156 void SigninManager::SignOut() { | 194 void SigninManager::SignOut() { |
| 157 DCHECK(IsInitialized()); | 195 DCHECK(IsInitialized()); |
| 158 if (authenticated_username_.empty() && !client_login_.get()) { | 196 if (authenticated_username_.empty() && !client_login_.get()) { |
| 159 // Just exit if we aren't signed in (or in the process of signing in). | 197 // Just exit if we aren't signed in (or in the process of signing in). |
| 160 // This avoids a perf regression because SignOut() is invoked on startup to | 198 // This avoids a perf regression because SignOut() is invoked on startup to |
| 161 // clean up any incomplete previous signin attempts. | 199 // clean up any incomplete previous signin attempts. |
| 162 return; | 200 return; |
| 163 } | 201 } |
| 164 | 202 |
| 165 ClearTransientSigninData(); | 203 ClearTransientSigninData(); |
| 166 authenticated_username_.clear(); | 204 authenticated_username_.clear(); |
| 167 profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername); | 205 profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername); |
| 168 profile_->GetPrefs()->ClearPref(prefs::kIsGooglePlusUser); | 206 profile_->GetPrefs()->ClearPref(prefs::kIsGooglePlusUser); |
| 169 profile_->GetTokenService()->ResetCredentialsInMemory(); | 207 profile_->GetTokenService()->ResetCredentialsInMemory(); |
| 170 profile_->GetTokenService()->EraseTokensFromDB(); | 208 profile_->GetTokenService()->EraseTokensFromDB(); |
| 171 } | 209 } |
| 172 | 210 |
| 173 const GoogleServiceAuthError& SigninManager::GetLoginAuthError() const { | 211 const GoogleServiceAuthError& SigninManager::GetLoginAuthError() const { |
| 174 return last_login_auth_error_; | 212 return last_login_auth_error_; |
| 175 } | 213 } |
| 176 | 214 |
| 177 bool SigninManager::AuthInProgress() const { | 215 bool SigninManager::AuthInProgress() const { |
| 178 return !possibly_invalid_username_.empty(); | 216 return !possibly_invalid_username_.empty(); |
| 179 } | 217 } |
| 180 | 218 |
| 219 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { | |
| 220 DCHECK(key == kGetInfoEmailKey); | |
| 221 LOG(ERROR) << "Account is not associated with a valid email address. " | |
| 222 << "Login failed."; | |
| 223 OnClientLoginFailure(GoogleServiceAuthError( | |
| 224 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); | |
| 225 } | |
| 226 | |
| 181 void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) { | 227 void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) { |
| 182 last_result_ = result; | 228 last_result_ = result; |
| 183 // Make a request for the canonical email address and services. | 229 // Make a request for the canonical email address and services. |
| 184 client_login_->StartGetUserInfo(result.lsid); | 230 client_login_->StartGetUserInfo(result.lsid); |
| 185 } | 231 } |
| 186 | 232 |
| 233 void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) { | |
| 234 // If we got a bad ASP, prompt for an ASP again by forcing another TWO_FACTOR | |
| 235 // error. | |
| 236 bool invalid_gaia = error.state() == | |
| 237 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS; | |
|
Andrew T Wilson (Slow)
2012/03/02 19:22:33
Probably worth documenting why we are not calling
Roger Tawa OOO till Jul 10th
2012/03/02 20:10:58
Done.
| |
| 238 last_login_auth_error_ = (invalid_gaia && had_two_factor_error_) ? | |
| 239 GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR) : error; | |
| 240 content::NotificationService::current()->Notify( | |
| 241 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | |
| 242 content::Source<Profile>(profile_), | |
| 243 content::Details<const GoogleServiceAuthError>(&last_login_auth_error_)); | |
| 244 | |
| 245 // We don't sign-out if the password was valid and we're just dealing with | |
| 246 // a second factor error, and we don't sign out if we're dealing with | |
| 247 // an invalid access code (again, because the password was valid). | |
| 248 if (last_login_auth_error_.state() == GoogleServiceAuthError::TWO_FACTOR) { | |
| 249 had_two_factor_error_ = true; | |
| 250 return; | |
| 251 } | |
| 252 | |
| 253 ClearTransientSigninData(); | |
| 254 } | |
| 255 | |
| 256 void SigninManager::OnOAuthLoginTokenSuccess(const std::string& refresh_token, | |
| 257 const std::string& access_token, | |
| 258 int expires_in_secs) { | |
| 259 DVLOG(1) << "SigninManager::OnOAuthLoginTokenSuccess access_token=" | |
| 260 << access_token; | |
| 261 client_login_->StartUberAuthTokenFetch(access_token); | |
| 262 } | |
| 263 | |
| 264 void SigninManager::OnOAuthLoginTokenFailure( | |
| 265 const GoogleServiceAuthError& error) { | |
| 266 LOG(WARNING) << "SigninManager::OnOAuthLoginTokenFailure"; | |
| 267 HandleAuthError(error); | |
| 268 } | |
| 269 | |
| 187 void SigninManager::OnGetUserInfoSuccess(const UserInfoMap& data) { | 270 void SigninManager::OnGetUserInfoSuccess(const UserInfoMap& data) { |
| 188 UserInfoMap::const_iterator email_iter = data.find(kGetInfoEmailKey); | 271 UserInfoMap::const_iterator email_iter = data.find(kGetInfoEmailKey); |
| 189 if (email_iter == data.end()) { | 272 if (email_iter == data.end()) { |
| 190 OnGetUserInfoKeyNotFound(kGetInfoEmailKey); | 273 OnGetUserInfoKeyNotFound(kGetInfoEmailKey); |
| 191 return; | 274 return; |
| 192 } else { | 275 } else { |
| 193 DCHECK(email_iter->first == kGetInfoEmailKey); | 276 DCHECK(email_iter->first == kGetInfoEmailKey); |
| 194 last_login_auth_error_ = GoogleServiceAuthError::None(); | 277 last_login_auth_error_ = GoogleServiceAuthError::None(); |
| 195 SetAuthenticatedUsername(email_iter->second); | 278 SetAuthenticatedUsername(email_iter->second); |
| 196 possibly_invalid_username_.clear(); | 279 possibly_invalid_username_.clear(); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 218 content::Source<Profile>(profile_), | 301 content::Source<Profile>(profile_), |
| 219 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); | 302 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); |
| 220 | 303 |
| 221 password_.clear(); // Don't need it anymore. | 304 password_.clear(); // Don't need it anymore. |
| 222 | 305 |
| 223 profile_->GetTokenService()->UpdateCredentials(last_result_); | 306 profile_->GetTokenService()->UpdateCredentials(last_result_); |
| 224 DCHECK(profile_->GetTokenService()->AreCredentialsValid()); | 307 DCHECK(profile_->GetTokenService()->AreCredentialsValid()); |
| 225 profile_->GetTokenService()->StartFetchingTokens(); | 308 profile_->GetTokenService()->StartFetchingTokens(); |
| 226 } | 309 } |
| 227 | 310 |
| 228 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { | |
| 229 DCHECK(key == kGetInfoEmailKey); | |
| 230 LOG(ERROR) << "Account is not associated with a valid email address. " | |
| 231 << "Login failed."; | |
| 232 OnClientLoginFailure(GoogleServiceAuthError( | |
| 233 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); | |
| 234 } | |
| 235 | |
| 236 void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) { | 311 void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) { |
| 237 LOG(ERROR) << "Unable to retreive the canonical email address. Login failed."; | 312 LOG(ERROR) << "Unable to retreive the canonical email address. Login failed."; |
| 313 // REVIEW: why does this call OnClientLoginFailure? | |
|
Andrew T Wilson (Slow)
2012/03/02 19:22:33
Hmmm. I'm guessing to make sure the SIGNIN_FAILED
| |
| 238 OnClientLoginFailure(error); | 314 OnClientLoginFailure(error); |
| 239 } | 315 } |
| 240 | 316 |
| 241 void SigninManager::OnTokenAuthFailure(const GoogleServiceAuthError& error) { | 317 void SigninManager::OnTokenAuthSuccess(const net::ResponseCookies& cookies, |
| 242 #if !defined(OS_CHROMEOS) | 318 const std::string& data) { |
| 243 DVLOG(1) << "Unable to retrieve the token auth."; | 319 DVLOG(1) << "SigninManager::OnTokenAuthSuccess"; |
| 244 CleanupNotificationRegistration(); | 320 |
| 245 #endif | 321 // The SID and LSID from this request is equivalent the pair returned by |
| 322 // ClientLogin. | |
| 323 std::string sid; | |
| 324 std::string lsid; | |
| 325 for (net::ResponseCookies::const_iterator i = cookies.begin(); | |
| 326 i != cookies.end(); ++i) { | |
| 327 net::CookieMonster::ParsedCookie parsed(*i); | |
| 328 if (parsed.Name() == "SID") { | |
| 329 sid = parsed.Value(); | |
| 330 } else if (parsed.Name() == "LSID") { | |
| 331 lsid = parsed.Value(); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 if (!sid.empty() && !lsid.empty()) { | |
| 336 OnClientLoginSuccess( | |
| 337 GaiaAuthConsumer::ClientLoginResult(sid, lsid, "", data)); | |
| 338 } else { | |
| 339 OnTokenAuthFailure( | |
| 340 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); | |
| 341 } | |
| 246 } | 342 } |
| 247 | 343 |
| 248 void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) { | 344 void SigninManager::OnTokenAuthFailure(const GoogleServiceAuthError& error) { |
| 249 // If we got a bad ASP, prompt for an ASP again by forcing another TWO_FACTOR | 345 DVLOG(1) << "Unable to retrieve the token auth."; |
| 250 // error. | 346 HandleAuthError(error); |
| 251 bool invalid_gaia = error.state() == | 347 } |
| 252 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS; | |
| 253 last_login_auth_error_ = (invalid_gaia && had_two_factor_error_) ? | |
| 254 GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR) : error; | |
| 255 content::NotificationService::current()->Notify( | |
| 256 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | |
| 257 content::Source<Profile>(profile_), | |
| 258 content::Details<const GoogleServiceAuthError>(&last_login_auth_error_)); | |
| 259 | 348 |
| 260 // We don't sign-out if the password was valid and we're just dealing with | 349 void SigninManager::OnUberAuthTokenSuccess(const std::string& token) { |
| 261 // a second factor error, and we don't sign out if we're dealing with | 350 DVLOG(1) << "SigninManager::OnUberAuthTokenSuccess token=" << token; |
| 262 // an invalid access code (again, because the password was valid). | 351 client_login_->StartTokenAuth(token); |
| 263 if (last_login_auth_error_.state() == GoogleServiceAuthError::TWO_FACTOR) { | 352 } |
| 264 had_two_factor_error_ = true; | |
| 265 return; | |
| 266 } | |
| 267 | 353 |
| 268 ClearTransientSigninData(); | 354 void SigninManager::OnUberAuthTokenFailure( |
| 355 const GoogleServiceAuthError& error) { | |
| 356 LOG(WARNING) << "SigninManager::OnUberAuthTokenFailure"; | |
| 357 HandleAuthError(error); | |
| 269 } | 358 } |
| 270 | 359 |
| 271 void SigninManager::Observe(int type, | 360 void SigninManager::Observe(int type, |
| 272 const content::NotificationSource& source, | 361 const content::NotificationSource& source, |
| 273 const content::NotificationDetails& details) { | 362 const content::NotificationDetails& details) { |
| 274 #if !defined(OS_CHROMEOS) | 363 #if !defined(OS_CHROMEOS) |
| 275 DCHECK(type == chrome::NOTIFICATION_TOKEN_AVAILABLE); | 364 DCHECK(type == chrome::NOTIFICATION_TOKEN_AVAILABLE); |
| 276 TokenService::TokenAvailableDetails* tok_details = | 365 TokenService::TokenAvailableDetails* tok_details = |
| 277 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); | 366 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); |
| 278 | 367 |
| 279 // If a GAIA service token has become available, use it to pre-login the | 368 // If a GAIA service token has become available, use it to pre-login the |
| 280 // user to other services that depend on GAIA credentials. | 369 // user to other services that depend on GAIA credentials. |
| 281 if (tok_details->service() == GaiaConstants::kGaiaService) { | 370 if (tok_details->service() == GaiaConstants::kGaiaService) { |
| 282 if (client_login_.get() == NULL) { | 371 if (client_login_.get() == NULL) { |
| 283 client_login_.reset(new GaiaAuthFetcher(this, | 372 client_login_.reset(new GaiaAuthFetcher(this, |
| 284 GaiaConstants::kChromeSource, | 373 GaiaConstants::kChromeSource, |
| 285 profile_->GetRequestContext())); | 374 profile_->GetRequestContext())); |
| 286 } | 375 } |
| 287 | 376 |
| 288 client_login_->StartMergeSession(tok_details->token()); | 377 client_login_->StartMergeSession(tok_details->token()); |
| 289 | 378 |
| 290 // We only want to do this once per sign-in. | 379 // We only want to do this once per sign-in. |
| 291 CleanupNotificationRegistration(); | 380 CleanupNotificationRegistration(); |
| 292 } | 381 } |
| 293 #endif | 382 #endif |
| 294 } | 383 } |
| OLD | NEW |