This source file includes following definitions.
- ApplyAccountIdPrefix
- IsLegacyRefreshTokenId
- IsLegacyServiceId
- RemoveAccountIdPrefix
- fetcher_
- OnOAuth2RevokeTokenCompleted
- last_auth_error_
- SetLastAuthError
- GetAccountId
- GetAuthStatus
- Shutdown
- RefreshTokenIsAvailable
- GetRefreshToken
- CreateAccessTokenFetcher
- GetRequestContext
- LoadCredentials
- OnWebDataServiceRequestDone
- LoadAllCredentialsIntoMemory
- UpdateAuthError
- GetAccounts
- UpdateCredentials
- RevokeCredentials
- PersistCredentials
- ClearPersistedCredentials
- RevokeAllCredentials
- RevokeCredentialsOnServer
- CancelWebTokenFetch
#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/webdata/token_web_data.h"
#include "components/webdata/common/web_data_service_base.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "net/url_request/url_request_context_getter.h"
namespace {
const char kAccountIdPrefix[] = "AccountId-";
const size_t kAccountIdPrefixLength = 10;
std::string ApplyAccountIdPrefix(const std::string& account_id) {
return kAccountIdPrefix + account_id;
}
bool IsLegacyRefreshTokenId(const std::string& service_id) {
return service_id == GaiaConstants::kGaiaOAuth2LoginRefreshToken;
}
bool IsLegacyServiceId(const std::string& account_id) {
return account_id.compare(0u, kAccountIdPrefixLength, kAccountIdPrefix) != 0;
}
std::string RemoveAccountIdPrefix(const std::string& prefixed_account_id) {
return prefixed_account_id.substr(kAccountIdPrefixLength);
}
}
class MutableProfileOAuth2TokenService::RevokeServerRefreshToken
: public GaiaAuthConsumer {
public:
RevokeServerRefreshToken(MutableProfileOAuth2TokenService* token_service,
const std::string& account_id);
virtual ~RevokeServerRefreshToken();
private:
virtual void OnOAuth2RevokeTokenCompleted() OVERRIDE;
MutableProfileOAuth2TokenService* token_service_;
GaiaAuthFetcher fetcher_;
DISALLOW_COPY_AND_ASSIGN(RevokeServerRefreshToken);
};
MutableProfileOAuth2TokenService::
RevokeServerRefreshToken::RevokeServerRefreshToken(
MutableProfileOAuth2TokenService* token_service,
const std::string& refresh_token)
: token_service_(token_service),
fetcher_(this, GaiaConstants::kChromeSource,
token_service_->GetRequestContext()) {
fetcher_.StartRevokeOAuth2Token(refresh_token);
}
MutableProfileOAuth2TokenService::
RevokeServerRefreshToken::~RevokeServerRefreshToken() {}
void MutableProfileOAuth2TokenService::
RevokeServerRefreshToken::OnOAuth2RevokeTokenCompleted() {
token_service_->server_revokes_.erase(
std::find(token_service_->server_revokes_.begin(),
token_service_->server_revokes_.end(),
this));
}
MutableProfileOAuth2TokenService::AccountInfo::AccountInfo(
ProfileOAuth2TokenService* token_service,
const std::string& account_id,
const std::string& refresh_token)
: token_service_(token_service),
account_id_(account_id),
refresh_token_(refresh_token),
last_auth_error_(GoogleServiceAuthError::NONE) {
DCHECK(token_service_);
DCHECK(!account_id_.empty());
token_service_->signin_error_controller()->AddProvider(this);
}
MutableProfileOAuth2TokenService::AccountInfo::~AccountInfo() {
token_service_->signin_error_controller()->RemoveProvider(this);
}
void MutableProfileOAuth2TokenService::AccountInfo::SetLastAuthError(
const GoogleServiceAuthError& error) {
if (error.state() != last_auth_error_.state()) {
last_auth_error_ = error;
token_service_->signin_error_controller()->AuthStatusChanged();
}
}
std::string
MutableProfileOAuth2TokenService::AccountInfo::GetAccountId() const {
return account_id_;
}
GoogleServiceAuthError
MutableProfileOAuth2TokenService::AccountInfo::GetAuthStatus() const {
return last_auth_error_;
}
MutableProfileOAuth2TokenService::MutableProfileOAuth2TokenService()
: web_data_service_request_(0) {
}
MutableProfileOAuth2TokenService::~MutableProfileOAuth2TokenService() {
DCHECK(server_revokes_.empty());
}
void MutableProfileOAuth2TokenService::Shutdown() {
server_revokes_.clear();
CancelWebTokenFetch();
CancelAllRequests();
refresh_tokens_.clear();
ProfileOAuth2TokenService::Shutdown();
}
bool MutableProfileOAuth2TokenService::RefreshTokenIsAvailable(
const std::string& account_id) const {
return !GetRefreshToken(account_id).empty();
}
std::string MutableProfileOAuth2TokenService::GetRefreshToken(
const std::string& account_id) const {
AccountInfoMap::const_iterator iter = refresh_tokens_.find(account_id);
if (iter != refresh_tokens_.end())
return iter->second->refresh_token();
return std::string();
}
OAuth2AccessTokenFetcher*
MutableProfileOAuth2TokenService::CreateAccessTokenFetcher(
const std::string& account_id,
net::URLRequestContextGetter* getter,
OAuth2AccessTokenConsumer* consumer) {
std::string refresh_token = GetRefreshToken(account_id);
DCHECK(!refresh_token.empty());
return new OAuth2AccessTokenFetcherImpl(consumer, getter, refresh_token);
}
net::URLRequestContextGetter*
MutableProfileOAuth2TokenService::GetRequestContext() {
return client()->GetURLRequestContext();
}
void MutableProfileOAuth2TokenService::LoadCredentials(
const std::string& primary_account_id) {
DCHECK(!primary_account_id.empty());
DCHECK(loading_primary_account_id_.empty());
DCHECK_EQ(0, web_data_service_request_);
CancelAllRequests();
refresh_tokens().clear();
loading_primary_account_id_ = primary_account_id;
scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
if (token_web_data.get())
web_data_service_request_ = token_web_data->GetAllTokens(this);
}
void MutableProfileOAuth2TokenService::OnWebDataServiceRequestDone(
WebDataServiceBase::Handle handle,
const WDTypedResult* result) {
DCHECK_EQ(web_data_service_request_, handle);
web_data_service_request_ = 0;
if (result) {
DCHECK(result->GetType() == TOKEN_RESULT);
const WDResult<std::map<std::string, std::string> > * token_result =
static_cast<const WDResult<std::map<std::string, std::string> > * > (
result);
LoadAllCredentialsIntoMemory(token_result->GetValue());
}
DCHECK(!loading_primary_account_id_.empty());
if (refresh_tokens().count(loading_primary_account_id_) == 0) {
refresh_tokens()[loading_primary_account_id_].reset(
new AccountInfo(this, loading_primary_account_id_, std::string()));
}
for (AccountInfoMap::const_iterator i = refresh_tokens_.begin();
i != refresh_tokens_.end(); ++i) {
if (!RefreshTokenIsAvailable(i->first)) {
UpdateAuthError(
i->first,
GoogleServiceAuthError(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
break;
}
}
loading_primary_account_id_.clear();
}
void MutableProfileOAuth2TokenService::LoadAllCredentialsIntoMemory(
const std::map<std::string, std::string>& db_tokens) {
std::string old_login_token;
for (std::map<std::string, std::string>::const_iterator iter =
db_tokens.begin();
iter != db_tokens.end();
++iter) {
std::string prefixed_account_id = iter->first;
std::string refresh_token = iter->second;
if (IsLegacyRefreshTokenId(prefixed_account_id) && !refresh_token.empty())
old_login_token = refresh_token;
if (IsLegacyServiceId(prefixed_account_id)) {
scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
if (token_web_data.get())
token_web_data->RemoveTokenForService(prefixed_account_id);
} else {
DCHECK(!refresh_token.empty());
std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);
refresh_tokens()[account_id].reset(
new AccountInfo(this, account_id, refresh_token));
FireRefreshTokenAvailable(account_id);
}
}
if (!old_login_token.empty()) {
DCHECK(!loading_primary_account_id_.empty());
if (refresh_tokens().count(loading_primary_account_id_) == 0)
UpdateCredentials(loading_primary_account_id_, old_login_token);
}
FireRefreshTokensLoaded();
}
void MutableProfileOAuth2TokenService::UpdateAuthError(
const std::string& account_id,
const GoogleServiceAuthError& error) {
if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE)
return;
#if defined(OS_IOS)
if (refresh_tokens_.count(account_id) == 0) {
refresh_tokens_[account_id].reset(
new AccountInfo(this, account_id, std::string()));
}
#endif
if (refresh_tokens_.count(account_id) == 0) {
NOTREACHED();
return;
}
refresh_tokens_[account_id]->SetLastAuthError(error);
}
std::vector<std::string> MutableProfileOAuth2TokenService::GetAccounts() {
std::vector<std::string> account_ids;
for (AccountInfoMap::const_iterator iter = refresh_tokens_.begin();
iter != refresh_tokens_.end(); ++iter) {
account_ids.push_back(iter->first);
}
return account_ids;
}
void MutableProfileOAuth2TokenService::UpdateCredentials(
const std::string& account_id,
const std::string& refresh_token) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!account_id.empty());
DCHECK(!refresh_token.empty());
bool refresh_token_present = refresh_tokens_.count(account_id) > 0;
if (!refresh_token_present ||
refresh_tokens_[account_id]->refresh_token() != refresh_token) {
if (refresh_token_present) {
std::string revoke_reason = refresh_token_present ? "token differs" :
"token is missing";
LOG(WARNING) << "Revoking refresh token on server. "
<< "Reason: token update, " << revoke_reason;
RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
CancelRequestsForAccount(account_id);
ClearCacheForAccount(account_id);
refresh_tokens_[account_id]->set_refresh_token(refresh_token);
} else {
refresh_tokens_[account_id].reset(
new AccountInfo(this, account_id, refresh_token));
}
PersistCredentials(account_id, refresh_token);
UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
FireRefreshTokenAvailable(account_id);
}
}
void MutableProfileOAuth2TokenService::RevokeCredentials(
const std::string& account_id) {
DCHECK(thread_checker_.CalledOnValidThread());
if (refresh_tokens_.count(account_id) > 0) {
RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
CancelRequestsForAccount(account_id);
ClearCacheForAccount(account_id);
refresh_tokens_.erase(account_id);
ClearPersistedCredentials(account_id);
FireRefreshTokenRevoked(account_id);
}
}
void MutableProfileOAuth2TokenService::PersistCredentials(
const std::string& account_id,
const std::string& refresh_token) {
scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
if (token_web_data.get()) {
token_web_data->SetTokenForService(ApplyAccountIdPrefix(account_id),
refresh_token);
}
}
void MutableProfileOAuth2TokenService::ClearPersistedCredentials(
const std::string& account_id) {
scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
if (token_web_data.get())
token_web_data->RemoveTokenForService(ApplyAccountIdPrefix(account_id));
}
void MutableProfileOAuth2TokenService::RevokeAllCredentials() {
if (!client()->CanRevokeCredentials())
return;
DCHECK(thread_checker_.CalledOnValidThread());
CancelWebTokenFetch();
CancelAllRequests();
ClearCache();
AccountInfoMap tokens = refresh_tokens_;
for (AccountInfoMap::iterator i = tokens.begin(); i != tokens.end(); ++i)
RevokeCredentials(i->first);
DCHECK_EQ(0u, refresh_tokens_.size());
}
void MutableProfileOAuth2TokenService::RevokeCredentialsOnServer(
const std::string& refresh_token) {
server_revokes_.push_back(
new RevokeServerRefreshToken(this, refresh_token));
}
void MutableProfileOAuth2TokenService::CancelWebTokenFetch() {
if (web_data_service_request_ != 0) {
scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
DCHECK(token_web_data.get());
token_web_data->CancelRequest(web_data_service_request_);
web_data_service_request_ = 0;
}
}