// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/oauth2_login_manager.h"

#include <vector>

#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chromeos/chromeos_switches.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/url_request/url_request_context_getter.h"

namespace chromeos {

namespace {

static const char kServiceScopeGetUserInfo[] =
    "https://www.googleapis.com/auth/userinfo.email";
static const int kMaxRetries = 5;

}  // namespace

OAuth2LoginManager::OAuth2LoginManager(Profile* user_profile)
    : user_profile_(user_profile),
      restore_strategy_(RESTORE_FROM_COOKIE_JAR),
      state_(SESSION_RESTORE_NOT_STARTED) {
  GetTokenService()->AddObserver(this);
  if (CommandLine::ForCurrentProcess()->
          HasSwitch(chromeos::switches::kOobeSkipPostLogin)) {
    // For telemetry we should mark session restore completed to avoid
    // warnings from MergeSessionThrottle.
    SetSessionRestoreState(SESSION_RESTORE_DONE);
  }
}

OAuth2LoginManager::~OAuth2LoginManager() {
}

void OAuth2LoginManager::AddObserver(OAuth2LoginManager::Observer* observer) {
  observer_list_.AddObserver(observer);
}

void OAuth2LoginManager::RemoveObserver(
    OAuth2LoginManager::Observer* observer) {
  observer_list_.RemoveObserver(observer);
}

void OAuth2LoginManager::RestoreSession(
    net::URLRequestContextGetter* auth_request_context,
    SessionRestoreStrategy restore_strategy,
    const std::string& oauth2_refresh_token,
    const std::string& auth_code) {
  DCHECK(user_profile_);
  auth_request_context_ = auth_request_context;
  restore_strategy_ = restore_strategy;
  refresh_token_ = oauth2_refresh_token;
  auth_code_ = auth_code;
  session_restore_start_ = base::Time::Now();
  SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_PREPARING);
  ContinueSessionRestore();
}

void OAuth2LoginManager::ContinueSessionRestore() {
  if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR ||
      restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
    FetchOAuth2Tokens();
    return;
  }

  // Save passed OAuth2 refresh token.
  if (restore_strategy_ == RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN) {
    DCHECK(!refresh_token_.empty());
    restore_strategy_ = RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN;
    StoreOAuth2Token();
    return;
  }

  DCHECK(restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN);
  RestoreSessionFromSavedTokens();
}

void OAuth2LoginManager::RestoreSessionFromSavedTokens() {
  ProfileOAuth2TokenService* token_service = GetTokenService();
  const std::string& primary_account_id = token_service->GetPrimaryAccountId();
  if (token_service->RefreshTokenIsAvailable(primary_account_id)) {
    LOG(WARNING) << "OAuth2 refresh token is already loaded.";
    RestoreSessionCookies();
  } else {
    LOG(WARNING) << "Loading OAuth2 refresh token from database.";

    // Flag user with invalid token status in case there are no saved tokens
    // and OnRefreshTokenAvailable is not called. Flagging it here would
    // cause user to go through Gaia in next login to obtain a new refresh
    // token.
    UserManager::Get()->SaveUserOAuthStatus(primary_account_id,
                                            User::OAUTH2_TOKEN_STATUS_INVALID);

    token_service->LoadCredentials();
  }
}

void OAuth2LoginManager::Stop() {
  oauth2_token_fetcher_.reset();
  login_verifier_.reset();
}

bool OAuth2LoginManager::ShouldBlockTabLoading() {
  return state_ == SESSION_RESTORE_PREPARING ||
         state_ == SESSION_RESTORE_IN_PROGRESS;
}

void OAuth2LoginManager::OnRefreshTokenAvailable(
    const std::string& account_id) {
  LOG(WARNING) << "OnRefreshTokenAvailable";

  if (state_ == SESSION_RESTORE_NOT_STARTED)
    return;

  // TODO(fgorski): Once ProfileOAuth2TokenService supports multi-login, make
  // sure to restore session cookies in the context of the correct account_id.

  // Do not validate tokens for supervised users, as they don't actually have
  // oauth2 token.
  if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
    LOG(WARNING) << "Logged in as managed user, skip token validation.";
    return;
  }
  // Do only restore session cookies if called for the primary user.
  if (GetTokenService()->GetPrimaryAccountId() == account_id)
    RestoreSessionCookies();
}

ProfileOAuth2TokenService* OAuth2LoginManager::GetTokenService() {
  ProfileOAuth2TokenService* token_service =
      ProfileOAuth2TokenServiceFactory::GetForProfile(user_profile_);
  return token_service;
}

void OAuth2LoginManager::StoreOAuth2Token() {
  ProfileOAuth2TokenService* token_service = GetTokenService();
  std::string primary_account_id = token_service->GetPrimaryAccountId();
  if (primary_account_id.empty()) {
    GetAccountIdOfRefreshToken(refresh_token_);
    return;
  }

  OnGetUserEmailResponse(primary_account_id);
}

void OAuth2LoginManager::GetAccountIdOfRefreshToken(
    const std::string& refresh_token) {
  gaia::OAuthClientInfo client_info;
  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
  client_info.client_id = gaia_urls->oauth2_chrome_client_id();
  client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();

  account_id_fetcher_.reset(new gaia::GaiaOAuthClient(
      auth_request_context_.get()));
  account_id_fetcher_->RefreshToken(client_info, refresh_token,
      std::vector<std::string>(1, kServiceScopeGetUserInfo), kMaxRetries,
      this);
}

void OAuth2LoginManager::OnRefreshTokenResponse(
    const std::string& access_token,
    int expires_in_seconds) {
  account_id_fetcher_->GetUserEmail(access_token, kMaxRetries, this);
}

void OAuth2LoginManager::OnGetUserEmailResponse(
    const std::string& user_email)  {
  DCHECK(!refresh_token_.empty());
  account_id_fetcher_.reset();
  std::string canonicalized = gaia::CanonicalizeEmail(user_email);
  GetTokenService()->UpdateCredentials(canonicalized, refresh_token_);

  FOR_EACH_OBSERVER(Observer, observer_list_,
                    OnNewRefreshTokenAvaiable(user_profile_));
}

void OAuth2LoginManager::OnOAuthError() {
  account_id_fetcher_.reset();
  LOG(ERROR) << "Account id fetch failed!";
  SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
}

void OAuth2LoginManager::OnNetworkError(int response_code) {
  account_id_fetcher_.reset();
  LOG(ERROR) << "Account id fetch failed! response_code=" << response_code;
  SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
}

void OAuth2LoginManager::FetchOAuth2Tokens() {
  DCHECK(auth_request_context_.get());
  // If we have authenticated cookie jar, get OAuth1 token first, then fetch
  // SID/LSID cookies through OAuthLogin call.
  if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR) {
    oauth2_token_fetcher_.reset(
        new OAuth2TokenFetcher(this, auth_request_context_.get()));
    oauth2_token_fetcher_->StartExchangeFromCookies();
  } else if (restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
    DCHECK(!auth_code_.empty());
    oauth2_token_fetcher_.reset(
        new OAuth2TokenFetcher(this,
                               g_browser_process->system_request_context()));
    oauth2_token_fetcher_->StartExchangeFromAuthCode(auth_code_);
  } else {
    NOTREACHED();
    SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
  }
}

void OAuth2LoginManager::OnOAuth2TokensAvailable(
    const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) {
  VLOG(1) << "OAuth2 tokens fetched";
  DCHECK(refresh_token_.empty());
  refresh_token_.assign(oauth2_tokens.refresh_token);
  StoreOAuth2Token();
}

void OAuth2LoginManager::OnOAuth2TokensFetchFailed() {
  LOG(ERROR) << "OAuth2 tokens fetch failed!";
  UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore",
                            SESSION_RESTORE_TOKEN_FETCH_FAILED,
                            SESSION_RESTORE_COUNT);
  SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
}

void OAuth2LoginManager::RestoreSessionCookies() {
  DCHECK(!login_verifier_.get());
  SetSessionRestoreState(SESSION_RESTORE_IN_PROGRESS);
  login_verifier_.reset(
      new OAuth2LoginVerifier(this,
                              g_browser_process->system_request_context(),
                              user_profile_->GetRequestContext()));
  login_verifier_->VerifyProfileTokens(user_profile_);
}

void OAuth2LoginManager::Shutdown() {
  GetTokenService()->RemoveObserver(this);
  login_verifier_.reset();
  oauth2_token_fetcher_.reset();
}

void OAuth2LoginManager::OnSessionMergeSuccess() {
  VLOG(1) << "OAuth2 refresh and/or GAIA token verification succeeded.";
  UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore",
                            SESSION_RESTORE_SUCCESS,
                            SESSION_RESTORE_COUNT);
  SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_DONE);
}

void OAuth2LoginManager::OnSessionMergeFailure(bool connection_error) {
  LOG(ERROR) << "OAuth2 refresh and GAIA token verification failed!"
             << " connection_error: " << connection_error;
  UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore",
                            SESSION_RESTORE_MERGE_SESSION_FAILED,
                            SESSION_RESTORE_COUNT);
  SetSessionRestoreState(connection_error ?
      OAuth2LoginManager::SESSION_RESTORE_CONNECTION_FAILED :
      OAuth2LoginManager::SESSION_RESTORE_FAILED);
}

void OAuth2LoginManager::OnListAccountsSuccess(const std::string& data) {
  PostMergeVerificationOutcome outcome = POST_MERGE_SUCCESS;
  // Let's analyze which accounts we see logged in here:
  std::vector<std::string> accounts = gaia::ParseListAccountsData(data);
  std::string user_email = gaia::CanonicalizeEmail(
      GetTokenService()->GetPrimaryAccountId());
  if (!accounts.empty()) {
    bool found = false;
    bool first = true;
    for (std::vector<std::string>::const_iterator iter = accounts.begin();
         iter != accounts.end(); ++iter) {
      if (gaia::CanonicalizeEmail(*iter) == user_email) {
        found = true;
        break;
      }

      first = false;
    }

    if (!found)
      outcome = POST_MERGE_MISSING_PRIMARY_ACCOUNT;
    else if (!first)
      outcome = POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT;

  } else {
    outcome = POST_MERGE_NO_ACCOUNTS;
  }

  RecordPostMergeOutcome(outcome);
}

void OAuth2LoginManager::OnListAccountsFailure(bool connection_error) {
  RecordPostMergeOutcome(connection_error ? POST_MERGE_CONNECTION_FAILED :
                                            POST_MERGE_VERIFICATION_FAILED);
}

// static
void OAuth2LoginManager::RecordPostMergeOutcome(
    PostMergeVerificationOutcome outcome) {
  UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PostMergeVerification",
                            outcome,
                            POST_MERGE_COUNT);
}


void OAuth2LoginManager::SetSessionRestoreState(
    OAuth2LoginManager::SessionRestoreState state) {
  if (state_ == state)
    return;

  state_ = state;
  if (state == OAuth2LoginManager::SESSION_RESTORE_FAILED) {
    UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToFailure",
                        base::Time::Now() - session_restore_start_);
  } else if (state == OAuth2LoginManager::SESSION_RESTORE_DONE) {
    UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToSuccess",
                        base::Time::Now() - session_restore_start_);
  }

  FOR_EACH_OBSERVER(Observer, observer_list_,
                    OnSessionRestoreStateChanged(user_profile_, state_));
}

void OAuth2LoginManager::SetSessionRestoreStartForTesting(
    const base::Time& time) {
  session_restore_start_ = time;
}

}  // namespace chromeos
