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() { } |
|
Roger Tawa OOO till Jul 10th
2013/03/27 17:36:33
should } be on next line?
tim (not reviewing)
2013/03/29 18:03:16
Done.
| |
| 176 DCHECK(!signin_global_error_.get()) << | |
| 177 "SigninManager::Initialize called but not SigninManager::Shutdown"; | |
| 178 } | |
| 179 | 126 |
| 180 void SigninManager::Initialize(Profile* profile) { | 127 void SigninManager::InitTokenService() { |
| 181 // Should never call Initialize() twice. | 128 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_); | 129 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 213 if (token_service) { | 130 if (token_service && !GetAuthenticatedUsername().empty()) |
| 214 token_service->Initialize(GaiaConstants::kChromeSource, profile_); | 131 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 } | 132 } |
| 255 | 133 |
| 256 void SigninManager::CleanupNotificationRegistration() { | 134 void SigninManager::CleanupNotificationRegistration() { |
| 257 #if !defined(OS_CHROMEOS) | |
| 258 content::Source<TokenService> token_service( | 135 content::Source<TokenService> token_service( |
| 259 TokenServiceFactory::GetForProfile(profile_)); | 136 TokenServiceFactory::GetForProfile(profile_)); |
| 260 if (registrar_.IsRegistered(this, | 137 if (registrar_.IsRegistered(this, |
| 261 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 138 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 262 token_service)) { | 139 token_service)) { |
| 263 registrar_.Remove(this, | 140 registrar_.Remove(this, |
| 264 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 141 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 265 token_service); | 142 token_service); |
| 266 } | 143 } |
| 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 } | 144 } |
| 293 | 145 |
| 294 std::string SigninManager::SigninTypeToString( | 146 std::string SigninManager::SigninTypeToString( |
| 295 SigninManager::SigninType type) { | 147 SigninManager::SigninType type) { |
| 296 switch (type) { | 148 switch (type) { |
| 297 case SIGNIN_TYPE_NONE: | 149 case SIGNIN_TYPE_NONE: |
| 298 return "No Signin"; | 150 return "No Signin"; |
| 299 case SIGNIN_TYPE_CLIENT_LOGIN: | 151 case SIGNIN_TYPE_CLIENT_LOGIN: |
| 300 return "Client Login"; | 152 return "Client Login"; |
| 301 case SIGNIN_TYPE_WITH_CREDENTIALS: | 153 case SIGNIN_TYPE_WITH_CREDENTIALS: |
| 302 return "Signin with credentials"; | 154 return "Signin with credentials"; |
| 303 case SIGNIN_TYPE_CLIENT_OAUTH: | 155 case SIGNIN_TYPE_CLIENT_OAUTH: |
| 304 return "Client OAuth"; | 156 return "Client OAuth"; |
| 305 } | 157 } |
| 306 | 158 |
| 307 NOTREACHED(); | 159 NOTREACHED(); |
| 308 return ""; | 160 return ""; |
| 309 } | 161 } |
| 310 | 162 |
| 311 | |
| 312 bool SigninManager::PrepareForSignin(SigninType type, | 163 bool SigninManager::PrepareForSignin(SigninType type, |
| 313 const std::string& username, | 164 const std::string& username, |
| 314 const std::string& password) { | 165 const std::string& password) { |
| 315 DCHECK(possibly_invalid_username_.empty() || | 166 DCHECK(possibly_invalid_username_.empty() || |
| 316 possibly_invalid_username_ == username); | 167 possibly_invalid_username_ == username); |
| 317 DCHECK(!username.empty()); | 168 DCHECK(!username.empty()); |
| 318 | 169 |
| 319 if (!IsAllowedUsername(username)) { | 170 if (!IsAllowedUsername(username)) { |
| 320 // Account is not allowed by admin policy. | 171 // Account is not allowed by admin policy. |
| 321 HandleAuthError(GoogleServiceAuthError( | 172 HandleAuthError(GoogleServiceAuthError( |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 339 | 190 |
| 340 NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); | 191 NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); |
| 341 return true; | 192 return true; |
| 342 } | 193 } |
| 343 | 194 |
| 344 // Users must always sign out before they sign in again. | 195 // Users must always sign out before they sign in again. |
| 345 void SigninManager::StartSignIn(const std::string& username, | 196 void SigninManager::StartSignIn(const std::string& username, |
| 346 const std::string& password, | 197 const std::string& password, |
| 347 const std::string& login_token, | 198 const std::string& login_token, |
| 348 const std::string& login_captcha) { | 199 const std::string& login_captcha) { |
| 349 DCHECK(authenticated_username_.empty() || | 200 DCHECK(GetAuthenticatedUsername().empty() || |
| 350 gaia::AreEmailsSame(username, authenticated_username_)); | 201 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| 351 | 202 |
| 352 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_LOGIN, username, password)) | 203 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_LOGIN, username, password)) |
| 353 return; | 204 return; |
| 354 | 205 |
| 355 client_login_->StartClientLogin(username, | 206 client_login_->StartClientLogin(username, |
| 356 password, | 207 password, |
| 357 "", | 208 "", |
| 358 login_token, | 209 login_token, |
| 359 login_captcha, | 210 login_captcha, |
| 360 GaiaAuthFetcher::HostedAccountsNotAllowed); | 211 GaiaAuthFetcher::HostedAccountsNotAllowed); |
| 361 | 212 |
| 362 // Register for token availability. The signin manager will pre-login the | 213 // 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 | 214 // 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_)) { | 215 if (AreSigninCookiesAllowed(profile_)) { |
| 368 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 216 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 369 registrar_.Add(this, | 217 registrar_.Add(this, |
| 370 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 218 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 371 content::Source<TokenService>(token_service)); | 219 content::Source<TokenService>(token_service)); |
| 372 } | 220 } |
| 373 #endif | |
| 374 } | 221 } |
| 375 | 222 |
| 376 void SigninManager::ProvideSecondFactorAccessCode( | 223 void SigninManager::ProvideSecondFactorAccessCode( |
| 377 const std::string& access_code) { | 224 const std::string& access_code) { |
| 378 DCHECK(!possibly_invalid_username_.empty() && !password_.empty() && | 225 DCHECK(!possibly_invalid_username_.empty() && !password_.empty() && |
| 379 last_result_.data.empty()); | 226 last_result_.data.empty()); |
| 380 DCHECK(type_ == SIGNIN_TYPE_CLIENT_LOGIN); | 227 DCHECK(type_ == SIGNIN_TYPE_CLIENT_LOGIN); |
| 381 | 228 |
| 382 client_login_.reset(new GaiaAuthFetcher(this, | 229 client_login_.reset(new GaiaAuthFetcher(this, |
| 383 GaiaConstants::kChromeSource, | 230 GaiaConstants::kChromeSource, |
| 384 profile_->GetRequestContext())); | 231 profile_->GetRequestContext())); |
| 385 client_login_->StartClientLogin(possibly_invalid_username_, | 232 client_login_->StartClientLogin(possibly_invalid_username_, |
| 386 access_code, | 233 access_code, |
| 387 "", | 234 "", |
| 388 std::string(), | 235 std::string(), |
| 389 std::string(), | 236 std::string(), |
| 390 GaiaAuthFetcher::HostedAccountsNotAllowed); | 237 GaiaAuthFetcher::HostedAccountsNotAllowed); |
| 391 } | 238 } |
| 392 | 239 |
| 393 void SigninManager::StartSignInWithCredentials(const std::string& session_index, | 240 void SigninManager::StartSignInWithCredentials(const std::string& session_index, |
| 394 const std::string& username, | 241 const std::string& username, |
| 395 const std::string& password) { | 242 const std::string& password) { |
| 396 DCHECK(authenticated_username_.empty() || | 243 DCHECK(GetAuthenticatedUsername().empty() || |
| 397 gaia::AreEmailsSame(username, authenticated_username_)); | 244 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| 398 | 245 |
| 399 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) | 246 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) |
| 400 return; | 247 return; |
| 401 | 248 |
| 402 if (password.empty()) { | 249 if (password.empty()) { |
| 403 // Chrome must verify the GAIA cookies first if auto sign-in is triggered | 250 // 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 | 251 // with no password provided. This is to protect Chrome against forged |
| 405 // GAIA cookies from a super-domain. | 252 // GAIA cookies from a super-domain. |
| 406 VerifyGaiaCookiesBeforeSignIn(session_index); | 253 VerifyGaiaCookiesBeforeSignIn(session_index); |
| 407 } else { | 254 } else { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 if (success) { | 298 if (success) { |
| 452 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); | 299 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); |
| 453 } else { | 300 } else { |
| 454 HandleAuthError(GoogleServiceAuthError( | 301 HandleAuthError(GoogleServiceAuthError( |
| 455 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); | 302 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); |
| 456 } | 303 } |
| 457 } | 304 } |
| 458 | 305 |
| 459 void SigninManager::StartSignInWithOAuth(const std::string& username, | 306 void SigninManager::StartSignInWithOAuth(const std::string& username, |
| 460 const std::string& password) { | 307 const std::string& password) { |
| 461 DCHECK(authenticated_username_.empty()); | 308 DCHECK(GetAuthenticatedUsername().empty()); |
| 462 | 309 |
| 463 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_OAUTH, username, password)) | 310 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_OAUTH, username, password)) |
| 464 return; | 311 return; |
| 465 | 312 |
| 466 std::vector<std::string> scopes; | 313 std::vector<std::string> scopes; |
| 467 scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope()); | 314 scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope()); |
| 468 const std::string& locale = g_browser_process->GetApplicationLocale(); | 315 const std::string& locale = g_browser_process->GetApplicationLocale(); |
| 469 | 316 |
| 470 client_login_->StartClientOAuth(username, password, scopes, "", locale); | 317 client_login_->StartClientOAuth(username, password, scopes, "", locale); |
| 471 | 318 |
| 472 // Register for token availability. The signin manager will pre-login the | 319 // Register for token availability. The signin manager will pre-login the |
| 473 // user when the GAIA service token is ready for use. Only do this if we | 320 // user when the GAIA service token is ready for use. |
| 474 // are not running in ChomiumOS, since it handles pre-login itself, and if | |
| 475 // cookies are not disabled for Google accounts. | |
| 476 #if !defined(OS_CHROMEOS) | |
| 477 if (AreSigninCookiesAllowed(profile_)) { | 321 if (AreSigninCookiesAllowed(profile_)) { |
| 478 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 322 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 479 registrar_.Add(this, | 323 registrar_.Add(this, |
| 480 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 324 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 481 content::Source<TokenService>(token_service)); | 325 content::Source<TokenService>(token_service)); |
| 482 } | 326 } |
| 483 #endif | |
| 484 } | 327 } |
| 485 | 328 |
| 486 void SigninManager::ProvideOAuthChallengeResponse( | 329 void SigninManager::ProvideOAuthChallengeResponse( |
| 487 GoogleServiceAuthError::State type, | 330 GoogleServiceAuthError::State type, |
| 488 const std::string& token, | 331 const std::string& token, |
| 489 const std::string& solution) { | 332 const std::string& solution) { |
| 490 DCHECK(!possibly_invalid_username_.empty() && !password_.empty()); | 333 DCHECK(!possibly_invalid_username_.empty() && !password_.empty()); |
| 491 DCHECK(type_ == SIGNIN_TYPE_CLIENT_OAUTH); | 334 DCHECK(type_ == SIGNIN_TYPE_CLIENT_OAUTH); |
| 492 | 335 |
| 493 client_login_.reset(new GaiaAuthFetcher(this, | 336 client_login_.reset(new GaiaAuthFetcher(this, |
| 494 GaiaConstants::kChromeSource, | 337 GaiaConstants::kChromeSource, |
| 495 profile_->GetRequestContext())); | 338 profile_->GetRequestContext())); |
| 496 client_login_->StartClientOAuthChallengeResponse(type, token, solution); | 339 client_login_->StartClientOAuthChallengeResponse(type, token, solution); |
| 497 } | 340 } |
| 498 | 341 |
| 499 void SigninManager::ClearTransientSigninData() { | 342 void SigninManager::ClearTransientSigninData() { |
| 500 DCHECK(IsInitialized()); | 343 DCHECK(IsInitialized()); |
| 501 | 344 |
| 502 CleanupNotificationRegistration(); | 345 CleanupNotificationRegistration(); |
| 503 client_login_.reset(); | 346 client_login_.reset(); |
| 504 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 347 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 505 policy_client_.reset(); | 348 policy_client_.reset(); |
| 506 #endif | 349 #endif |
| 507 last_result_ = ClientLoginResult(); | 350 last_result_ = ClientLoginResult(); |
| 508 possibly_invalid_username_.clear(); | 351 possibly_invalid_username_.clear(); |
| 509 password_.clear(); | 352 password_.clear(); |
| 510 had_two_factor_error_ = false; | 353 had_two_factor_error_ = false; |
| 511 type_ = SIGNIN_TYPE_NONE; | 354 type_ = SIGNIN_TYPE_NONE; |
| 512 temp_oauth_login_tokens_ = ClientOAuthResult(); | 355 temp_oauth_login_tokens_ = ClientOAuthResult(); |
| 513 } | 356 } |
| 514 | 357 |
| 515 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, | 358 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, |
| 516 bool clear_transient_data) { | 359 bool clear_transient_data) { |
| 517 content::NotificationService::current()->Notify( | 360 content::NotificationService::current()->Notify( |
| 518 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | 361 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, |
| 519 content::Source<Profile>(profile_), | 362 content::Source<Profile>(profile_), |
| 520 content::Details<const GoogleServiceAuthError>(&error)); | 363 content::Details<const GoogleServiceAuthError>(&error)); |
| 521 | 364 |
| 522 // In some cases, the user should not be signed out. For example, the failure | 365 // In some cases, the user should not be signed out. For example, the failure |
| 523 // may be due to a captcha or OTP challenge. In these cases, the transient | 366 // may be due to a captcha or OTP challenge. In these cases, the transient |
| 524 // data must be kept to properly handle the follow up. | 367 // data must be kept to properly handle the follow up. |
| 525 if (clear_transient_data) | 368 if (clear_transient_data) |
| 526 ClearTransientSigninData(); | 369 ClearTransientSigninData(); |
| 527 } | 370 } |
| 528 | 371 |
| 372 bool SigninManager::ShouldSignOut() { | |
| 373 if (prohibit_signout_) | |
| 374 return false; | |
| 375 | |
| 376 // Exit if we aren't signed in (or in the process of signing in). | |
| 377 // This avoids a perf regression from clearing out the TokenDB if | |
| 378 // SignOut() is invoked on startup to clean up any incomplete previous | |
| 379 // signin attempts. | |
| 380 if (GetAuthenticatedUsername().empty() && !client_login_.get()) | |
| 381 return false; | |
| 382 | |
| 383 return true; | |
| 384 } | |
| 385 | |
| 529 void SigninManager::SignOut() { | 386 void SigninManager::SignOut() { |
| 530 DCHECK(IsInitialized()); | 387 DCHECK(IsInitialized()); |
| 531 if (prohibit_signout_) { | 388 if (prohibit_signout_) { |
| 532 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; | 389 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; |
| 533 return; | 390 return; |
| 534 } | 391 } |
| 535 if (authenticated_username_.empty() && !client_login_.get()) { | |
| 536 // Clean up our transient data and exit if we aren't signed in (or in the | |
| 537 // process of signing in). This avoids a perf regression from clearing out | |
| 538 // the TokenDB if SignOut() is invoked on startup to clean up any | |
| 539 // incomplete previous signin attempts. | |
| 540 ClearTransientSigninData(); | |
| 541 return; | |
| 542 } | |
| 543 | |
| 544 GoogleServiceSignoutDetails details(authenticated_username_); | |
| 545 | 392 |
| 546 ClearTransientSigninData(); | 393 ClearTransientSigninData(); |
| 547 authenticated_username_.clear(); | 394 SigninManagerBase::SignOut(); |
| 548 profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername); | |
| 549 | |
| 550 // Erase (now) stale information from AboutSigninInternals. | |
| 551 NotifyDiagnosticsObservers(USERNAME, ""); | |
| 552 NotifyDiagnosticsObservers(LSID, ""); | |
| 553 NotifyDiagnosticsObservers( | |
| 554 signin_internals_util::SID, ""); | |
| 555 | |
| 556 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | |
| 557 content::NotificationService::current()->Notify( | |
| 558 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, | |
| 559 content::Source<Profile>(profile_), | |
| 560 content::Details<const GoogleServiceSignoutDetails>(&details)); | |
| 561 token_service->ResetCredentialsInMemory(); | |
| 562 token_service->EraseTokensFromDB(); | |
| 563 } | 395 } |
| 564 | 396 |
| 565 bool SigninManager::AuthInProgress() const { | 397 bool SigninManager::AuthInProgress() const { |
| 566 return !possibly_invalid_username_.empty(); | 398 return !possibly_invalid_username_.empty(); |
| 567 } | 399 } |
| 568 | 400 |
| 569 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { | 401 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { |
| 570 DCHECK(key == kGetInfoDisplayEmailKey || key == kGetInfoEmailKey); | 402 DCHECK(key == kGetInfoDisplayEmailKey || key == kGetInfoEmailKey); |
| 571 LOG(ERROR) << "Account is not associated with a valid email address. " | 403 LOG(ERROR) << "Account is not associated with a valid email address. " |
| 572 << "Login failed."; | 404 << "Login failed."; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 664 // expected, return an error. | 496 // expected, return an error. |
| 665 if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && | 497 if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && |
| 666 !gaia::AreEmailsSame(display_email_iter->second, | 498 !gaia::AreEmailsSame(display_email_iter->second, |
| 667 possibly_invalid_username_)) { | 499 possibly_invalid_username_)) { |
| 668 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); | 500 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); |
| 669 return; | 501 return; |
| 670 } | 502 } |
| 671 | 503 |
| 672 possibly_invalid_username_ = email_iter->second; | 504 possibly_invalid_username_ = email_iter->second; |
| 673 | 505 |
| 674 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 506 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 675 // TODO(atwilson): Move this code out to OneClickSignin instead of having | 507 // TODO(atwilson): Move this code out to OneClickSignin instead of having |
| 676 // it embedded in SigninManager - we don't want UI logic in SigninManager. | 508 // it embedded in SigninManager - we don't want UI logic in SigninManager. |
| 677 // If this is a new signin (authenticated_username_ is not set) and we have | 509 // If this is a new signin (authenticated_username_ is not set) and we have |
| 678 // an OAuth token, try loading policy for this user now, before any signed in | 510 // an OAuth token, try loading policy for this user now, before any signed in |
| 679 // services are initialized. If there's no oauth token (the user is using the | 511 // services are initialized. If there's no oauth token (the user is using the |
| 680 // old ClientLogin flow) then policy will get loaded once the TokenService | 512 // old ClientLogin flow) then policy will get loaded once the TokenService |
| 681 // finishes initializing (not ideal, but it's a reasonable fallback). | 513 // finishes initializing (not ideal, but it's a reasonable fallback). |
| 682 if (authenticated_username_.empty() && | 514 if (GetAuthenticatedUsername().empty() && |
| 683 !temp_oauth_login_tokens_.refresh_token.empty()) { | 515 !temp_oauth_login_tokens_.refresh_token.empty()) { |
| 684 policy::UserPolicySigninService* policy_service = | 516 policy::UserPolicySigninService* policy_service = |
| 685 policy::UserPolicySigninServiceFactory::GetForProfile(profile_); | 517 policy::UserPolicySigninServiceFactory::GetForProfile(profile_); |
| 686 policy_service->RegisterPolicyClient( | 518 policy_service->RegisterPolicyClient( |
| 687 possibly_invalid_username_, | 519 possibly_invalid_username_, |
| 688 temp_oauth_login_tokens_.refresh_token, | 520 temp_oauth_login_tokens_.refresh_token, |
| 689 base::Bind(&SigninManager::OnRegisteredForPolicy, | 521 base::Bind(&SigninManager::OnRegisteredForPolicy, |
| 690 weak_pointer_factory_.GetWeakPtr())); | 522 weak_pointer_factory_.GetWeakPtr())); |
| 691 return; | 523 return; |
| 692 } | 524 } |
| 693 #endif | 525 #endif |
| 694 | 526 |
| 695 // Not waiting for policy load - just complete signin directly. | 527 // Not waiting for policy load - just complete signin directly. |
| 696 CompleteSigninAfterPolicyLoad(); | 528 CompleteSigninAfterPolicyLoad(); |
| 697 } | 529 } |
| 698 | 530 |
| 699 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 531 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 700 void SigninManager::OnRegisteredForPolicy( | 532 void SigninManager::OnRegisteredForPolicy( |
| 701 scoped_ptr<policy::CloudPolicyClient> client) { | 533 scoped_ptr<policy::CloudPolicyClient> client) { |
| 702 // If there's no token for the user (no policy) just finish signing in. | 534 // If there's no token for the user (no policy) just finish signing in. |
| 703 if (!client.get()) { | 535 if (!client.get()) { |
| 704 DVLOG(1) << "Policy registration failed"; | 536 DVLOG(1) << "Policy registration failed"; |
| 705 CompleteSigninAfterPolicyLoad(); | 537 CompleteSigninAfterPolicyLoad(); |
| 706 return; | 538 return; |
| 707 } | 539 } |
| 708 | 540 |
| 709 // Stash away a copy of our CloudPolicyClient (should not already have one). | 541 // Stash away a copy of our CloudPolicyClient (should not already have one). |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 790 SignOut(); | 622 SignOut(); |
| 791 } | 623 } |
| 792 } | 624 } |
| 793 #endif | 625 #endif |
| 794 | 626 |
| 795 void SigninManager::CompleteSigninAfterPolicyLoad() { | 627 void SigninManager::CompleteSigninAfterPolicyLoad() { |
| 796 DCHECK(!possibly_invalid_username_.empty()); | 628 DCHECK(!possibly_invalid_username_.empty()); |
| 797 SetAuthenticatedUsername(possibly_invalid_username_); | 629 SetAuthenticatedUsername(possibly_invalid_username_); |
| 798 possibly_invalid_username_.clear(); | 630 possibly_invalid_username_.clear(); |
| 799 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, | 631 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, |
| 800 authenticated_username_); | 632 GetAuthenticatedUsername()); |
| 801 | 633 |
| 802 GoogleServiceSigninSuccessDetails details(authenticated_username_, | 634 GoogleServiceSigninSuccessDetails details(GetAuthenticatedUsername(), |
| 803 password_); | 635 password_); |
| 804 content::NotificationService::current()->Notify( | 636 content::NotificationService::current()->Notify( |
| 805 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, | 637 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, |
| 806 content::Source<Profile>(profile_), | 638 content::Source<Profile>(profile_), |
| 807 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); | 639 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); |
| 808 | 640 |
| 809 password_.clear(); // Don't need it anymore. | 641 password_.clear(); // Don't need it anymore. |
| 810 DisableOneClickSignIn(profile_); // Don't ever offer again. | 642 DisableOneClickSignIn(profile_); // Don't ever offer again. |
| 811 | 643 |
| 812 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 644 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 843 | 675 |
| 844 void SigninManager::OnUbertokenFailure(const GoogleServiceAuthError& error) { | 676 void SigninManager::OnUbertokenFailure(const GoogleServiceAuthError& error) { |
| 845 LOG(WARNING) << " Unable to login the user to the web: " << error.ToString(); | 677 LOG(WARNING) << " Unable to login the user to the web: " << error.ToString(); |
| 846 ubertoken_fetcher_.reset(); | 678 ubertoken_fetcher_.reset(); |
| 847 } | 679 } |
| 848 | 680 |
| 849 void SigninManager::Observe(int type, | 681 void SigninManager::Observe(int type, |
| 850 const content::NotificationSource& source, | 682 const content::NotificationSource& source, |
| 851 const content::NotificationDetails& details) { | 683 const content::NotificationDetails& details) { |
| 852 switch (type) { | 684 switch (type) { |
| 853 #if !defined(OS_CHROMEOS) | |
| 854 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { | 685 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { |
| 855 TokenService::TokenAvailableDetails* tok_details = | 686 TokenService::TokenAvailableDetails* tok_details = |
| 856 content::Details<TokenService::TokenAvailableDetails>( | 687 content::Details<TokenService::TokenAvailableDetails>( |
| 857 details).ptr(); | 688 details).ptr(); |
| 858 | 689 |
| 859 // If a GAIA service token has become available, use it to pre-login the | 690 // If a GAIA service token has become available, use it to pre-login the |
| 860 // user to other services that depend on GAIA credentials. | 691 // user to other services that depend on GAIA credentials. |
| 861 if (tok_details->service() == | 692 if (tok_details->service() == |
| 862 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { | 693 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { |
| 863 ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this)); | 694 ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this)); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 875 // if this was from the current signin process. | 706 // if this was from the current signin process. |
| 876 registrar_.Remove(this, | 707 registrar_.Remove(this, |
| 877 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 708 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| 878 source); | 709 source); |
| 879 if (signin_process_id_ == | 710 if (signin_process_id_ == |
| 880 content::Source<content::RenderProcessHost>(source)->GetID()) { | 711 content::Source<content::RenderProcessHost>(source)->GetID()) { |
| 881 signin_process_id_ = kInvalidProcessId; | 712 signin_process_id_ = kInvalidProcessId; |
| 882 } | 713 } |
| 883 break; | 714 break; |
| 884 } | 715 } |
| 885 #endif | |
| 886 default: | 716 default: |
| 887 NOTREACHED(); | 717 NOTREACHED(); |
| 888 } | 718 } |
| 889 } | 719 } |
| 890 | 720 |
| 891 void SigninManager::Shutdown() { | |
| 892 if (signin_global_error_.get()) { | |
| 893 GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError( | |
| 894 signin_global_error_.get()); | |
| 895 signin_global_error_.reset(); | |
| 896 } | |
| 897 } | |
| 898 | |
| 899 void SigninManager::ProhibitSignout() { | 721 void SigninManager::ProhibitSignout() { |
| 900 prohibit_signout_ = true; | 722 prohibit_signout_ = true; |
| 901 } | 723 } |
| 902 | 724 |
| 903 bool SigninManager::IsSignoutProhibited() const { | 725 bool SigninManager::IsSignoutProhibited() const { |
| 904 return prohibit_signout_; | 726 return prohibit_signout_; |
| 905 } | 727 } |
| 906 | |
| 907 void SigninManager::OnGoogleServicesUsernamePatternChanged() { | |
| 908 if (!authenticated_username_.empty() && | |
| 909 !IsAllowedUsername(authenticated_username_)) { | |
| 910 // Signed in user is invalid according to the current policy so sign | |
| 911 // the user out. | |
| 912 SignOut(); | |
| 913 } | |
| 914 } | |
| 915 | |
| 916 void SigninManager::OnSigninAllowedPrefChanged() { | |
| 917 if (!IsSigninAllowed()) | |
| 918 SignOut(); | |
| 919 } | |
| 920 | |
| 921 void SigninManager::AddSigninDiagnosticsObserver( | |
| 922 SigninDiagnosticsObserver* observer) { | |
| 923 signin_diagnostics_observers_.AddObserver(observer); | |
| 924 } | |
| 925 | |
| 926 void SigninManager::RemoveSigninDiagnosticsObserver( | |
| 927 SigninDiagnosticsObserver* observer) { | |
| 928 signin_diagnostics_observers_.RemoveObserver(observer); | |
| 929 } | |
| 930 | |
| 931 void SigninManager::NotifyDiagnosticsObservers( | |
| 932 const UntimedSigninStatusField& field, | |
| 933 const std::string& value) { | |
| 934 FOR_EACH_OBSERVER(SigninDiagnosticsObserver, | |
| 935 signin_diagnostics_observers_, | |
| 936 NotifySigninValueChanged(field, value)); | |
| 937 } | |
| 938 | |
| 939 void SigninManager::NotifyDiagnosticsObservers( | |
| 940 const TimedSigninStatusField& field, | |
| 941 const std::string& value) { | |
| 942 FOR_EACH_OBSERVER(SigninDiagnosticsObserver, | |
| 943 signin_diagnostics_observers_, | |
| 944 NotifySigninValueChanged(field, value)); | |
| 945 } | |
| OLD | NEW |