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" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 #include "content/public/browser/notification_service.h" | 40 #include "content/public/browser/notification_service.h" |
| 41 #include "content/public/browser/render_process_host.h" | 41 #include "content/public/browser/render_process_host.h" |
| 42 #include "google_apis/gaia/gaia_auth_fetcher.h" | 42 #include "google_apis/gaia/gaia_auth_fetcher.h" |
| 43 #include "google_apis/gaia/gaia_auth_util.h" | 43 #include "google_apis/gaia/gaia_auth_util.h" |
| 44 #include "google_apis/gaia/gaia_constants.h" | 44 #include "google_apis/gaia/gaia_constants.h" |
| 45 #include "google_apis/gaia/gaia_urls.h" | 45 #include "google_apis/gaia/gaia_urls.h" |
| 46 #include "net/base/escape.h" | 46 #include "net/base/escape.h" |
| 47 #include "net/url_request/url_request_context.h" | 47 #include "net/url_request/url_request_context.h" |
| 48 #include "third_party/icu/public/i18n/unicode/regex.h" | 48 #include "third_party/icu/public/i18n/unicode/regex.h" |
| 49 | 49 |
| 50 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 50 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 51 #include "chrome/browser/policy/cloud/user_policy_signin_service.h" | 51 #include "chrome/browser/policy/cloud/user_policy_signin_service.h" |
| 52 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h" | 52 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h" |
| 53 #endif | 53 #endif |
| 54 | 54 |
| 55 using namespace signin_internals_util; | 55 using namespace signin_internals_util; |
| 56 | 56 |
| 57 using content::BrowserThread; | 57 using content::BrowserThread; |
| 58 | 58 |
| 59 namespace { | 59 namespace { |
| 60 | 60 |
| 61 const char kGetInfoDisplayEmailKey[] = "displayEmail"; | 61 const char kGetInfoDisplayEmailKey[] = "displayEmail"; |
| 62 const char kGetInfoEmailKey[] = "email"; | 62 const char kGetInfoEmailKey[] = "email"; |
| 63 | 63 |
| 64 const char kGoogleAccountsUrl[] = "https://accounts.google.com"; | |
| 65 | |
| 66 const int kInvalidProcessId = -1; | 64 const int kInvalidProcessId = -1; |
| 67 | 65 |
| 68 const char kChromiumSyncService[] = "service=chromiumsync"; | 66 const char kChromiumSyncService[] = "service=chromiumsync"; |
| 69 | 67 |
| 70 } // namespace | 68 } // namespace |
| 71 | 69 |
| 72 // Under the covers, we use a dummy chrome-extension ID to serve the purposes | 70 // Under the covers, we use a dummy chrome-extension ID to serve the purposes |
| 73 // outlined in the .h file comment for this string. | 71 // outlined in the .h file comment for this string. |
| 74 const char* SigninManager::kChromeSigninEffectiveSite = | 72 const char* SigninManager::kChromeSigninEffectiveSite = |
| 75 "chrome-extension://acfccoigjajmmgbhpfbjnpckhjjegnih"; | 73 "chrome-extension://acfccoigjajmmgbhpfbjnpckhjjegnih"; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 87 return false; | 85 return false; |
| 88 | 86 |
| 89 // Any login UI URLs with signin=chromiumsync should be considered a web | 87 // Any login UI URLs with signin=chromiumsync should be considered a web |
| 90 // URL (relies on GAIA keeping the "service=chromiumsync" query string | 88 // URL (relies on GAIA keeping the "service=chromiumsync" query string |
| 91 // fragment present even when embedding inside a "continue" parameter). | 89 // fragment present even when embedding inside a "continue" parameter). |
| 92 return net::UnescapeURLComponent( | 90 return net::UnescapeURLComponent( |
| 93 url.query(), net::UnescapeRule::URL_SPECIAL_CHARS) | 91 url.query(), net::UnescapeRule::URL_SPECIAL_CHARS) |
| 94 .find(kChromiumSyncService) != std::string::npos; | 92 .find(kChromiumSyncService) != std::string::npos; |
| 95 } | 93 } |
| 96 | 94 |
| 97 // static | |
| 98 bool SigninManager::AreSigninCookiesAllowed(Profile* profile) { | |
| 99 CookieSettings* cookie_settings = | |
| 100 CookieSettings::Factory::GetForProfile(profile); | |
| 101 return AreSigninCookiesAllowed(cookie_settings); | |
| 102 } | |
| 103 | |
| 104 // static | |
| 105 bool SigninManager::AreSigninCookiesAllowed(CookieSettings* cookie_settings) { | |
| 106 return cookie_settings && | |
| 107 cookie_settings->IsSettingCookieAllowed(GURL(kGoogleAccountsUrl), | |
| 108 GURL(kGoogleAccountsUrl)); | |
| 109 } | |
| 110 | |
| 111 // static | |
| 112 bool SigninManager::IsAllowedUsername(const std::string& username, | |
| 113 const std::string& policy) { | |
| 114 if (policy.empty()) | |
| 115 return true; | |
| 116 | |
| 117 // Patterns like "*@foo.com" are not accepted by our regex engine (since they | |
| 118 // are not valid regular expressions - they should instead be ".*@foo.com"). | |
| 119 // For convenience, detect these patterns and insert a "." character at the | |
| 120 // front. | |
| 121 string16 pattern = UTF8ToUTF16(policy); | |
| 122 if (pattern[0] == L'*') | |
| 123 pattern.insert(pattern.begin(), L'.'); | |
| 124 | |
| 125 // See if the username matches the policy-provided pattern. | |
| 126 UErrorCode status = U_ZERO_ERROR; | |
| 127 const icu::UnicodeString icu_pattern(pattern.data(), pattern.length()); | |
| 128 icu::RegexMatcher matcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status); | |
| 129 if (!U_SUCCESS(status)) { | |
| 130 LOG(ERROR) << "Invalid login regex: " << pattern << ", status: " << status; | |
| 131 // If an invalid pattern is provided, then prohibit *all* logins (better to | |
| 132 // break signin than to quietly allow users to sign in). | |
| 133 return false; | |
| 134 } | |
| 135 string16 username16 = UTF8ToUTF16(username); | |
| 136 icu::UnicodeString icu_input(username16.data(), username16.length()); | |
| 137 matcher.reset(icu_input); | |
| 138 status = U_ZERO_ERROR; | |
| 139 UBool match = matcher.matches(status); | |
| 140 DCHECK(U_SUCCESS(status)); | |
| 141 return !!match; // !! == convert from UBool to bool. | |
| 142 } | |
| 143 | |
| 144 SigninManager::SigninManager() | 95 SigninManager::SigninManager() |
| 145 : profile_(NULL), | 96 : prohibit_signout_(false), |
| 146 prohibit_signout_(false), | |
| 147 had_two_factor_error_(false), | 97 had_two_factor_error_(false), |
| 148 type_(SIGNIN_TYPE_NONE), | 98 type_(SIGNIN_TYPE_NONE), |
| 149 weak_pointer_factory_(this), | 99 weak_pointer_factory_(this), |
| 150 signin_process_id_(kInvalidProcessId) { | 100 signin_process_id_(kInvalidProcessId) { |
| 151 } | 101 } |
| 152 | 102 |
| 153 void SigninManager::SetSigninProcess(int process_id) { | 103 void SigninManager::SetSigninProcess(int process_id) { |
| 154 if (process_id == signin_process_id_) | 104 if (process_id == signin_process_id_) |
| 155 return; | 105 return; |
| 156 DLOG_IF(WARNING, signin_process_id_ != kInvalidProcessId) << | 106 DLOG_IF(WARNING, signin_process_id_ != kInvalidProcessId) << |
| 157 "Replacing in-use signin process."; | 107 "Replacing in-use signin process."; |
| 158 signin_process_id_ = process_id; | 108 signin_process_id_ = process_id; |
| 159 const content::RenderProcessHost* process = | 109 const content::RenderProcessHost* process = |
| 160 content::RenderProcessHost::FromID(process_id); | 110 content::RenderProcessHost::FromID(process_id); |
| 161 DCHECK(process); | 111 DCHECK(process); |
| 162 registrar_.Add(this, | 112 registrar_.Add(this, |
| 163 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 113 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| 164 content::Source<content::RenderProcessHost>(process)); | 114 content::Source<content::RenderProcessHost>(process)); |
| 165 } | 115 } |
| 166 | 116 |
| 167 bool SigninManager::IsSigninProcess(int process_id) const { | 117 bool SigninManager::IsSigninProcess(int process_id) const { |
| 168 return process_id == signin_process_id_; | 118 return process_id == signin_process_id_; |
| 169 } | 119 } |
| 170 | 120 |
| 171 bool SigninManager::HasSigninProcess() const { | 121 bool SigninManager::HasSigninProcess() const { |
| 172 return signin_process_id_ != kInvalidProcessId; | 122 return signin_process_id_ != kInvalidProcessId; |
| 173 } | 123 } |
| 174 | 124 |
| 175 SigninManager::~SigninManager() { | 125 SigninManager::~SigninManager() { |
| 176 DCHECK(!signin_global_error_.get()) << | |
| 177 "SigninManager::Initialize called but not SigninManager::Shutdown"; | |
| 178 } | 126 } |
| 179 | 127 |
| 180 void SigninManager::Initialize(Profile* profile) { | 128 void SigninManager::InitTokenService() { |
| 181 // Should never call Initialize() twice. | 129 SigninManagerBase::InitTokenService(); |
| 182 DCHECK(!IsInitialized()); | |
| 183 profile_ = profile; | |
| 184 signin_global_error_.reset(new SigninGlobalError(this, profile)); | |
| 185 GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError( | |
| 186 signin_global_error_.get()); | |
| 187 PrefService* local_state = g_browser_process->local_state(); | |
| 188 // local_state can be null during unit tests. | |
| 189 if (local_state) { | |
| 190 local_state_pref_registrar_.Init(local_state); | |
| 191 local_state_pref_registrar_.Add( | |
| 192 prefs::kGoogleServicesUsernamePattern, | |
| 193 base::Bind(&SigninManager::OnGoogleServicesUsernamePatternChanged, | |
| 194 weak_pointer_factory_.GetWeakPtr())); | |
| 195 } | |
| 196 signin_allowed_.Init(prefs::kSigninAllowed, profile_->GetPrefs(), | |
| 197 base::Bind(&SigninManager::OnSigninAllowedPrefChanged, | |
| 198 base::Unretained(this))); | |
| 199 | |
| 200 // If the user is clearing the token service from the command line, then | |
| 201 // clear their login info also (not valid to be logged in without any | |
| 202 // tokens). | |
| 203 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | |
| 204 if (cmd_line->HasSwitch(switches::kClearTokenService)) | |
| 205 profile->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername); | |
| 206 | |
| 207 std::string user = profile_->GetPrefs()->GetString( | |
| 208 prefs::kGoogleServicesUsername); | |
| 209 if (!user.empty()) | |
| 210 SetAuthenticatedUsername(user); | |
| 211 // TokenService can be null for unit tests. | |
| 212 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 130 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 213 if (token_service) { | 131 if (token_service && !GetAuthenticatedUsername().empty()) |
| 214 token_service->Initialize(GaiaConstants::kChromeSource, profile_); | 132 token_service->LoadTokensFromDB(); |
| 215 // ChromeOS will kick off TokenService::LoadTokensFromDB from | |
| 216 // OAuthLoginManager once the rest of the Profile is fully initialized. | |
| 217 // Starting it from here would cause OAuthLoginManager mismatch the origin | |
| 218 // of OAuth2 tokens. | |
| 219 #if !defined(OS_CHROMEOS) | |
| 220 if (!authenticated_username_.empty()) { | |
| 221 token_service->LoadTokensFromDB(); | |
| 222 } | |
| 223 #endif | |
| 224 } | |
| 225 if ((!user.empty() && !IsAllowedUsername(user)) || !IsSigninAllowed()) { | |
| 226 // User is signed in, but the username is invalid - the administrator must | |
| 227 // have changed the policy since the last signin, so sign out the user. | |
| 228 SignOut(); | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 bool SigninManager::IsInitialized() const { | |
| 233 return profile_ != NULL; | |
| 234 } | |
| 235 | |
| 236 bool SigninManager::IsAllowedUsername(const std::string& username) const { | |
| 237 PrefService* local_state = g_browser_process->local_state(); | |
| 238 if (!local_state) | |
| 239 return true; // In a unit test with no local state - all names are allowed. | |
| 240 | |
| 241 std::string pattern = local_state->GetString( | |
| 242 prefs::kGoogleServicesUsernamePattern); | |
| 243 return IsAllowedUsername(username, pattern); | |
| 244 } | |
| 245 | |
| 246 bool SigninManager::IsSigninAllowed() const { | |
| 247 return signin_allowed_.GetValue(); | |
| 248 } | |
| 249 | |
| 250 // static | |
| 251 bool SigninManager::IsSigninAllowedOnIOThread(ProfileIOData* io_data) { | |
| 252 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 253 return io_data->signin_allowed()->GetValue(); | |
| 254 } | 133 } |
| 255 | 134 |
| 256 void SigninManager::CleanupNotificationRegistration() { | 135 void SigninManager::CleanupNotificationRegistration() { |
| 257 #if !defined(OS_CHROMEOS) | |
| 258 content::Source<TokenService> token_service( | 136 content::Source<TokenService> token_service( |
| 259 TokenServiceFactory::GetForProfile(profile_)); | 137 TokenServiceFactory::GetForProfile(profile_)); |
| 260 if (registrar_.IsRegistered(this, | 138 if (registrar_.IsRegistered(this, |
| 261 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 139 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 262 token_service)) { | 140 token_service)) { |
| 263 registrar_.Remove(this, | 141 registrar_.Remove(this, |
| 264 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 142 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 265 token_service); | 143 token_service); |
| 266 } | 144 } |
| 267 #endif | |
| 268 } | |
| 269 | |
| 270 const std::string& SigninManager::GetAuthenticatedUsername() const { | |
| 271 return authenticated_username_; | |
| 272 } | |
| 273 | |
| 274 void SigninManager::SetAuthenticatedUsername(const std::string& username) { | |
| 275 if (!authenticated_username_.empty()) { | |
| 276 DLOG_IF(ERROR, username != authenticated_username_) << | |
| 277 "Tried to change the authenticated username to something different: " << | |
| 278 "Current: " << authenticated_username_ << ", New: " << username; | |
| 279 return; | |
| 280 } | |
| 281 authenticated_username_ = username; | |
| 282 // TODO(tim): We could go further in ensuring kGoogleServicesUsername and | |
| 283 // authenticated_username_ are consistent once established (e.g. remove | |
| 284 // authenticated_username_ altogether). Bug 107160. | |
| 285 | |
| 286 NotifyDiagnosticsObservers(USERNAME, username); | |
| 287 | |
| 288 // Go ahead and update the last signed in username here as well. Once a | |
| 289 // user is signed in the two preferences should match. Doing it here as | |
| 290 // opposed to on signin allows us to catch the upgrade scenario. | |
| 291 profile_->GetPrefs()->SetString(prefs::kGoogleServicesLastUsername, username); | |
| 292 } | 145 } |
| 293 | 146 |
| 294 std::string SigninManager::SigninTypeToString( | 147 std::string SigninManager::SigninTypeToString( |
| 295 SigninManager::SigninType type) { | 148 SigninManager::SigninType type) { |
| 296 switch (type) { | 149 switch (type) { |
| 297 case SIGNIN_TYPE_NONE: | 150 case SIGNIN_TYPE_NONE: |
| 298 return "No Signin"; | 151 return "No Signin"; |
| 299 case SIGNIN_TYPE_CLIENT_LOGIN: | 152 case SIGNIN_TYPE_CLIENT_LOGIN: |
| 300 return "Client Login"; | 153 return "Client Login"; |
| 301 case SIGNIN_TYPE_WITH_CREDENTIALS: | 154 case SIGNIN_TYPE_WITH_CREDENTIALS: |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 | 192 |
| 340 NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); | 193 NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); |
| 341 return true; | 194 return true; |
| 342 } | 195 } |
| 343 | 196 |
| 344 // Users must always sign out before they sign in again. | 197 // Users must always sign out before they sign in again. |
| 345 void SigninManager::StartSignIn(const std::string& username, | 198 void SigninManager::StartSignIn(const std::string& username, |
| 346 const std::string& password, | 199 const std::string& password, |
| 347 const std::string& login_token, | 200 const std::string& login_token, |
| 348 const std::string& login_captcha) { | 201 const std::string& login_captcha) { |
| 349 DCHECK(authenticated_username_.empty() || | 202 DCHECK(GetAuthenticatedUsername().empty() || |
| 350 gaia::AreEmailsSame(username, authenticated_username_)); | 203 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| 351 | 204 |
| 352 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_LOGIN, username, password)) | 205 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_LOGIN, username, password)) |
| 353 return; | 206 return; |
| 354 | 207 |
| 355 client_login_->StartClientLogin(username, | 208 client_login_->StartClientLogin(username, |
| 356 password, | 209 password, |
| 357 "", | 210 "", |
| 358 login_token, | 211 login_token, |
| 359 login_captcha, | 212 login_captcha, |
| 360 GaiaAuthFetcher::HostedAccountsNotAllowed); | 213 GaiaAuthFetcher::HostedAccountsNotAllowed); |
| 361 | 214 |
| 362 // Register for token availability. The signin manager will pre-login the | 215 // Register for token availability. The signin manager will pre-login the |
| 363 // user when the GAIA service token is ready for use. Only do this if we | 216 // user when the GAIA service token is ready for use. |
| 364 // are not running in ChomiumOS, since it handles pre-login itself, and if | |
| 365 // cookies are not disabled for Google accounts. | |
| 366 #if !defined(OS_CHROMEOS) | |
| 367 if (AreSigninCookiesAllowed(profile_)) { | 217 if (AreSigninCookiesAllowed(profile_)) { |
| 368 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 218 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 369 registrar_.Add(this, | 219 registrar_.Add(this, |
| 370 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 220 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 371 content::Source<TokenService>(token_service)); | 221 content::Source<TokenService>(token_service)); |
| 372 } | 222 } |
| 373 #endif | |
| 374 } | 223 } |
| 375 | 224 |
| 376 void SigninManager::ProvideSecondFactorAccessCode( | 225 void SigninManager::ProvideSecondFactorAccessCode( |
| 377 const std::string& access_code) { | 226 const std::string& access_code) { |
| 378 DCHECK(!possibly_invalid_username_.empty() && !password_.empty() && | 227 DCHECK(!possibly_invalid_username_.empty() && !password_.empty() && |
| 379 last_result_.data.empty()); | 228 last_result_.data.empty()); |
| 380 DCHECK(type_ == SIGNIN_TYPE_CLIENT_LOGIN); | 229 DCHECK(type_ == SIGNIN_TYPE_CLIENT_LOGIN); |
| 381 | 230 |
| 382 client_login_.reset(new GaiaAuthFetcher(this, | 231 client_login_.reset(new GaiaAuthFetcher(this, |
| 383 GaiaConstants::kChromeSource, | 232 GaiaConstants::kChromeSource, |
| 384 profile_->GetRequestContext())); | 233 profile_->GetRequestContext())); |
| 385 client_login_->StartClientLogin(possibly_invalid_username_, | 234 client_login_->StartClientLogin(possibly_invalid_username_, |
| 386 access_code, | 235 access_code, |
| 387 "", | 236 "", |
| 388 std::string(), | 237 std::string(), |
| 389 std::string(), | 238 std::string(), |
| 390 GaiaAuthFetcher::HostedAccountsNotAllowed); | 239 GaiaAuthFetcher::HostedAccountsNotAllowed); |
| 391 } | 240 } |
| 392 | 241 |
| 393 void SigninManager::StartSignInWithCredentials(const std::string& session_index, | 242 void SigninManager::StartSignInWithCredentials(const std::string& session_index, |
| 394 const std::string& username, | 243 const std::string& username, |
| 395 const std::string& password) { | 244 const std::string& password) { |
| 396 DCHECK(authenticated_username_.empty() || | 245 DCHECK(GetAuthenticatedUsername().empty() || |
| 397 gaia::AreEmailsSame(username, authenticated_username_)); | 246 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| 398 | 247 |
| 399 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) | 248 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) |
| 400 return; | 249 return; |
| 401 | 250 |
| 402 if (password.empty()) { | 251 if (password.empty()) { |
| 403 // Chrome must verify the GAIA cookies first if auto sign-in is triggered | 252 // Chrome must verify the GAIA cookies first if auto sign-in is triggered |
| 404 // with no password provided. This is to protect Chrome against forged | 253 // with no password provided. This is to protect Chrome against forged |
| 405 // GAIA cookies from a super-domain. | 254 // GAIA cookies from a super-domain. |
| 406 VerifyGaiaCookiesBeforeSignIn(session_index); | 255 VerifyGaiaCookiesBeforeSignIn(session_index); |
| 407 } else { | 256 } else { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 if (success) { | 300 if (success) { |
| 452 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); | 301 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); |
| 453 } else { | 302 } else { |
| 454 HandleAuthError(GoogleServiceAuthError( | 303 HandleAuthError(GoogleServiceAuthError( |
| 455 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); | 304 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); |
| 456 } | 305 } |
| 457 } | 306 } |
| 458 | 307 |
| 459 void SigninManager::StartSignInWithOAuth(const std::string& username, | 308 void SigninManager::StartSignInWithOAuth(const std::string& username, |
| 460 const std::string& password) { | 309 const std::string& password) { |
| 461 DCHECK(authenticated_username_.empty()); | 310 DCHECK(GetAuthenticatedUsername().empty()); |
| 462 | 311 |
| 463 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_OAUTH, username, password)) | 312 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_OAUTH, username, password)) |
| 464 return; | 313 return; |
| 465 | 314 |
| 466 std::vector<std::string> scopes; | 315 std::vector<std::string> scopes; |
| 467 scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope()); | 316 scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope()); |
| 468 const std::string& locale = g_browser_process->GetApplicationLocale(); | 317 const std::string& locale = g_browser_process->GetApplicationLocale(); |
| 469 | 318 |
| 470 client_login_->StartClientOAuth( | 319 client_login_->StartClientOAuth( |
| 471 username, password, scopes, std::string(), locale); | 320 username, password, scopes, std::string(), locale); |
| 472 | 321 |
| 473 // Register for token availability. The signin manager will pre-login the | 322 // Register for token availability. The signin manager will pre-login the |
| 474 // user when the GAIA service token is ready for use. Only do this if we | 323 // user when the GAIA service token is ready for use. |
| 475 // are not running in ChomiumOS, since it handles pre-login itself, and if | |
| 476 // cookies are not disabled for Google accounts. | |
| 477 #if !defined(OS_CHROMEOS) | |
| 478 if (AreSigninCookiesAllowed(profile_)) { | 324 if (AreSigninCookiesAllowed(profile_)) { |
| 479 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 325 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 480 registrar_.Add(this, | 326 registrar_.Add(this, |
| 481 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 327 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 482 content::Source<TokenService>(token_service)); | 328 content::Source<TokenService>(token_service)); |
| 483 } | 329 } |
| 484 #endif | |
| 485 } | 330 } |
| 486 | 331 |
| 487 void SigninManager::ProvideOAuthChallengeResponse( | 332 void SigninManager::ProvideOAuthChallengeResponse( |
| 488 GoogleServiceAuthError::State type, | 333 GoogleServiceAuthError::State type, |
| 489 const std::string& token, | 334 const std::string& token, |
| 490 const std::string& solution) { | 335 const std::string& solution) { |
| 491 DCHECK(!possibly_invalid_username_.empty() && !password_.empty()); | 336 DCHECK(!possibly_invalid_username_.empty() && !password_.empty()); |
| 492 DCHECK(type_ == SIGNIN_TYPE_CLIENT_OAUTH); | 337 DCHECK(type_ == SIGNIN_TYPE_CLIENT_OAUTH); |
| 493 | 338 |
| 494 client_login_.reset(new GaiaAuthFetcher(this, | 339 client_login_.reset(new GaiaAuthFetcher(this, |
| 495 GaiaConstants::kChromeSource, | 340 GaiaConstants::kChromeSource, |
| 496 profile_->GetRequestContext())); | 341 profile_->GetRequestContext())); |
| 497 client_login_->StartClientOAuthChallengeResponse(type, token, solution); | 342 client_login_->StartClientOAuthChallengeResponse(type, token, solution); |
| 498 } | 343 } |
| 499 | 344 |
| 500 void SigninManager::ClearTransientSigninData() { | 345 void SigninManager::ClearTransientSigninData() { |
| 501 DCHECK(IsInitialized()); | 346 DCHECK(IsInitialized()); |
| 502 | 347 |
| 503 CleanupNotificationRegistration(); | 348 CleanupNotificationRegistration(); |
| 504 client_login_.reset(); | 349 client_login_.reset(); |
| 505 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 350 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 506 policy_client_.reset(); | 351 policy_client_.reset(); |
| 507 #endif | 352 #endif |
| 508 last_result_ = ClientLoginResult(); | 353 last_result_ = ClientLoginResult(); |
| 509 possibly_invalid_username_.clear(); | 354 possibly_invalid_username_.clear(); |
| 510 password_.clear(); | 355 password_.clear(); |
| 511 had_two_factor_error_ = false; | 356 had_two_factor_error_ = false; |
| 512 type_ = SIGNIN_TYPE_NONE; | 357 type_ = SIGNIN_TYPE_NONE; |
| 513 temp_oauth_login_tokens_ = ClientOAuthResult(); | 358 temp_oauth_login_tokens_ = ClientOAuthResult(); |
| 514 } | 359 } |
| 515 | 360 |
| 516 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, | 361 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, |
| 517 bool clear_transient_data) { | 362 bool clear_transient_data) { |
| 518 // In some cases, the user should not be signed out. For example, the failure | 363 // In some cases, the user should not be signed out. For example, the failure |
| 519 // may be due to a captcha or OTP challenge. In these cases, the transient | 364 // may be due to a captcha or OTP challenge. In these cases, the transient |
| 520 // data must be kept to properly handle the follow up. This routine clears | 365 // data must be kept to properly handle the follow up. This routine clears |
| 521 // the data before sending out the notification so the SigninManager is no | 366 // the data before sending out the notification so the SigninManager is no |
| 522 // longer in the AuthInProgress state when the notification goes out. | 367 // longer in the AuthInProgress state when the notification goes out. |
| 523 if (clear_transient_data) | 368 if (clear_transient_data) |
| 524 ClearTransientSigninData(); | 369 ClearTransientSigninData(); |
| 525 | 370 |
| 526 content::NotificationService::current()->Notify( | 371 content::NotificationService::current()->Notify( |
| 527 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | 372 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, |
| 528 content::Source<Profile>(profile_), | 373 content::Source<Profile>(profile_), |
| 529 content::Details<const GoogleServiceAuthError>(&error)); | 374 content::Details<const GoogleServiceAuthError>(&error)); |
| 530 } | 375 } |
| 531 | 376 |
| 532 void SigninManager::SignOut() { | 377 void SigninManager::SignOut() { |
| 533 DCHECK(IsInitialized()); | 378 DCHECK(IsInitialized()); |
| 534 | 379 |
| 535 if (authenticated_username_.empty()) { | 380 if (GetAuthenticatedUsername().empty()) { |
| 536 if (AuthInProgress()) { | 381 if (AuthInProgress()) { |
| 537 // If the user is in the process of signing in, then treat a call to | 382 // If the user is in the process of signing in, then treat a call to |
| 538 // SignOut as a cancellation request. | 383 // SignOut as a cancellation request. |
| 539 GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); | 384 GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); |
| 540 HandleAuthError(error, true); | 385 HandleAuthError(error, true); |
| 541 } else { | 386 } else { |
| 542 // Clean up our transient data and exit if we aren't signed in. | 387 // Clean up our transient data and exit if we aren't signed in. |
| 543 // This avoids a perf regression from clearing out the TokenDB if | 388 // This avoids a perf regression from clearing out the TokenDB if |
| 544 // SignOut() is invoked on startup to clean up any incomplete previous | 389 // SignOut() is invoked on startup to clean up any incomplete previous |
| 545 // signin attempts. | 390 // signin attempts. |
| 546 ClearTransientSigninData(); | 391 ClearTransientSigninData(); |
| 547 } | 392 } |
| 548 return; | 393 return; |
|
Andrew T Wilson (Slow)
2013/04/18 13:28:07
Not to keep beating on the SignOut drum, but it's
| |
| 549 } | 394 } |
| 550 | 395 |
| 551 if (prohibit_signout_) { | 396 if (prohibit_signout_) { |
| 552 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; | 397 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; |
| 553 return; | 398 return; |
| 554 } | 399 } |
| 555 DCHECK(!authenticated_username_.empty()); | |
| 556 GoogleServiceSignoutDetails details(authenticated_username_); | |
| 557 | 400 |
| 558 ClearTransientSigninData(); | 401 ClearTransientSigninData(); |
| 559 authenticated_username_.clear(); | |
| 560 profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername); | |
| 561 | |
| 562 // Erase (now) stale information from AboutSigninInternals. | |
| 563 NotifyDiagnosticsObservers(USERNAME, std::string()); | |
| 564 NotifyDiagnosticsObservers(LSID, std::string()); | |
| 565 NotifyDiagnosticsObservers(signin_internals_util::SID, std::string()); | |
| 566 | |
| 567 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | |
| 568 content::NotificationService::current()->Notify( | |
| 569 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, | |
| 570 content::Source<Profile>(profile_), | |
| 571 content::Details<const GoogleServiceSignoutDetails>(&details)); | |
| 572 RevokeOAuthLoginToken(); | 402 RevokeOAuthLoginToken(); |
| 573 token_service->ResetCredentialsInMemory(); | 403 SigninManagerBase::SignOut(); |
| 574 token_service->EraseTokensFromDB(); | |
| 575 } | 404 } |
| 576 | 405 |
| 577 void SigninManager::RevokeOAuthLoginToken() { | 406 void SigninManager::RevokeOAuthLoginToken() { |
| 578 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 407 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 579 if (token_service->HasOAuthLoginToken()) { | 408 if (token_service->HasOAuthLoginToken()) { |
| 580 revoke_token_fetcher_.reset( | 409 revoke_token_fetcher_.reset( |
| 581 new GaiaAuthFetcher(this, | 410 new GaiaAuthFetcher(this, |
| 582 GaiaConstants::kChromeSource, | 411 GaiaConstants::kChromeSource, |
| 583 profile_->GetRequestContext())); | 412 profile_->GetRequestContext())); |
| 584 revoke_token_fetcher_->StartRevokeOAuth2Token( | 413 revoke_token_fetcher_->StartRevokeOAuth2Token( |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 692 // expected, return an error. | 521 // expected, return an error. |
| 693 if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && | 522 if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && |
| 694 !gaia::AreEmailsSame(display_email_iter->second, | 523 !gaia::AreEmailsSame(display_email_iter->second, |
| 695 possibly_invalid_username_)) { | 524 possibly_invalid_username_)) { |
| 696 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); | 525 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); |
| 697 return; | 526 return; |
| 698 } | 527 } |
| 699 | 528 |
| 700 possibly_invalid_username_ = email_iter->second; | 529 possibly_invalid_username_ = email_iter->second; |
| 701 | 530 |
| 702 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 531 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 703 // TODO(atwilson): Move this code out to OneClickSignin instead of having | 532 // TODO(atwilson): Move this code out to OneClickSignin instead of having |
| 704 // it embedded in SigninManager - we don't want UI logic in SigninManager. | 533 // it embedded in SigninManager - we don't want UI logic in SigninManager. |
| 705 // If this is a new signin (authenticated_username_ is not set) and we have | 534 // If this is a new signin (authenticated_username_ is not set) and we have |
| 706 // an OAuth token, try loading policy for this user now, before any signed in | 535 // an OAuth token, try loading policy for this user now, before any signed in |
| 707 // services are initialized. If there's no oauth token (the user is using the | 536 // services are initialized. If there's no oauth token (the user is using the |
| 708 // old ClientLogin flow) then policy will get loaded once the TokenService | 537 // old ClientLogin flow) then policy will get loaded once the TokenService |
| 709 // finishes initializing (not ideal, but it's a reasonable fallback). | 538 // finishes initializing (not ideal, but it's a reasonable fallback). |
| 710 if (authenticated_username_.empty() && | 539 if (GetAuthenticatedUsername().empty() && |
| 711 !temp_oauth_login_tokens_.refresh_token.empty()) { | 540 !temp_oauth_login_tokens_.refresh_token.empty()) { |
| 712 policy::UserPolicySigninService* policy_service = | 541 policy::UserPolicySigninService* policy_service = |
| 713 policy::UserPolicySigninServiceFactory::GetForProfile(profile_); | 542 policy::UserPolicySigninServiceFactory::GetForProfile(profile_); |
| 714 policy_service->RegisterPolicyClient( | 543 policy_service->RegisterPolicyClient( |
| 715 possibly_invalid_username_, | 544 possibly_invalid_username_, |
| 716 temp_oauth_login_tokens_.refresh_token, | 545 temp_oauth_login_tokens_.refresh_token, |
| 717 base::Bind(&SigninManager::OnRegisteredForPolicy, | 546 base::Bind(&SigninManager::OnRegisteredForPolicy, |
| 718 weak_pointer_factory_.GetWeakPtr())); | 547 weak_pointer_factory_.GetWeakPtr())); |
| 719 return; | 548 return; |
| 720 } | 549 } |
| 721 #endif | 550 #endif |
| 722 | 551 |
| 723 // Not waiting for policy load - just complete signin directly. | 552 // Not waiting for policy load - just complete signin directly. |
| 724 CompleteSigninAfterPolicyLoad(); | 553 CompleteSigninAfterPolicyLoad(); |
| 725 } | 554 } |
| 726 | 555 |
| 727 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 556 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 728 void SigninManager::OnRegisteredForPolicy( | 557 void SigninManager::OnRegisteredForPolicy( |
| 729 scoped_ptr<policy::CloudPolicyClient> client) { | 558 scoped_ptr<policy::CloudPolicyClient> client) { |
| 730 // If there's no token for the user (no policy) just finish signing in. | 559 // If there's no token for the user (no policy) just finish signing in. |
| 731 if (!client.get()) { | 560 if (!client.get()) { |
| 732 DVLOG(1) << "Policy registration failed"; | 561 DVLOG(1) << "Policy registration failed"; |
| 733 CompleteSigninAfterPolicyLoad(); | 562 CompleteSigninAfterPolicyLoad(); |
| 734 return; | 563 return; |
| 735 } | 564 } |
| 736 | 565 |
| 737 // Stash away a copy of our CloudPolicyClient (should not already have one). | 566 // Stash away a copy of our CloudPolicyClient (should not already have one). |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 823 SignOut(); | 652 SignOut(); |
| 824 } | 653 } |
| 825 } | 654 } |
| 826 #endif | 655 #endif |
| 827 | 656 |
| 828 void SigninManager::CompleteSigninAfterPolicyLoad() { | 657 void SigninManager::CompleteSigninAfterPolicyLoad() { |
| 829 DCHECK(!possibly_invalid_username_.empty()); | 658 DCHECK(!possibly_invalid_username_.empty()); |
| 830 SetAuthenticatedUsername(possibly_invalid_username_); | 659 SetAuthenticatedUsername(possibly_invalid_username_); |
| 831 possibly_invalid_username_.clear(); | 660 possibly_invalid_username_.clear(); |
| 832 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, | 661 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, |
| 833 authenticated_username_); | 662 GetAuthenticatedUsername()); |
| 834 | 663 |
| 835 GoogleServiceSigninSuccessDetails details(authenticated_username_, | 664 GoogleServiceSigninSuccessDetails details(GetAuthenticatedUsername(), |
| 836 password_); | 665 password_); |
| 837 content::NotificationService::current()->Notify( | 666 content::NotificationService::current()->Notify( |
| 838 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, | 667 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, |
| 839 content::Source<Profile>(profile_), | 668 content::Source<Profile>(profile_), |
| 840 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); | 669 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); |
| 841 | 670 |
| 842 password_.clear(); // Don't need it anymore. | 671 password_.clear(); // Don't need it anymore. |
| 843 DisableOneClickSignIn(profile_); // Don't ever offer again. | 672 DisableOneClickSignIn(profile_); // Don't ever offer again. |
| 844 | 673 |
| 845 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 674 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 876 | 705 |
| 877 void SigninManager::OnUbertokenFailure(const GoogleServiceAuthError& error) { | 706 void SigninManager::OnUbertokenFailure(const GoogleServiceAuthError& error) { |
| 878 LOG(WARNING) << " Unable to login the user to the web: " << error.ToString(); | 707 LOG(WARNING) << " Unable to login the user to the web: " << error.ToString(); |
| 879 ubertoken_fetcher_.reset(); | 708 ubertoken_fetcher_.reset(); |
| 880 } | 709 } |
| 881 | 710 |
| 882 void SigninManager::Observe(int type, | 711 void SigninManager::Observe(int type, |
| 883 const content::NotificationSource& source, | 712 const content::NotificationSource& source, |
| 884 const content::NotificationDetails& details) { | 713 const content::NotificationDetails& details) { |
| 885 switch (type) { | 714 switch (type) { |
| 886 #if !defined(OS_CHROMEOS) | |
| 887 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { | 715 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { |
| 888 TokenService::TokenAvailableDetails* tok_details = | 716 TokenService::TokenAvailableDetails* tok_details = |
| 889 content::Details<TokenService::TokenAvailableDetails>( | 717 content::Details<TokenService::TokenAvailableDetails>( |
| 890 details).ptr(); | 718 details).ptr(); |
| 891 | 719 |
| 892 // If a GAIA service token has become available, use it to pre-login the | 720 // If a GAIA service token has become available, use it to pre-login the |
| 893 // user to other services that depend on GAIA credentials. | 721 // user to other services that depend on GAIA credentials. |
| 894 if (tok_details->service() == | 722 if (tok_details->service() == |
| 895 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { | 723 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { |
| 896 ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this)); | 724 ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this)); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 908 // if this was from the current signin process. | 736 // if this was from the current signin process. |
| 909 registrar_.Remove(this, | 737 registrar_.Remove(this, |
| 910 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 738 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| 911 source); | 739 source); |
| 912 if (signin_process_id_ == | 740 if (signin_process_id_ == |
| 913 content::Source<content::RenderProcessHost>(source)->GetID()) { | 741 content::Source<content::RenderProcessHost>(source)->GetID()) { |
| 914 signin_process_id_ = kInvalidProcessId; | 742 signin_process_id_ = kInvalidProcessId; |
| 915 } | 743 } |
| 916 break; | 744 break; |
| 917 } | 745 } |
| 918 #endif | |
| 919 default: | 746 default: |
| 920 NOTREACHED(); | 747 NOTREACHED(); |
| 921 } | 748 } |
| 922 } | 749 } |
| 923 | 750 |
| 924 void SigninManager::Shutdown() { | |
| 925 if (signin_global_error_.get()) { | |
| 926 GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError( | |
| 927 signin_global_error_.get()); | |
| 928 signin_global_error_.reset(); | |
| 929 } | |
| 930 } | |
| 931 | |
| 932 void SigninManager::ProhibitSignout(bool prohibit_signout) { | 751 void SigninManager::ProhibitSignout(bool prohibit_signout) { |
| 933 prohibit_signout_ = prohibit_signout; | 752 prohibit_signout_ = prohibit_signout; |
| 934 } | 753 } |
| 935 | 754 |
| 936 bool SigninManager::IsSignoutProhibited() const { | 755 bool SigninManager::IsSignoutProhibited() const { |
| 937 return prohibit_signout_; | 756 return prohibit_signout_; |
| 938 } | 757 } |
| 939 | |
| 940 void SigninManager::OnGoogleServicesUsernamePatternChanged() { | |
| 941 if (!authenticated_username_.empty() && | |
| 942 !IsAllowedUsername(authenticated_username_)) { | |
| 943 // Signed in user is invalid according to the current policy so sign | |
| 944 // the user out. | |
| 945 SignOut(); | |
| 946 } | |
| 947 } | |
| 948 | |
| 949 void SigninManager::OnSigninAllowedPrefChanged() { | |
| 950 if (!IsSigninAllowed()) | |
| 951 SignOut(); | |
| 952 } | |
| 953 | |
| 954 void SigninManager::AddSigninDiagnosticsObserver( | |
| 955 SigninDiagnosticsObserver* observer) { | |
| 956 signin_diagnostics_observers_.AddObserver(observer); | |
| 957 } | |
| 958 | |
| 959 void SigninManager::RemoveSigninDiagnosticsObserver( | |
| 960 SigninDiagnosticsObserver* observer) { | |
| 961 signin_diagnostics_observers_.RemoveObserver(observer); | |
| 962 } | |
| 963 | |
| 964 void SigninManager::NotifyDiagnosticsObservers( | |
| 965 const UntimedSigninStatusField& field, | |
| 966 const std::string& value) { | |
| 967 FOR_EACH_OBSERVER(SigninDiagnosticsObserver, | |
| 968 signin_diagnostics_observers_, | |
| 969 NotifySigninValueChanged(field, value)); | |
| 970 } | |
| 971 | |
| 972 void SigninManager::NotifyDiagnosticsObservers( | |
| 973 const TimedSigninStatusField& field, | |
| 974 const std::string& value) { | |
| 975 FOR_EACH_OBSERVER(SigninDiagnosticsObserver, | |
| 976 signin_diagnostics_observers_, | |
| 977 NotifySigninValueChanged(field, value)); | |
| 978 } | |
| OLD | NEW |