| Index: components/signin/ios/browser/profile_oauth2_token_service_ios.mm
|
| diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios.mm
|
| deleted file mode 100644
|
| index 2eb3cff42429ff2564df047782c82c5e57351f19..0000000000000000000000000000000000000000
|
| --- a/components/signin/ios/browser/profile_oauth2_token_service_ios.mm
|
| +++ /dev/null
|
| @@ -1,499 +0,0 @@
|
| -// Copyright 2014 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 "components/signin/ios/browser/profile_oauth2_token_service_ios.h"
|
| -
|
| -#include <Foundation/Foundation.h>
|
| -
|
| -#include <set>
|
| -#include <string>
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/prefs/pref_service.h"
|
| -#include "base/prefs/scoped_user_pref_update.h"
|
| -#include "base/strings/sys_string_conversions.h"
|
| -#include "base/values.h"
|
| -#include "components/signin/core/browser/signin_client.h"
|
| -#include "components/signin/core/common/signin_pref_names.h"
|
| -#include "google_apis/gaia/oauth2_access_token_fetcher.h"
|
| -#include "ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h"
|
| -#include "net/url_request/url_request_status.h"
|
| -
|
| -namespace {
|
| -
|
| -// Match the way Chromium handles authentication errors in
|
| -// google_apis/gaia/oauth2_access_token_fetcher.cc:
|
| -GoogleServiceAuthError GetGoogleServiceAuthErrorFromNSError(
|
| - ios::ProfileOAuth2TokenServiceIOSProvider* provider,
|
| - NSError* error) {
|
| - if (!error)
|
| - return GoogleServiceAuthError::AuthErrorNone();
|
| -
|
| - ios::AuthenticationErrorCategory errorCategory =
|
| - provider->GetAuthenticationErrorCategory(error);
|
| - switch (errorCategory) {
|
| - case ios::kAuthenticationErrorCategoryUnknownErrors:
|
| - // Treat all unknown error as unexpected service response errors.
|
| - // This may be too general and may require a finer grain filtering.
|
| - return GoogleServiceAuthError(
|
| - GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE);
|
| - case ios::kAuthenticationErrorCategoryAuthorizationErrors:
|
| - return GoogleServiceAuthError(
|
| - GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
|
| - case ios::kAuthenticationErrorCategoryAuthorizationForbiddenErrors:
|
| - // HTTP_FORBIDDEN (403) is treated as temporary error, because it may be
|
| - // '403 Rate Limit Exceeded.' (for more details, see
|
| - // google_apis/gaia/oauth2_access_token_fetcher.cc).
|
| - return GoogleServiceAuthError(
|
| - GoogleServiceAuthError::SERVICE_UNAVAILABLE);
|
| - case ios::kAuthenticationErrorCategoryNetworkServerErrors:
|
| - // Just set the connection error state to FAILED.
|
| - return GoogleServiceAuthError::FromConnectionError(
|
| - net::URLRequestStatus::FAILED);
|
| - case ios::kAuthenticationErrorCategoryUserCancellationErrors:
|
| - return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
|
| - case ios::kAuthenticationErrorCategoryUnknownIdentityErrors:
|
| - return GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
|
| - }
|
| -}
|
| -
|
| -class SSOAccessTokenFetcher : public OAuth2AccessTokenFetcher {
|
| - public:
|
| - SSOAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer,
|
| - ios::ProfileOAuth2TokenServiceIOSProvider* provider,
|
| - const std::string account_id);
|
| - ~SSOAccessTokenFetcher() override;
|
| -
|
| - void Start(const std::string& client_id,
|
| - const std::string& client_secret,
|
| - const std::vector<std::string>& scopes) override;
|
| -
|
| - void CancelRequest() override;
|
| -
|
| - // Handles an access token response.
|
| - void OnAccessTokenResponse(NSString* token,
|
| - NSDate* expiration,
|
| - NSError* error);
|
| -
|
| - private:
|
| - ios::ProfileOAuth2TokenServiceIOSProvider* provider_; // weak
|
| - std::string account_id_;
|
| - bool request_was_cancelled_;
|
| - base::WeakPtrFactory<SSOAccessTokenFetcher> weak_factory_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(SSOAccessTokenFetcher);
|
| -};
|
| -
|
| -SSOAccessTokenFetcher::SSOAccessTokenFetcher(
|
| - OAuth2AccessTokenConsumer* consumer,
|
| - ios::ProfileOAuth2TokenServiceIOSProvider* provider,
|
| - const std::string account_id)
|
| - : OAuth2AccessTokenFetcher(consumer),
|
| - provider_(provider),
|
| - account_id_(account_id),
|
| - request_was_cancelled_(false),
|
| - weak_factory_(this) {
|
| - DCHECK(provider_);
|
| -}
|
| -
|
| -SSOAccessTokenFetcher::~SSOAccessTokenFetcher() {}
|
| -
|
| -void SSOAccessTokenFetcher::Start(const std::string& client_id,
|
| - const std::string& client_secret,
|
| - const std::vector<std::string>& scopes) {
|
| - std::set<std::string> scopes_set(scopes.begin(), scopes.end());
|
| - provider_->GetAccessToken(
|
| - account_id_, client_id, client_secret, scopes_set,
|
| - base::Bind(&SSOAccessTokenFetcher::OnAccessTokenResponse,
|
| - weak_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -void SSOAccessTokenFetcher::CancelRequest() { request_was_cancelled_ = true; }
|
| -
|
| -void SSOAccessTokenFetcher::OnAccessTokenResponse(NSString* token,
|
| - NSDate* expiration,
|
| - NSError* error) {
|
| - if (request_was_cancelled_) {
|
| - // Ignore the callback if the request was cancelled.
|
| - return;
|
| - }
|
| - GoogleServiceAuthError auth_error =
|
| - GetGoogleServiceAuthErrorFromNSError(provider_, error);
|
| - if (auth_error.state() == GoogleServiceAuthError::NONE) {
|
| - base::Time expiration_date =
|
| - base::Time::FromDoubleT([expiration timeIntervalSince1970]);
|
| - FireOnGetTokenSuccess(base::SysNSStringToUTF8(token), expiration_date);
|
| - } else {
|
| - FireOnGetTokenFailure(auth_error);
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -ProfileOAuth2TokenServiceIOS::AccountInfo::AccountInfo(
|
| - SigninErrorController* signin_error_controller,
|
| - const std::string& account_id)
|
| - : signin_error_controller_(signin_error_controller),
|
| - account_id_(account_id),
|
| - last_auth_error_(GoogleServiceAuthError::NONE),
|
| - marked_for_removal_(false) {
|
| - DCHECK(signin_error_controller_);
|
| - DCHECK(!account_id_.empty());
|
| - signin_error_controller_->AddProvider(this);
|
| -}
|
| -
|
| -ProfileOAuth2TokenServiceIOS::AccountInfo::~AccountInfo() {
|
| - signin_error_controller_->RemoveProvider(this);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::AccountInfo::SetLastAuthError(
|
| - const GoogleServiceAuthError& error) {
|
| - if (error.state() != last_auth_error_.state()) {
|
| - last_auth_error_ = error;
|
| - signin_error_controller_->AuthStatusChanged();
|
| - }
|
| -}
|
| -
|
| -std::string ProfileOAuth2TokenServiceIOS::AccountInfo::GetAccountId() const {
|
| - return account_id_;
|
| -}
|
| -
|
| -GoogleServiceAuthError
|
| -ProfileOAuth2TokenServiceIOS::AccountInfo::GetAuthStatus() const {
|
| - return last_auth_error_;
|
| -}
|
| -
|
| -ProfileOAuth2TokenServiceIOS::ProfileOAuth2TokenServiceIOS()
|
| - : ProfileOAuth2TokenService() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -}
|
| -
|
| -ProfileOAuth2TokenServiceIOS::~ProfileOAuth2TokenServiceIOS() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::Initialize(
|
| - SigninClient* client, SigninErrorController* signin_error_controller) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - ProfileOAuth2TokenService::Initialize(client, signin_error_controller);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::Shutdown() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - CancelAllRequests();
|
| - accounts_.clear();
|
| - ProfileOAuth2TokenService::Shutdown();
|
| -}
|
| -
|
| -ios::ProfileOAuth2TokenServiceIOSProvider*
|
| -ProfileOAuth2TokenServiceIOS::GetProvider() {
|
| - ios::ProfileOAuth2TokenServiceIOSProvider* provider =
|
| - client()->GetIOSProvider();
|
| - DCHECK(provider);
|
| - return provider;
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::LoadCredentials(
|
| - const std::string& primary_account_id) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // LoadCredentials() is called iff the user is signed in to Chrome, so the
|
| - // primary account id must not be empty.
|
| - DCHECK(!primary_account_id.empty());
|
| -
|
| - GetProvider()->InitializeSharedAuthentication();
|
| - ReloadCredentials(primary_account_id);
|
| - FireRefreshTokensLoaded();
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::ReloadCredentials(
|
| - const std::string& primary_account_id) {
|
| - DCHECK(!primary_account_id.empty());
|
| - DCHECK(primary_account_id_.empty() ||
|
| - primary_account_id_ == primary_account_id);
|
| - primary_account_id_ = primary_account_id;
|
| - ReloadCredentials();
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::ReloadCredentials() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (primary_account_id_.empty()) {
|
| - // Avoid loading the credentials if there is no primary account id.
|
| - return;
|
| - }
|
| -
|
| - std::vector<std::string> new_accounts(GetProvider()->GetAllAccountIds());
|
| - if (GetExcludeAllSecondaryAccounts()) {
|
| - // Only keep the |primary_account_id| in the list of new accounts.
|
| - if (std::find(new_accounts.begin(),
|
| - new_accounts.end(),
|
| - primary_account_id_) != new_accounts.end()) {
|
| - new_accounts.clear();
|
| - new_accounts.push_back(primary_account_id_);
|
| - }
|
| - } else {
|
| - std::set<std::string> exclude_secondary_accounts =
|
| - GetExcludedSecondaryAccounts();
|
| - DCHECK(std::find(exclude_secondary_accounts.begin(),
|
| - exclude_secondary_accounts.end(),
|
| - primary_account_id_) == exclude_secondary_accounts.end());
|
| - for (const auto& excluded_account_id : exclude_secondary_accounts) {
|
| - DCHECK(!excluded_account_id.empty());
|
| - auto account_id_to_remove_position = std::remove(
|
| - new_accounts.begin(), new_accounts.end(), excluded_account_id);
|
| - new_accounts.erase(account_id_to_remove_position, new_accounts.end());
|
| - }
|
| - }
|
| -
|
| - std::vector<std::string> old_accounts(GetAccounts());
|
| - std::sort(new_accounts.begin(), new_accounts.end());
|
| - std::sort(old_accounts.begin(), old_accounts.end());
|
| - if (new_accounts == old_accounts) {
|
| - // Avoid starting a batch change if there are no changes in the list of
|
| - // account.
|
| - return;
|
| - }
|
| -
|
| - // Remove all old accounts that do not appear in |new_accounts| and then
|
| - // load |new_accounts|.
|
| - ScopedBatchChange batch(this);
|
| - for (auto i = old_accounts.begin(); i != old_accounts.end(); ++i) {
|
| - if (std::find(new_accounts.begin(), new_accounts.end(), *i) ==
|
| - new_accounts.end()) {
|
| - RemoveAccount(*i);
|
| - }
|
| - }
|
| -
|
| - // Load all new_accounts.
|
| - for (auto i = new_accounts.begin(); i != new_accounts.end(); ++i) {
|
| - AddOrUpdateAccount(*i);
|
| - }
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::UpdateCredentials(
|
| - const std::string& account_id,
|
| - const std::string& refresh_token) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - NOTREACHED() << "Unexpected call to UpdateCredentials when using shared "
|
| - "authentication.";
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::RevokeAllCredentials() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - ScopedBatchChange batch(this);
|
| - AccountInfoMap toRemove = accounts_;
|
| - for (AccountInfoMap::iterator i = toRemove.begin(); i != toRemove.end(); ++i)
|
| - RemoveAccount(i->first);
|
| -
|
| - DCHECK_EQ(0u, accounts_.size());
|
| - primary_account_id_.clear();
|
| - ClearExcludedSecondaryAccounts();
|
| - // |RemoveAccount| should have cancelled all the requests and cleared the
|
| - // cache, account-by-account. This extra-cleaning should do nothing unless
|
| - // something went wrong and some cache values and/or pending requests were not
|
| - // linked to any valid account.
|
| - CancelAllRequests();
|
| - ClearCache();
|
| -}
|
| -
|
| -OAuth2AccessTokenFetcher*
|
| -ProfileOAuth2TokenServiceIOS::CreateAccessTokenFetcher(
|
| - const std::string& account_id,
|
| - net::URLRequestContextGetter* getter,
|
| - OAuth2AccessTokenConsumer* consumer) {
|
| - return new SSOAccessTokenFetcher(consumer, GetProvider(), account_id);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::InvalidateOAuth2Token(
|
| - const std::string& account_id,
|
| - const std::string& client_id,
|
| - const ScopeSet& scopes,
|
| - const std::string& access_token) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // Call |ProfileOAuth2TokenService::InvalidateOAuth2Token| to clear the
|
| - // cached access token.
|
| - ProfileOAuth2TokenService::InvalidateOAuth2Token(account_id,
|
| - client_id,
|
| - scopes,
|
| - access_token);
|
| -
|
| - // There is no need to inform the authentication library that the access
|
| - // token is invalid as it never caches the token.
|
| -}
|
| -
|
| -std::vector<std::string> ProfileOAuth2TokenServiceIOS::GetAccounts() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - std::vector<std::string> account_ids;
|
| - for (auto i = accounts_.begin(); i != accounts_.end(); ++i)
|
| - account_ids.push_back(i->first);
|
| - return account_ids;
|
| -}
|
| -
|
| -bool ProfileOAuth2TokenServiceIOS::RefreshTokenIsAvailable(
|
| - const std::string& account_id) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - AccountInfoMap::const_iterator iter = accounts_.find(account_id);
|
| - return iter != accounts_.end() && !iter->second->marked_for_removal();
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::UpdateAuthError(
|
| - const std::string& account_id,
|
| - const GoogleServiceAuthError& error) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // Do not report connection errors as these are not actually auth errors.
|
| - // We also want to avoid masking a "real" auth error just because we
|
| - // subsequently get a transient network error.
|
| - if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
|
| - error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
|
| - return;
|
| - }
|
| -
|
| - if (accounts_.count(account_id) == 0) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| - accounts_[account_id]->SetLastAuthError(error);
|
| -}
|
| -
|
| -// Clear the authentication error state and notify all observers that a new
|
| -// refresh token is available so that they request new access tokens.
|
| -void ProfileOAuth2TokenServiceIOS::AddOrUpdateAccount(
|
| - const std::string& account_id) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(!account_id.empty());
|
| -
|
| - bool account_present = accounts_.count(account_id) > 0;
|
| - if (account_present && accounts_[account_id]->GetAuthStatus().state() ==
|
| - GoogleServiceAuthError::NONE) {
|
| - // No need to update the account if it is already a known account and if
|
| - // there is no auth error.
|
| - return;
|
| - }
|
| -
|
| - if (account_present) {
|
| - CancelRequestsForAccount(account_id);
|
| - ClearCacheForAccount(account_id);
|
| - } else {
|
| - accounts_[account_id].reset(
|
| - new AccountInfo(signin_error_controller(), account_id));
|
| - }
|
| - UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
|
| - FireRefreshTokenAvailable(account_id);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::RemoveAccount(
|
| - const std::string& account_id) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(!account_id.empty());
|
| -
|
| - if (accounts_.count(account_id) > 0) {
|
| - // This is needed to ensure that refresh token for |acccount_id| is not
|
| - // available while the account is removed. Thus all access token requests
|
| - // for |account_id| triggered while an account is being removed will get a
|
| - // user not signed up error response.
|
| - accounts_[account_id]->set_marked_for_removal(true);
|
| - CancelRequestsForAccount(account_id);
|
| - ClearCacheForAccount(account_id);
|
| - accounts_.erase(account_id);
|
| - FireRefreshTokenRevoked(account_id);
|
| - }
|
| -}
|
| -
|
| -std::set<std::string>
|
| -ProfileOAuth2TokenServiceIOS::GetExcludedSecondaryAccounts() {
|
| - const base::ListValue* excluded_secondary_accounts_pref =
|
| - client()->GetPrefs()->GetList(
|
| - prefs::kTokenServiceExcludedSecondaryAccounts);
|
| - std::set<std::string> excluded_secondary_accounts;
|
| - for (base::Value* pref_value : *excluded_secondary_accounts_pref) {
|
| - std::string value;
|
| - if (pref_value->GetAsString(&value))
|
| - excluded_secondary_accounts.insert(value);
|
| - }
|
| - return excluded_secondary_accounts;
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::ExcludeSecondaryAccounts(
|
| - const std::vector<std::string>& account_ids) {
|
| - for (const auto& account_id : account_ids)
|
| - ExcludeSecondaryAccount(account_id);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::ExcludeSecondaryAccount(
|
| - const std::string& account_id) {
|
| - if (GetExcludeAllSecondaryAccounts()) {
|
| - // Avoid excluding individual secondary accounts when all secondary
|
| - // accounts are excluded.
|
| - return;
|
| - }
|
| -
|
| - DCHECK(!account_id.empty());
|
| - ListPrefUpdate update(client()->GetPrefs(),
|
| - prefs::kTokenServiceExcludedSecondaryAccounts);
|
| - base::ListValue* excluded_secondary_accounts = update.Get();
|
| - for (base::Value* pref_value : *excluded_secondary_accounts) {
|
| - std::string value_at_it;
|
| - if (pref_value->GetAsString(&value_at_it) && (value_at_it == account_id)) {
|
| - // |account_id| is already excluded.
|
| - return;
|
| - }
|
| - }
|
| - excluded_secondary_accounts->AppendString(account_id);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::IncludeSecondaryAccount(
|
| - const std::string& account_id) {
|
| - if (GetExcludeAllSecondaryAccounts()) {
|
| - // Avoid including individual secondary accounts when all secondary
|
| - // accounts are excluded.
|
| - return;
|
| - }
|
| -
|
| - DCHECK_NE(account_id, primary_account_id_);
|
| - DCHECK(!primary_account_id_.empty());
|
| -
|
| - // Excluded secondary account ids is a logical set (not a list) of accounts.
|
| - // As the value stored in the excluded account ids preference is a list,
|
| - // the code below removes all occurences of |account_id| from this list. This
|
| - // ensures that |account_id| is actually included even in cases when the
|
| - // preference value was corrupted (see bug http://crbug.com/453470 as
|
| - // example).
|
| - ListPrefUpdate update(client()->GetPrefs(),
|
| - prefs::kTokenServiceExcludedSecondaryAccounts);
|
| - base::ListValue* excluded_secondary_accounts = update.Get();
|
| - base::ListValue::iterator it = excluded_secondary_accounts->begin();
|
| - while (it != excluded_secondary_accounts->end()) {
|
| - base::Value* pref_value = *it;
|
| - std::string value_at_it;
|
| - if (pref_value->GetAsString(&value_at_it) && (value_at_it == account_id)) {
|
| - it = excluded_secondary_accounts->Erase(it, nullptr);
|
| - continue;
|
| - }
|
| - ++it;
|
| - }
|
| -}
|
| -
|
| -bool ProfileOAuth2TokenServiceIOS::GetExcludeAllSecondaryAccounts() {
|
| - return client()->GetPrefs()->GetBoolean(
|
| - prefs::kTokenServiceExcludeAllSecondaryAccounts);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::ExcludeAllSecondaryAccounts() {
|
| - client()->GetPrefs()->SetBoolean(
|
| - prefs::kTokenServiceExcludeAllSecondaryAccounts, true);
|
| -}
|
| -
|
| -void ProfileOAuth2TokenServiceIOS::ClearExcludedSecondaryAccounts() {
|
| - client()->GetPrefs()->ClearPref(
|
| - prefs::kTokenServiceExcludeAllSecondaryAccounts);
|
| - client()->GetPrefs()->ClearPref(
|
| - prefs::kTokenServiceExcludedSecondaryAccounts);
|
| -}
|
|
|