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: |
| 302 return "Signin with credentials"; | 155 return "Signin with credentials"; |
| 303 case SIGNIN_TYPE_CLIENT_OAUTH: | 156 case SIGNIN_TYPE_CLIENT_OAUTH: |
| 304 return "Client OAuth"; | 157 return "Client OAuth"; |
| 305 } | 158 } |
| 306 | 159 |
| 307 NOTREACHED(); | 160 NOTREACHED(); |
| 308 return ""; | 161 return ""; |
| 309 } | 162 } |
| 310 | 163 |
| 311 | |
| 312 bool SigninManager::PrepareForSignin(SigninType type, | 164 bool SigninManager::PrepareForSignin(SigninType type, |
| 313 const std::string& username, | 165 const std::string& username, |
| 314 const std::string& password) { | 166 const std::string& password) { |
| 315 DCHECK(possibly_invalid_username_.empty() || | 167 DCHECK(possibly_invalid_username_.empty() || |
| 316 possibly_invalid_username_ == username); | 168 possibly_invalid_username_ == username); |
| 317 DCHECK(!username.empty()); | 169 DCHECK(!username.empty()); |
| 318 | 170 |
| 319 if (!IsAllowedUsername(username)) { | 171 if (!IsAllowedUsername(username)) { |
| 320 // Account is not allowed by admin policy. | 172 // Account is not allowed by admin policy. |
| 321 HandleAuthError(GoogleServiceAuthError( | 173 HandleAuthError(GoogleServiceAuthError( |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 339 | 191 |
| 340 NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); | 192 NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); |
| 341 return true; | 193 return true; |
| 342 } | 194 } |
| 343 | 195 |
| 344 // Users must always sign out before they sign in again. | 196 // Users must always sign out before they sign in again. |
| 345 void SigninManager::StartSignIn(const std::string& username, | 197 void SigninManager::StartSignIn(const std::string& username, |
| 346 const std::string& password, | 198 const std::string& password, |
| 347 const std::string& login_token, | 199 const std::string& login_token, |
| 348 const std::string& login_captcha) { | 200 const std::string& login_captcha) { |
| 349 DCHECK(authenticated_username_.empty() || | 201 DCHECK(GetAuthenticatedUsername().empty() || |
| 350 gaia::AreEmailsSame(username, authenticated_username_)); | 202 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| 351 | 203 |
| 352 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_LOGIN, username, password)) | 204 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_LOGIN, username, password)) |
| 353 return; | 205 return; |
| 354 | 206 |
| 355 client_login_->StartClientLogin(username, | 207 client_login_->StartClientLogin(username, |
| 356 password, | 208 password, |
| 357 "", | 209 "", |
| 358 login_token, | 210 login_token, |
| 359 login_captcha, | 211 login_captcha, |
| 360 GaiaAuthFetcher::HostedAccountsNotAllowed); | 212 GaiaAuthFetcher::HostedAccountsNotAllowed); |
| 361 | 213 |
| 362 // Register for token availability. The signin manager will pre-login the | 214 // 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 | 215 // 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_)) { | 216 if (AreSigninCookiesAllowed(profile_)) { |
| 368 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 217 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 369 registrar_.Add(this, | 218 registrar_.Add(this, |
| 370 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 219 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 371 content::Source<TokenService>(token_service)); | 220 content::Source<TokenService>(token_service)); |
| 372 } | 221 } |
| 373 #endif | |
| 374 } | 222 } |
| 375 | 223 |
| 376 void SigninManager::ProvideSecondFactorAccessCode( | 224 void SigninManager::ProvideSecondFactorAccessCode( |
| 377 const std::string& access_code) { | 225 const std::string& access_code) { |
| 378 DCHECK(!possibly_invalid_username_.empty() && !password_.empty() && | 226 DCHECK(!possibly_invalid_username_.empty() && !password_.empty() && |
| 379 last_result_.data.empty()); | 227 last_result_.data.empty()); |
| 380 DCHECK(type_ == SIGNIN_TYPE_CLIENT_LOGIN); | 228 DCHECK(type_ == SIGNIN_TYPE_CLIENT_LOGIN); |
| 381 | 229 |
| 382 client_login_.reset(new GaiaAuthFetcher(this, | 230 client_login_.reset(new GaiaAuthFetcher(this, |
| 383 GaiaConstants::kChromeSource, | 231 GaiaConstants::kChromeSource, |
| 384 profile_->GetRequestContext())); | 232 profile_->GetRequestContext())); |
| 385 client_login_->StartClientLogin(possibly_invalid_username_, | 233 client_login_->StartClientLogin(possibly_invalid_username_, |
| 386 access_code, | 234 access_code, |
| 387 "", | 235 "", |
| 388 std::string(), | 236 std::string(), |
| 389 std::string(), | 237 std::string(), |
| 390 GaiaAuthFetcher::HostedAccountsNotAllowed); | 238 GaiaAuthFetcher::HostedAccountsNotAllowed); |
| 391 } | 239 } |
| 392 | 240 |
| 393 void SigninManager::StartSignInWithCredentials(const std::string& session_index, | 241 void SigninManager::StartSignInWithCredentials(const std::string& session_index, |
| 394 const std::string& username, | 242 const std::string& username, |
| 395 const std::string& password) { | 243 const std::string& password) { |
| 396 DCHECK(authenticated_username_.empty() || | 244 DCHECK(GetAuthenticatedUsername().empty() || |
| 397 gaia::AreEmailsSame(username, authenticated_username_)); | 245 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| 398 | 246 |
| 399 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) | 247 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) |
| 400 return; | 248 return; |
| 401 | 249 |
| 402 if (password.empty()) { | 250 if (password.empty()) { |
| 403 // Chrome must verify the GAIA cookies first if auto sign-in is triggered | 251 // 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 | 252 // with no password provided. This is to protect Chrome against forged |
| 405 // GAIA cookies from a super-domain. | 253 // GAIA cookies from a super-domain. |
| 406 VerifyGaiaCookiesBeforeSignIn(session_index); | 254 VerifyGaiaCookiesBeforeSignIn(session_index); |
| 407 } else { | 255 } else { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 if (success) { | 299 if (success) { |
| 452 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); | 300 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); |
| 453 } else { | 301 } else { |
| 454 HandleAuthError(GoogleServiceAuthError( | 302 HandleAuthError(GoogleServiceAuthError( |
| 455 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); | 303 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); |
| 456 } | 304 } |
| 457 } | 305 } |
| 458 | 306 |
| 459 void SigninManager::StartSignInWithOAuth(const std::string& username, | 307 void SigninManager::StartSignInWithOAuth(const std::string& username, |
| 460 const std::string& password) { | 308 const std::string& password) { |
| 461 DCHECK(authenticated_username_.empty()); | 309 DCHECK(GetAuthenticatedUsername().empty()); |
| 462 | 310 |
| 463 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_OAUTH, username, password)) | 311 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_OAUTH, username, password)) |
| 464 return; | 312 return; |
| 465 | 313 |
| 466 std::vector<std::string> scopes; | 314 std::vector<std::string> scopes; |
| 467 scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope()); | 315 scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope()); |
| 468 const std::string& locale = g_browser_process->GetApplicationLocale(); | 316 const std::string& locale = g_browser_process->GetApplicationLocale(); |
| 469 | 317 |
| 470 client_login_->StartClientOAuth(username, password, scopes, "", locale); | 318 client_login_->StartClientOAuth(username, password, scopes, "", locale); |
| 471 | 319 |
| 472 // Register for token availability. The signin manager will pre-login the | 320 // 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 | 321 // 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_)) { | 322 if (AreSigninCookiesAllowed(profile_)) { |
| 478 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 323 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 479 registrar_.Add(this, | 324 registrar_.Add(this, |
| 480 chrome::NOTIFICATION_TOKEN_AVAILABLE, | 325 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 481 content::Source<TokenService>(token_service)); | 326 content::Source<TokenService>(token_service)); |
| 482 } | 327 } |
| 483 #endif | |
| 484 } | 328 } |
| 485 | 329 |
| 486 void SigninManager::ProvideOAuthChallengeResponse( | 330 void SigninManager::ProvideOAuthChallengeResponse( |
| 487 GoogleServiceAuthError::State type, | 331 GoogleServiceAuthError::State type, |
| 488 const std::string& token, | 332 const std::string& token, |
| 489 const std::string& solution) { | 333 const std::string& solution) { |
| 490 DCHECK(!possibly_invalid_username_.empty() && !password_.empty()); | 334 DCHECK(!possibly_invalid_username_.empty() && !password_.empty()); |
| 491 DCHECK(type_ == SIGNIN_TYPE_CLIENT_OAUTH); | 335 DCHECK(type_ == SIGNIN_TYPE_CLIENT_OAUTH); |
| 492 | 336 |
| 493 client_login_.reset(new GaiaAuthFetcher(this, | 337 client_login_.reset(new GaiaAuthFetcher(this, |
| 494 GaiaConstants::kChromeSource, | 338 GaiaConstants::kChromeSource, |
| 495 profile_->GetRequestContext())); | 339 profile_->GetRequestContext())); |
| 496 client_login_->StartClientOAuthChallengeResponse(type, token, solution); | 340 client_login_->StartClientOAuthChallengeResponse(type, token, solution); |
| 497 } | 341 } |
| 498 | 342 |
| 499 void SigninManager::ClearTransientSigninData() { | 343 void SigninManager::ClearTransientSigninData() { |
| 500 DCHECK(IsInitialized()); | 344 DCHECK(IsInitialized()); |
| 501 | 345 |
| 502 CleanupNotificationRegistration(); | 346 CleanupNotificationRegistration(); |
| 503 client_login_.reset(); | 347 client_login_.reset(); |
| 504 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 348 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 505 policy_client_.reset(); | 349 policy_client_.reset(); |
| 506 #endif | 350 #endif |
| 507 last_result_ = ClientLoginResult(); | 351 last_result_ = ClientLoginResult(); |
| 508 possibly_invalid_username_.clear(); | 352 possibly_invalid_username_.clear(); |
| 509 password_.clear(); | 353 password_.clear(); |
| 510 had_two_factor_error_ = false; | 354 had_two_factor_error_ = false; |
| 511 type_ = SIGNIN_TYPE_NONE; | 355 type_ = SIGNIN_TYPE_NONE; |
| 512 temp_oauth_login_tokens_ = ClientOAuthResult(); | 356 temp_oauth_login_tokens_ = ClientOAuthResult(); |
| 513 } | 357 } |
| 514 | 358 |
| 515 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, | 359 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, |
| 516 bool clear_transient_data) { | 360 bool clear_transient_data) { |
| 517 content::NotificationService::current()->Notify( | 361 content::NotificationService::current()->Notify( |
| 518 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, | 362 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, |
| 519 content::Source<Profile>(profile_), | 363 content::Source<Profile>(profile_), |
| 520 content::Details<const GoogleServiceAuthError>(&error)); | 364 content::Details<const GoogleServiceAuthError>(&error)); |
| 521 | 365 |
| 522 // In some cases, the user should not be signed out. For example, the failure | 366 // 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 | 367 // 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. | 368 // data must be kept to properly handle the follow up. |
| 525 if (clear_transient_data) | 369 if (clear_transient_data) |
| 526 ClearTransientSigninData(); | 370 ClearTransientSigninData(); |
| 527 } | 371 } |
| 528 | 372 |
| 373 bool SigninManager::ShouldSignOut() { | |
| 374 if (prohibit_signout_) | |
| 375 return false; | |
| 376 | |
| 377 // Exit if we aren't signed in (or in the process of signing in). | |
| 378 // This avoids a perf regression from clearing out the TokenDB if | |
| 379 // SignOut() is invoked on startup to clean up any incomplete previous | |
| 380 // signin attempts. | |
| 381 if (GetAuthenticatedUsername().empty() && !client_login_.get()) | |
| 382 return false; | |
| 383 | |
| 384 return true; | |
|
Roger Tawa OOO till Jul 10th
2013/04/05 20:53:57
call base class?
tim (not reviewing)
2013/04/05 22:14:12
We don't want to do that. This method replaces th
| |
| 385 } | |
| 386 | |
| 529 void SigninManager::SignOut() { | 387 void SigninManager::SignOut() { |
| 530 DCHECK(IsInitialized()); | 388 DCHECK(IsInitialized()); |
| 531 if (prohibit_signout_) { | 389 if (prohibit_signout_) { |
| 532 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; | 390 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; |
| 533 return; | 391 return; |
| 534 } | 392 } |
| 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 | 393 |
| 546 ClearTransientSigninData(); | 394 ClearTransientSigninData(); |
| 547 authenticated_username_.clear(); | 395 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 } | 396 } |
| 564 | 397 |
| 565 bool SigninManager::AuthInProgress() const { | 398 bool SigninManager::AuthInProgress() const { |
| 566 return !possibly_invalid_username_.empty(); | 399 return !possibly_invalid_username_.empty(); |
| 567 } | 400 } |
| 568 | 401 |
| 569 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { | 402 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { |
| 570 DCHECK(key == kGetInfoDisplayEmailKey || key == kGetInfoEmailKey); | 403 DCHECK(key == kGetInfoDisplayEmailKey || key == kGetInfoEmailKey); |
| 571 LOG(ERROR) << "Account is not associated with a valid email address. " | 404 LOG(ERROR) << "Account is not associated with a valid email address. " |
| 572 << "Login failed."; | 405 << "Login failed."; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 664 // expected, return an error. | 497 // expected, return an error. |
| 665 if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && | 498 if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && |
| 666 !gaia::AreEmailsSame(display_email_iter->second, | 499 !gaia::AreEmailsSame(display_email_iter->second, |
| 667 possibly_invalid_username_)) { | 500 possibly_invalid_username_)) { |
| 668 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); | 501 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); |
| 669 return; | 502 return; |
| 670 } | 503 } |
| 671 | 504 |
| 672 possibly_invalid_username_ = email_iter->second; | 505 possibly_invalid_username_ = email_iter->second; |
| 673 | 506 |
| 674 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 507 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 675 // TODO(atwilson): Move this code out to OneClickSignin instead of having | 508 // TODO(atwilson): Move this code out to OneClickSignin instead of having |
| 676 // it embedded in SigninManager - we don't want UI logic in SigninManager. | 509 // 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 | 510 // 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 | 511 // 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 | 512 // 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 | 513 // old ClientLogin flow) then policy will get loaded once the TokenService |
| 681 // finishes initializing (not ideal, but it's a reasonable fallback). | 514 // finishes initializing (not ideal, but it's a reasonable fallback). |
| 682 if (authenticated_username_.empty() && | 515 if (GetAuthenticatedUsername().empty() && |
| 683 !temp_oauth_login_tokens_.refresh_token.empty()) { | 516 !temp_oauth_login_tokens_.refresh_token.empty()) { |
| 684 policy::UserPolicySigninService* policy_service = | 517 policy::UserPolicySigninService* policy_service = |
| 685 policy::UserPolicySigninServiceFactory::GetForProfile(profile_); | 518 policy::UserPolicySigninServiceFactory::GetForProfile(profile_); |
| 686 policy_service->RegisterPolicyClient( | 519 policy_service->RegisterPolicyClient( |
| 687 possibly_invalid_username_, | 520 possibly_invalid_username_, |
| 688 temp_oauth_login_tokens_.refresh_token, | 521 temp_oauth_login_tokens_.refresh_token, |
| 689 base::Bind(&SigninManager::OnRegisteredForPolicy, | 522 base::Bind(&SigninManager::OnRegisteredForPolicy, |
| 690 weak_pointer_factory_.GetWeakPtr())); | 523 weak_pointer_factory_.GetWeakPtr())); |
| 691 return; | 524 return; |
| 692 } | 525 } |
| 693 #endif | 526 #endif |
| 694 | 527 |
| 695 // Not waiting for policy load - just complete signin directly. | 528 // Not waiting for policy load - just complete signin directly. |
| 696 CompleteSigninAfterPolicyLoad(); | 529 CompleteSigninAfterPolicyLoad(); |
| 697 } | 530 } |
| 698 | 531 |
| 699 #if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) | 532 #if defined(ENABLE_CONFIGURATION_POLICY) |
| 700 void SigninManager::OnRegisteredForPolicy( | 533 void SigninManager::OnRegisteredForPolicy( |
| 701 scoped_ptr<policy::CloudPolicyClient> client) { | 534 scoped_ptr<policy::CloudPolicyClient> client) { |
| 702 // If there's no token for the user (no policy) just finish signing in. | 535 // If there's no token for the user (no policy) just finish signing in. |
| 703 if (!client.get()) { | 536 if (!client.get()) { |
| 704 DVLOG(1) << "Policy registration failed"; | 537 DVLOG(1) << "Policy registration failed"; |
| 705 CompleteSigninAfterPolicyLoad(); | 538 CompleteSigninAfterPolicyLoad(); |
| 706 return; | 539 return; |
| 707 } | 540 } |
| 708 | 541 |
| 709 // Stash away a copy of our CloudPolicyClient (should not already have one). | 542 // 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(); | 623 SignOut(); |
| 791 } | 624 } |
| 792 } | 625 } |
| 793 #endif | 626 #endif |
| 794 | 627 |
| 795 void SigninManager::CompleteSigninAfterPolicyLoad() { | 628 void SigninManager::CompleteSigninAfterPolicyLoad() { |
| 796 DCHECK(!possibly_invalid_username_.empty()); | 629 DCHECK(!possibly_invalid_username_.empty()); |
| 797 SetAuthenticatedUsername(possibly_invalid_username_); | 630 SetAuthenticatedUsername(possibly_invalid_username_); |
| 798 possibly_invalid_username_.clear(); | 631 possibly_invalid_username_.clear(); |
| 799 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, | 632 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, |
| 800 authenticated_username_); | 633 GetAuthenticatedUsername()); |
| 801 | 634 |
| 802 GoogleServiceSigninSuccessDetails details(authenticated_username_, | 635 GoogleServiceSigninSuccessDetails details(GetAuthenticatedUsername(), |
| 803 password_); | 636 password_); |
| 804 content::NotificationService::current()->Notify( | 637 content::NotificationService::current()->Notify( |
| 805 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, | 638 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, |
| 806 content::Source<Profile>(profile_), | 639 content::Source<Profile>(profile_), |
| 807 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); | 640 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); |
| 808 | 641 |
| 809 password_.clear(); // Don't need it anymore. | 642 password_.clear(); // Don't need it anymore. |
| 810 DisableOneClickSignIn(profile_); // Don't ever offer again. | 643 DisableOneClickSignIn(profile_); // Don't ever offer again. |
| 811 | 644 |
| 812 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 645 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 843 | 676 |
| 844 void SigninManager::OnUbertokenFailure(const GoogleServiceAuthError& error) { | 677 void SigninManager::OnUbertokenFailure(const GoogleServiceAuthError& error) { |
| 845 LOG(WARNING) << " Unable to login the user to the web: " << error.ToString(); | 678 LOG(WARNING) << " Unable to login the user to the web: " << error.ToString(); |
| 846 ubertoken_fetcher_.reset(); | 679 ubertoken_fetcher_.reset(); |
| 847 } | 680 } |
| 848 | 681 |
| 849 void SigninManager::Observe(int type, | 682 void SigninManager::Observe(int type, |
| 850 const content::NotificationSource& source, | 683 const content::NotificationSource& source, |
| 851 const content::NotificationDetails& details) { | 684 const content::NotificationDetails& details) { |
| 852 switch (type) { | 685 switch (type) { |
| 853 #if !defined(OS_CHROMEOS) | |
| 854 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { | 686 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { |
| 855 TokenService::TokenAvailableDetails* tok_details = | 687 TokenService::TokenAvailableDetails* tok_details = |
| 856 content::Details<TokenService::TokenAvailableDetails>( | 688 content::Details<TokenService::TokenAvailableDetails>( |
| 857 details).ptr(); | 689 details).ptr(); |
| 858 | 690 |
| 859 // If a GAIA service token has become available, use it to pre-login the | 691 // If a GAIA service token has become available, use it to pre-login the |
| 860 // user to other services that depend on GAIA credentials. | 692 // user to other services that depend on GAIA credentials. |
| 861 if (tok_details->service() == | 693 if (tok_details->service() == |
| 862 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { | 694 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { |
| 863 ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this)); | 695 ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this)); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 875 // if this was from the current signin process. | 707 // if this was from the current signin process. |
| 876 registrar_.Remove(this, | 708 registrar_.Remove(this, |
| 877 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 709 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| 878 source); | 710 source); |
| 879 if (signin_process_id_ == | 711 if (signin_process_id_ == |
| 880 content::Source<content::RenderProcessHost>(source)->GetID()) { | 712 content::Source<content::RenderProcessHost>(source)->GetID()) { |
| 881 signin_process_id_ = kInvalidProcessId; | 713 signin_process_id_ = kInvalidProcessId; |
| 882 } | 714 } |
| 883 break; | 715 break; |
| 884 } | 716 } |
| 885 #endif | |
| 886 default: | 717 default: |
| 887 NOTREACHED(); | 718 NOTREACHED(); |
| 888 } | 719 } |
| 889 } | 720 } |
| 890 | 721 |
| 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() { | 722 void SigninManager::ProhibitSignout() { |
| 900 prohibit_signout_ = true; | 723 prohibit_signout_ = true; |
| 901 } | 724 } |
| 902 | 725 |
| 903 bool SigninManager::IsSignoutProhibited() const { | 726 bool SigninManager::IsSignoutProhibited() const { |
| 904 return prohibit_signout_; | 727 return prohibit_signout_; |
| 905 } | 728 } |
| 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 |