1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h" 6 7 #include <utility> 8 #include <vector> 9 10 #include "base/command_line.h" 11 #include "base/metrics/histogram.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/strings/string_util.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/signin/chrome_signin_client_factory.h" 17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 18 #include "chrome/browser/signin/signin_manager_factory.h" 19 #include "chrome/common/chrome_switches.h" 20 #include "chromeos/chromeos_switches.h" 21 #include "components/signin/core/browser/profile_oauth2_token_service.h" 22 #include "components/signin/core/browser/signin_client.h" 23 #include "components/signin/core/browser/signin_manager.h" 24 #include "components/user_manager/user_manager.h" 25 #include "google_apis/gaia/gaia_auth_util.h" 26 #include "google_apis/gaia/gaia_constants.h" 27 #include "google_apis/gaia/gaia_urls.h" 28 #include "net/url_request/url_request_context_getter.h" 29 30 namespace chromeos { 31 32 namespace { 33 34 static const char kServiceScopeGetUserInfo[] = 35 "https://www.googleapis.com/auth/userinfo.email"; 36 static const int kMaxRetries = 5; 37 38 } // namespace 39 40 OAuth2LoginManager::OAuth2LoginManager(Profile* user_profile) 41 : user_profile_(user_profile), 42 restore_strategy_(RESTORE_FROM_COOKIE_JAR), 43 state_(SESSION_RESTORE_NOT_STARTED) { 44 GetTokenService()->AddObserver(this); 45 46 // For telemetry, we mark session restore completed to avoid warnings from 47 // MergeSessionThrottle. 48 if (CommandLine::ForCurrentProcess()-> 49 HasSwitch(chromeos::switches::kDisableGaiaServices)) { 50 SetSessionRestoreState(SESSION_RESTORE_DONE); 51 } 52 } 53 54 OAuth2LoginManager::~OAuth2LoginManager() { 55 } 56 57 void OAuth2LoginManager::AddObserver(OAuth2LoginManager::Observer* observer) { 58 observer_list_.AddObserver(observer); 59 } 60 61 void OAuth2LoginManager::RemoveObserver( 62 OAuth2LoginManager::Observer* observer) { 63 observer_list_.RemoveObserver(observer); 64 } 65 66 void OAuth2LoginManager::RestoreSession( 67 net::URLRequestContextGetter* auth_request_context, 68 SessionRestoreStrategy restore_strategy, 69 const std::string& oauth2_refresh_token, 70 const std::string& auth_code) { 71 DCHECK(user_profile_); 72 auth_request_context_ = auth_request_context; 73 restore_strategy_ = restore_strategy; 74 refresh_token_ = oauth2_refresh_token; 75 oauthlogin_access_token_ = std::string(); 76 auth_code_ = auth_code; 77 session_restore_start_ = base::Time::Now(); 78 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_PREPARING); 79 ContinueSessionRestore(); 80 } 81 82 void OAuth2LoginManager::ContinueSessionRestore() { 83 if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR || 84 restore_strategy_ == RESTORE_FROM_AUTH_CODE) { 85 FetchOAuth2Tokens(); 86 return; 87 } 88 89 // Save passed OAuth2 refresh token. 90 if (restore_strategy_ == RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN) { 91 DCHECK(!refresh_token_.empty()); 92 restore_strategy_ = RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN; 93 StoreOAuth2Token(); 94 return; 95 } 96 97 DCHECK(restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN); 98 RestoreSessionFromSavedTokens(); 99 } 100 101 void OAuth2LoginManager::RestoreSessionFromSavedTokens() { 102 ProfileOAuth2TokenService* token_service = GetTokenService(); 103 const std::string& primary_account_id = GetPrimaryAccountId(); 104 if (token_service->RefreshTokenIsAvailable(primary_account_id)) { 105 VLOG(1) << "OAuth2 refresh token is already loaded."; 106 VerifySessionCookies(); 107 } else { 108 VLOG(1) << "Loading OAuth2 refresh token from database."; 109 110 // Flag user with unknown token status in case there are no saved tokens 111 // and OnRefreshTokenAvailable is not called. Flagging it here would 112 // cause user to go through Gaia in next login to obtain a new refresh 113 // token. 114 user_manager::UserManager::Get()->SaveUserOAuthStatus( 115 primary_account_id, user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN); 116 117 token_service->LoadCredentials(primary_account_id); 118 } 119 } 120 121 void OAuth2LoginManager::Stop() { 122 oauth2_token_fetcher_.reset(); 123 login_verifier_.reset(); 124 } 125 126 bool OAuth2LoginManager::ShouldBlockTabLoading() { 127 return state_ == SESSION_RESTORE_PREPARING || 128 state_ == SESSION_RESTORE_IN_PROGRESS; 129 } 130 131 void OAuth2LoginManager::OnRefreshTokenAvailable( 132 const std::string& account_id) { 133 VLOG(1) << "OnRefreshTokenAvailable"; 134 135 if (state_ == SESSION_RESTORE_NOT_STARTED) 136 return; 137 138 // TODO(fgorski): Once ProfileOAuth2TokenService supports multi-login, make 139 // sure to restore session cookies in the context of the correct account_id. 140 141 // Do not validate tokens for supervised users, as they don't actually have 142 // oauth2 token. 143 if (user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser()) { 144 VLOG(1) << "Logged in as supervised user, skip token validation."; 145 return; 146 } 147 // Only restore session cookies for the primary account in the profile. 148 if (GetPrimaryAccountId() == account_id) { 149 // Token is loaded. Undo the flagging before token loading. 150 user_manager::UserManager::Get()->SaveUserOAuthStatus( 151 account_id, user_manager::User::OAUTH2_TOKEN_STATUS_VALID); 152 VerifySessionCookies(); 153 } 154 } 155 156 ProfileOAuth2TokenService* OAuth2LoginManager::GetTokenService() { 157 return ProfileOAuth2TokenServiceFactory::GetForProfile(user_profile_); 158 } 159 160 const std::string& OAuth2LoginManager::GetPrimaryAccountId() { 161 SigninManagerBase* signin_manager = 162 SigninManagerFactory::GetForProfile(user_profile_); 163 return signin_manager->GetAuthenticatedAccountId(); 164 } 165 166 void OAuth2LoginManager::StoreOAuth2Token() { 167 const std::string& primary_account_id = GetPrimaryAccountId(); 168 if (primary_account_id.empty()) { 169 GetAccountIdOfRefreshToken(refresh_token_); 170 return; 171 } 172 173 OnGetUserEmailResponse(primary_account_id); 174 } 175 176 void OAuth2LoginManager::GetAccountIdOfRefreshToken( 177 const std::string& refresh_token) { 178 gaia::OAuthClientInfo client_info; 179 GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); 180 client_info.client_id = gaia_urls->oauth2_chrome_client_id(); 181 client_info.client_secret = gaia_urls->oauth2_chrome_client_secret(); 182 183 account_id_fetcher_.reset(new gaia::GaiaOAuthClient( 184 auth_request_context_.get())); 185 account_id_fetcher_->RefreshToken(client_info, refresh_token, 186 std::vector<std::string>(1, kServiceScopeGetUserInfo), kMaxRetries, 187 this); 188 } 189 190 void OAuth2LoginManager::OnRefreshTokenResponse( 191 const std::string& access_token, 192 int expires_in_seconds) { 193 account_id_fetcher_->GetUserEmail(access_token, kMaxRetries, this); 194 } 195 196 void OAuth2LoginManager::OnGetUserEmailResponse( 197 const std::string& user_email) { 198 DCHECK(!refresh_token_.empty()); 199 account_id_fetcher_.reset(); 200 std::string canonicalized = gaia::CanonicalizeEmail(user_email); 201 GetTokenService()->UpdateCredentials(canonicalized, refresh_token_); 202 203 FOR_EACH_OBSERVER(Observer, observer_list_, 204 OnNewRefreshTokenAvaiable(user_profile_)); 205 } 206 207 void OAuth2LoginManager::OnOAuthError() { 208 account_id_fetcher_.reset(); 209 LOG(ERROR) << "Account id fetch failed!"; 210 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED); 211 } 212 213 void OAuth2LoginManager::OnNetworkError(int response_code) { 214 account_id_fetcher_.reset(); 215 LOG(ERROR) << "Account id fetch failed! response_code=" << response_code; 216 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED); 217 } 218 219 void OAuth2LoginManager::FetchOAuth2Tokens() { 220 DCHECK(auth_request_context_.get()); 221 // If we have authenticated cookie jar, get OAuth1 token first, then fetch 222 // SID/LSID cookies through OAuthLogin call. 223 if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR) { 224 SigninClient* signin_client = 225 ChromeSigninClientFactory::GetForProfile(user_profile_); 226 std::string signin_scoped_device_id = 227 signin_client->GetSigninScopedDeviceId(); 228 229 oauth2_token_fetcher_.reset( 230 new OAuth2TokenFetcher(this, auth_request_context_.get())); 231 oauth2_token_fetcher_->StartExchangeFromCookies(std::string(), 232 signin_scoped_device_id); 233 } else if (restore_strategy_ == RESTORE_FROM_AUTH_CODE) { 234 DCHECK(!auth_code_.empty()); 235 oauth2_token_fetcher_.reset( 236 new OAuth2TokenFetcher(this, 237 g_browser_process->system_request_context())); 238 oauth2_token_fetcher_->StartExchangeFromAuthCode(auth_code_); 239 } else { 240 NOTREACHED(); 241 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED); 242 } 243 } 244 245 void OAuth2LoginManager::OnOAuth2TokensAvailable( 246 const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) { 247 VLOG(1) << "OAuth2 tokens fetched"; 248 DCHECK(refresh_token_.empty()); 249 refresh_token_.assign(oauth2_tokens.refresh_token); 250 oauthlogin_access_token_ = oauth2_tokens.access_token; 251 StoreOAuth2Token(); 252 } 253 254 void OAuth2LoginManager::OnOAuth2TokensFetchFailed() { 255 LOG(ERROR) << "OAuth2 tokens fetch failed!"; 256 RecordSessionRestoreOutcome(SESSION_RESTORE_TOKEN_FETCH_FAILED, 257 SESSION_RESTORE_FAILED); 258 } 259 260 void OAuth2LoginManager::VerifySessionCookies() { 261 DCHECK(!login_verifier_.get()); 262 login_verifier_.reset( 263 new OAuth2LoginVerifier(this, 264 g_browser_process->system_request_context(), 265 user_profile_->GetRequestContext(), 266 oauthlogin_access_token_)); 267 268 if (restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN) { 269 login_verifier_->VerifyUserCookies(user_profile_); 270 return; 271 } 272 273 RestoreSessionCookies(); 274 } 275 276 void OAuth2LoginManager::RestoreSessionCookies() { 277 SetSessionRestoreState(SESSION_RESTORE_IN_PROGRESS); 278 login_verifier_->VerifyProfileTokens(user_profile_); 279 } 280 281 void OAuth2LoginManager::Shutdown() { 282 GetTokenService()->RemoveObserver(this); 283 login_verifier_.reset(); 284 oauth2_token_fetcher_.reset(); 285 } 286 287 void OAuth2LoginManager::OnSessionMergeSuccess() { 288 VLOG(1) << "OAuth2 refresh and/or GAIA token verification succeeded."; 289 RecordSessionRestoreOutcome(SESSION_RESTORE_SUCCESS, 290 SESSION_RESTORE_DONE); 291 } 292 293 void OAuth2LoginManager::OnSessionMergeFailure(bool connection_error) { 294 LOG(ERROR) << "OAuth2 refresh and GAIA token verification failed!" 295 << " connection_error: " << connection_error; 296 RecordSessionRestoreOutcome(SESSION_RESTORE_MERGE_SESSION_FAILED, 297 connection_error ? 298 SESSION_RESTORE_CONNECTION_FAILED : 299 SESSION_RESTORE_FAILED); 300 } 301 302 void OAuth2LoginManager::OnListAccountsSuccess(const std::string& data) { 303 MergeVerificationOutcome outcome = POST_MERGE_SUCCESS; 304 // Let's analyze which accounts we see logged in here: 305 std::vector<std::pair<std::string, bool> > accounts; 306 gaia::ParseListAccountsData(data, &accounts); 307 std::string user_email = gaia::CanonicalizeEmail(GetPrimaryAccountId()); 308 if (!accounts.empty()) { 309 bool found = false; 310 bool first = true; 311 for (std::vector<std::pair<std::string, bool> >::const_iterator iter = 312 accounts.begin(); 313 iter != accounts.end(); ++iter) { 314 if (gaia::CanonicalizeEmail(iter->first) == user_email) { 315 found = iter->second; 316 break; 317 } 318 319 first = false; 320 } 321 322 if (!found) 323 outcome = POST_MERGE_MISSING_PRIMARY_ACCOUNT; 324 else if (!first) 325 outcome = POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT; 326 327 } else { 328 outcome = POST_MERGE_NO_ACCOUNTS; 329 } 330 331 bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING); 332 RecordCookiesCheckOutcome(is_pre_merge, outcome); 333 // If the primary account is missing during the initial cookie freshness 334 // check, try to restore GAIA session cookies form the OAuth2 tokens. 335 if (is_pre_merge) { 336 if (outcome != POST_MERGE_SUCCESS && 337 outcome != POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT) { 338 RestoreSessionCookies(); 339 } else { 340 // We are done with this account, it's GAIA cookies are legit. 341 RecordSessionRestoreOutcome(SESSION_RESTORE_NOT_NEEDED, 342 SESSION_RESTORE_DONE); 343 } 344 } 345 } 346 347 void OAuth2LoginManager::OnListAccountsFailure(bool connection_error) { 348 bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING); 349 RecordCookiesCheckOutcome( 350 is_pre_merge, 351 connection_error ? POST_MERGE_CONNECTION_FAILED : 352 POST_MERGE_VERIFICATION_FAILED); 353 if (is_pre_merge) { 354 if (!connection_error) { 355 // If we failed to get account list, our cookies might be stale so we 356 // need to attempt to restore them. 357 RestoreSessionCookies(); 358 } else { 359 RecordSessionRestoreOutcome(SESSION_RESTORE_LISTACCOUNTS_FAILED, 360 SESSION_RESTORE_CONNECTION_FAILED); 361 } 362 } 363 } 364 365 void OAuth2LoginManager::RecordSessionRestoreOutcome( 366 SessionRestoreOutcome outcome, 367 OAuth2LoginManager::SessionRestoreState state) { 368 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore", 369 outcome, 370 SESSION_RESTORE_COUNT); 371 SetSessionRestoreState(state); 372 } 373 374 // static 375 void OAuth2LoginManager::RecordCookiesCheckOutcome( 376 bool is_pre_merge, 377 MergeVerificationOutcome outcome) { 378 if (is_pre_merge) { 379 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PreMergeVerification", 380 outcome, 381 POST_MERGE_COUNT); 382 } else { 383 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PostMergeVerification", 384 outcome, 385 POST_MERGE_COUNT); 386 } 387 } 388 389 void OAuth2LoginManager::SetSessionRestoreState( 390 OAuth2LoginManager::SessionRestoreState state) { 391 if (state_ == state) 392 return; 393 394 state_ = state; 395 if (state == OAuth2LoginManager::SESSION_RESTORE_FAILED) { 396 UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToFailure", 397 base::Time::Now() - session_restore_start_); 398 } else if (state == OAuth2LoginManager::SESSION_RESTORE_DONE) { 399 UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToSuccess", 400 base::Time::Now() - session_restore_start_); 401 } 402 403 FOR_EACH_OBSERVER(Observer, observer_list_, 404 OnSessionRestoreStateChanged(user_profile_, state_)); 405 } 406 407 void OAuth2LoginManager::SetSessionRestoreStartForTesting( 408 const base::Time& time) { 409 session_restore_start_ = time; 410 } 411 412 } // namespace chromeos 413