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