blob: 5cc92a4e39ae00bc92015fa55185dc3acb2b8f95 [file] [log] [blame]
// Copyright 2015 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/signin/token_handle_util.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/values.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "components/user_manager/known_user.h"
#include "google_apis/gaia/gaia_oauth_client.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace {
const char kTokenHandlePref[] = "PasswordTokenHandle";
const char kTokenHandleStatusPref[] = "TokenHandleStatus";
const char kHandleStatusValid[] = "valid";
const char kHandleStatusInvalid[] = "invalid";
const char* const kDefaultHandleStatus = kHandleStatusValid;
constexpr int kMaxRetries = 3;
} // namespace
TokenHandleUtil::TokenHandleUtil() : weak_factory_(this) {}
TokenHandleUtil::~TokenHandleUtil() {
weak_factory_.InvalidateWeakPtrs();
gaia_client_.reset();
}
bool TokenHandleUtil::HasToken(const AccountId& account_id) {
const base::DictionaryValue* dict = nullptr;
std::string token;
if (!user_manager::known_user::FindPrefs(account_id, &dict))
return false;
if (!dict->GetString(kTokenHandlePref, &token))
return false;
return !token.empty();
}
bool TokenHandleUtil::ShouldObtainHandle(const AccountId& account_id) {
const base::DictionaryValue* dict = nullptr;
std::string token;
if (!user_manager::known_user::FindPrefs(account_id, &dict))
return true;
if (!dict->GetString(kTokenHandlePref, &token))
return true;
if (token.empty())
return true;
std::string status(kDefaultHandleStatus);
dict->GetString(kTokenHandleStatusPref, &status);
return kHandleStatusInvalid == status;
}
void TokenHandleUtil::DeleteHandle(const AccountId& account_id) {
const base::DictionaryValue* dict = nullptr;
if (!user_manager::known_user::FindPrefs(account_id, &dict))
return;
std::unique_ptr<base::DictionaryValue> dict_copy(dict->DeepCopy());
dict_copy->Remove(kTokenHandlePref, nullptr);
dict_copy->Remove(kTokenHandleStatusPref, nullptr);
user_manager::known_user::UpdatePrefs(account_id, *dict_copy.get(),
/* replace values */ true);
}
void TokenHandleUtil::MarkHandleInvalid(const AccountId& account_id) {
user_manager::known_user::SetStringPref(account_id, kTokenHandleStatusPref,
kHandleStatusInvalid);
}
void TokenHandleUtil::CheckToken(const AccountId& account_id,
const TokenValidationCallback& callback) {
const base::DictionaryValue* dict = nullptr;
std::string token;
if (!user_manager::known_user::FindPrefs(account_id, &dict)) {
callback.Run(account_id, UNKNOWN);
return;
}
if (!dict->GetString(kTokenHandlePref, &token)) {
callback.Run(account_id, UNKNOWN);
return;
}
if (!gaia_client_.get()) {
auto url_loader_factory = chromeos::ProfileHelper::Get()
->GetSigninProfile()
->GetURLLoaderFactory();
gaia_client_.reset(
new gaia::GaiaOAuthClient(std::move(url_loader_factory)));
}
validation_delegates_[token] =
std::unique_ptr<TokenDelegate>(new TokenDelegate(
weak_factory_.GetWeakPtr(), account_id, token, callback));
gaia_client_->GetTokenHandleInfo(token, kMaxRetries,
validation_delegates_[token].get());
}
void TokenHandleUtil::StoreTokenHandle(const AccountId& account_id,
const std::string& handle) {
user_manager::known_user::SetStringPref(account_id, kTokenHandlePref, handle);
user_manager::known_user::SetStringPref(account_id, kTokenHandleStatusPref,
kHandleStatusValid);
}
void TokenHandleUtil::OnValidationComplete(const std::string& token) {
validation_delegates_.erase(token);
}
TokenHandleUtil::TokenDelegate::TokenDelegate(
const base::WeakPtr<TokenHandleUtil>& owner,
const AccountId& account_id,
const std::string& token,
const TokenValidationCallback& callback)
: owner_(owner),
account_id_(account_id),
token_(token),
tokeninfo_response_start_time_(base::TimeTicks::Now()),
callback_(callback) {}
TokenHandleUtil::TokenDelegate::~TokenDelegate() {}
void TokenHandleUtil::TokenDelegate::OnOAuthError() {
callback_.Run(account_id_, INVALID);
NotifyDone();
}
// Warning: NotifyDone() deletes |this|
void TokenHandleUtil::TokenDelegate::NotifyDone() {
if (owner_)
owner_->OnValidationComplete(token_);
}
void TokenHandleUtil::TokenDelegate::OnNetworkError(int response_code) {
callback_.Run(account_id_, UNKNOWN);
NotifyDone();
}
void TokenHandleUtil::TokenDelegate::OnGetTokenInfoResponse(
std::unique_ptr<base::DictionaryValue> token_info) {
TokenHandleStatus outcome = UNKNOWN;
if (!token_info->HasKey("error")) {
int expires_in = 0;
if (token_info->GetInteger("expires_in", &expires_in))
outcome = (expires_in < 0) ? INVALID : VALID;
}
const base::TimeDelta duration =
base::TimeTicks::Now() - tokeninfo_response_start_time_;
UMA_HISTOGRAM_TIMES("Login.TokenCheckResponseTime", duration);
callback_.Run(account_id_, outcome);
NotifyDone();
}