| // Copyright 2017 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 "services/identity/identity_accessor_impl.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/time/time.h" |
| #include "google_apis/gaia/google_service_auth_error.h" |
| #include "services/identity/public/mojom/account.mojom.h" |
| |
| namespace identity { |
| |
| void IdentityAccessorImpl::OnTokenRequestCompleted( |
| base::UnguessableToken callback_id, |
| scoped_refptr<base::RefCountedData<bool>> is_callback_done, |
| GetAccessTokenCallback consumer_callback, |
| GoogleServiceAuthError error, |
| AccessTokenInfo access_token_info) { |
| if (error.state() == GoogleServiceAuthError::NONE) { |
| std::move(consumer_callback) |
| .Run(access_token_info.token, access_token_info.expiration_time, error); |
| } else { |
| std::move(consumer_callback).Run(base::nullopt, base::Time(), error); |
| } |
| |
| is_callback_done->data = true; |
| access_token_fetchers_.erase(callback_id); |
| } |
| |
| // static |
| void IdentityAccessorImpl::Create(mojom::IdentityAccessorRequest request, |
| IdentityManager* identity_manager) { |
| new IdentityAccessorImpl(std::move(request), identity_manager); |
| } |
| |
| IdentityAccessorImpl::IdentityAccessorImpl( |
| mojom::IdentityAccessorRequest request, |
| IdentityManager* identity_manager) |
| : binding_(this, std::move(request)), identity_manager_(identity_manager) { |
| binding_.set_connection_error_handler(base::BindRepeating( |
| &IdentityAccessorImpl::OnConnectionError, base::Unretained(this))); |
| |
| identity_manager_->AddObserver(this); |
| } |
| |
| IdentityAccessorImpl::~IdentityAccessorImpl() { |
| identity_manager_->RemoveObserver(this); |
| binding_.Close(); |
| } |
| |
| void IdentityAccessorImpl::GetPrimaryAccountInfo( |
| GetPrimaryAccountInfoCallback callback) { |
| AccountInfo account_info = |
| identity_manager_->GetPrimaryAccountInfoDeprecated(); |
| AccountState account_state = GetStateOfAccount(account_info); |
| std::move(callback).Run(account_info, account_state); |
| } |
| |
| void IdentityAccessorImpl::GetPrimaryAccountWhenAvailable( |
| GetPrimaryAccountWhenAvailableCallback callback) { |
| base::Optional<AccountInfo> account_info = |
| identity_manager_->FindExtendedAccountInfoForAccount( |
| identity_manager_->GetPrimaryAccountInfo()); |
| |
| if (!account_info || identity_manager_->GetErrorStateOfRefreshTokenForAccount( |
| account_info->account_id) != |
| GoogleServiceAuthError::AuthErrorNone()) { |
| primary_account_available_callbacks_.push_back(std::move(callback)); |
| return; |
| } |
| |
| AccountState account_state; |
| account_state.has_refresh_token = true; |
| account_state.is_primary_account = true; |
| DCHECK(!account_info->account_id.empty()); |
| DCHECK(!account_info->email.empty()); |
| DCHECK(!account_info->gaia.empty()); |
| std::move(callback).Run(account_info.value(), account_state); |
| } |
| |
| void IdentityAccessorImpl::GetAccessToken(const std::string& account_id, |
| const ScopeSet& scopes, |
| const std::string& consumer_id, |
| GetAccessTokenCallback callback) { |
| base::UnguessableToken callback_id = base::UnguessableToken::Create(); |
| auto is_callback_done = |
| base::MakeRefCounted<base::RefCountedData<bool>>(false); |
| |
| std::unique_ptr<AccessTokenFetcher> fetcher = |
| identity_manager_->CreateAccessTokenFetcherForAccount( |
| account_id, consumer_id, scopes, |
| base::BindOnce(&IdentityAccessorImpl::OnTokenRequestCompleted, |
| base::Unretained(this), callback_id, is_callback_done, |
| std::move(callback)), |
| identity::AccessTokenFetcher::Mode::kImmediate); |
| |
| // If our callback hasn't already been run, hold on to the AccessTokenFetcher |
| // so it won't be cleaned up until the request is done. |
| if (!is_callback_done->data) { |
| access_token_fetchers_[callback_id] = std::move(fetcher); |
| } |
| } |
| |
| void IdentityAccessorImpl::OnRefreshTokenUpdatedForAccount( |
| const CoreAccountInfo& account_info) { |
| OnAccountStateChange(account_info.account_id); |
| } |
| |
| void IdentityAccessorImpl::OnPrimaryAccountSet( |
| const CoreAccountInfo& primary_account_info) { |
| OnAccountStateChange(primary_account_info.account_id); |
| } |
| |
| void IdentityAccessorImpl::OnAccountStateChange(const std::string& account_id) { |
| base::Optional<AccountInfo> account_info = |
| identity_manager_->FindAccountInfoForAccountWithRefreshTokenByAccountId( |
| account_id); |
| if (account_info.has_value()) { |
| AccountState account_state = GetStateOfAccount(account_info.value()); |
| |
| // Check whether the primary account is available and notify any waiting |
| // consumers if so. |
| if (account_state.is_primary_account && |
| !identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState( |
| account_info->account_id)) { |
| DCHECK(!account_info->account_id.empty()); |
| DCHECK(!account_info->email.empty()); |
| DCHECK(!account_info->gaia.empty()); |
| |
| for (auto&& callback : primary_account_available_callbacks_) { |
| std::move(callback).Run(account_info.value(), account_state); |
| } |
| primary_account_available_callbacks_.clear(); |
| } |
| } |
| } |
| |
| AccountState IdentityAccessorImpl::GetStateOfAccount( |
| const CoreAccountInfo& account_info) { |
| AccountState account_state; |
| account_state.has_refresh_token = |
| identity_manager_->HasAccountWithRefreshToken(account_info.account_id); |
| account_state.is_primary_account = |
| (account_info.account_id == identity_manager_->GetPrimaryAccountId()); |
| return account_state; |
| } |
| |
| void IdentityAccessorImpl::OnConnectionError() { |
| delete this; |
| } |
| |
| } // namespace identity |