| // 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 "ios/chrome/browser/signin/signin_client_impl.h" |
| |
| #include <stddef.h> |
| |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/guid.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "components/content_settings/core/browser/cookie_settings.h" |
| #include "components/keyed_service/core/service_access_type.h" |
| #include "components/metrics/metrics_service.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/core/browser/profile_oauth2_token_service.h" |
| #include "components/signin/core/browser/signin_cookie_changed_subscription.h" |
| #include "components/signin/core/browser/signin_header_helper.h" |
| #include "components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h" |
| #include "google_apis/gaia/gaia_constants.h" |
| #include "google_apis/gaia/gaia_urls.h" |
| #include "ios/chrome/browser/application_context.h" |
| #include "ios/chrome/browser/browser_state/browser_state_info_cache.h" |
| #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| #include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" |
| #include "ios/chrome/browser/content_settings/cookie_settings_factory.h" |
| #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" |
| #include "ios/chrome/browser/signin/gaia_auth_fetcher_ios.h" |
| #include "ios/chrome/browser/web_data_service_factory.h" |
| #include "ios/chrome/common/channel_info.h" |
| #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
| #include "net/url_request/url_request_context_getter.h" |
| #include "url/gurl.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| SigninClientImpl::SigninClientImpl( |
| ios::ChromeBrowserState* browser_state, |
| SigninErrorController* signin_error_controller) |
| : OAuth2TokenService::Consumer("signin_client_impl"), |
| browser_state_(browser_state), |
| signin_error_controller_(signin_error_controller) { |
| signin_error_controller_->AddObserver(this); |
| net::NetworkChangeNotifier::AddNetworkChangeObserver(this); |
| } |
| |
| SigninClientImpl::~SigninClientImpl() { |
| signin_error_controller_->RemoveObserver(this); |
| } |
| |
| void SigninClientImpl::Shutdown() { |
| net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
| } |
| |
| void SigninClientImpl::DoFinalInit() {} |
| |
| // static |
| bool SigninClientImpl::AllowsSigninCookies( |
| ios::ChromeBrowserState* browser_state) { |
| scoped_refptr<content_settings::CookieSettings> cookie_settings = |
| ios::CookieSettingsFactory::GetForBrowserState(browser_state); |
| return signin::SettingsAllowSigninCookies(cookie_settings.get()); |
| } |
| |
| PrefService* SigninClientImpl::GetPrefs() { |
| return browser_state_->GetPrefs(); |
| } |
| |
| scoped_refptr<TokenWebData> SigninClientImpl::GetDatabase() { |
| return ios::WebDataServiceFactory::GetTokenWebDataForBrowserState( |
| browser_state_, ServiceAccessType::EXPLICIT_ACCESS); |
| } |
| |
| bool SigninClientImpl::CanRevokeCredentials() { |
| return true; |
| } |
| |
| std::string SigninClientImpl::GetSigninScopedDeviceId() { |
| return GetOrCreateScopedDeviceIdPref(GetPrefs()); |
| } |
| |
| void SigninClientImpl::OnSignedOut() { |
| BrowserStateInfoCache* cache = GetApplicationContext() |
| ->GetChromeBrowserStateManager() |
| ->GetBrowserStateInfoCache(); |
| size_t index = cache->GetIndexOfBrowserStateWithPath( |
| browser_state_->GetOriginalChromeBrowserState()->GetStatePath()); |
| |
| // If sign out occurs because Sync setup was in progress and the browser state |
| // got deleted, then it is no longer in the cache. |
| if (index == std::string::npos) |
| return; |
| |
| cache->SetAuthInfoOfBrowserStateAtIndex(index, std::string(), |
| base::string16()); |
| } |
| |
| net::URLRequestContextGetter* SigninClientImpl::GetURLRequestContext() { |
| return browser_state_->GetRequestContext(); |
| } |
| |
| bool SigninClientImpl::ShouldMergeSigninCredentialsIntoCookieJar() { |
| return false; |
| } |
| |
| std::string SigninClientImpl::GetProductVersion() { |
| return GetVersionString(); |
| } |
| |
| bool SigninClientImpl::IsFirstRun() const { |
| return false; |
| } |
| |
| base::Time SigninClientImpl::GetInstallDate() { |
| return base::Time::FromTimeT( |
| GetApplicationContext()->GetMetricsService()->GetInstallDate()); |
| } |
| |
| bool SigninClientImpl::AreSigninCookiesAllowed() { |
| return AllowsSigninCookies(browser_state_); |
| } |
| |
| void SigninClientImpl::AddContentSettingsObserver( |
| content_settings::Observer* observer) { |
| ios::HostContentSettingsMapFactory::GetForBrowserState(browser_state_) |
| ->AddObserver(observer); |
| } |
| |
| void SigninClientImpl::RemoveContentSettingsObserver( |
| content_settings::Observer* observer) { |
| ios::HostContentSettingsMapFactory::GetForBrowserState(browser_state_) |
| ->RemoveObserver(observer); |
| } |
| |
| std::unique_ptr<SigninClient::CookieChangedSubscription> |
| SigninClientImpl::AddCookieChangedCallback( |
| const GURL& url, |
| const std::string& name, |
| const net::CookieStore::CookieChangedCallback& callback) { |
| scoped_refptr<net::URLRequestContextGetter> context_getter = |
| browser_state_->GetRequestContext(); |
| DCHECK(context_getter.get()); |
| std::unique_ptr<SigninCookieChangedSubscription> subscription( |
| new SigninCookieChangedSubscription(context_getter, url, name, callback)); |
| // TODO(crbug.com/703565): remove std::move() once Xcode 9.0+ is required. |
| return std::move(subscription); |
| } |
| |
| void SigninClientImpl::OnSignedIn(const std::string& account_id, |
| const std::string& gaia_id, |
| const std::string& username, |
| const std::string& password) { |
| ios::ChromeBrowserStateManager* browser_state_manager = |
| GetApplicationContext()->GetChromeBrowserStateManager(); |
| BrowserStateInfoCache* cache = |
| browser_state_manager->GetBrowserStateInfoCache(); |
| size_t index = cache->GetIndexOfBrowserStateWithPath( |
| browser_state_->GetOriginalChromeBrowserState()->GetStatePath()); |
| if (index != std::string::npos) { |
| cache->SetAuthInfoOfBrowserStateAtIndex(index, gaia_id, |
| base::UTF8ToUTF16(username)); |
| } |
| } |
| |
| void SigninClientImpl::OnErrorChanged() { |
| BrowserStateInfoCache* cache = GetApplicationContext() |
| ->GetChromeBrowserStateManager() |
| ->GetBrowserStateInfoCache(); |
| size_t index = cache->GetIndexOfBrowserStateWithPath( |
| browser_state_->GetOriginalChromeBrowserState()->GetStatePath()); |
| if (index == std::string::npos) |
| return; |
| |
| cache->SetBrowserStateIsAuthErrorAtIndex( |
| index, signin_error_controller_->HasError()); |
| } |
| |
| void SigninClientImpl::OnGetTokenInfoResponse( |
| std::unique_ptr<base::DictionaryValue> token_info) { |
| oauth_request_.reset(); |
| } |
| |
| void SigninClientImpl::OnOAuthError() { |
| // Ignore the failure. It's not essential and we'll try again next time. |
| oauth_request_.reset(); |
| } |
| |
| void SigninClientImpl::OnNetworkError(int response_code) { |
| // Ignore the failure. It's not essential and we'll try again next time. |
| oauth_request_.reset(); |
| } |
| |
| void SigninClientImpl::OnGetTokenSuccess( |
| const OAuth2TokenService::Request* request, |
| const std::string& access_token, |
| const base::Time& expiration_time) { |
| // Exchange the access token for a handle that can be used for later |
| // verification that the token is still valid (i.e. the password has not |
| // been changed). |
| if (!oauth_client_) { |
| oauth_client_.reset( |
| new gaia::GaiaOAuthClient(browser_state_->GetRequestContext())); |
| } |
| oauth_client_->GetTokenInfo(access_token, 3 /* retries */, this); |
| } |
| |
| void SigninClientImpl::OnGetTokenFailure( |
| const OAuth2TokenService::Request* request, |
| const GoogleServiceAuthError& error) { |
| // Ignore the failure. It's not essential and we'll try again next time. |
| oauth_request_.reset(); |
| } |
| |
| void SigninClientImpl::OnNetworkChanged( |
| net::NetworkChangeNotifier::ConnectionType type) { |
| if (type >= net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE) |
| return; |
| |
| for (const base::Closure& callback : delayed_callbacks_) |
| callback.Run(); |
| |
| delayed_callbacks_.clear(); |
| } |
| |
| void SigninClientImpl::DelayNetworkCall(const base::Closure& callback) { |
| // Don't bother if we don't have any kind of network connection. |
| if (net::NetworkChangeNotifier::IsOffline()) { |
| delayed_callbacks_.push_back(callback); |
| } else { |
| callback.Run(); |
| } |
| } |
| |
| std::unique_ptr<GaiaAuthFetcher> SigninClientImpl::CreateGaiaAuthFetcher( |
| GaiaAuthConsumer* consumer, |
| const std::string& source, |
| net::URLRequestContextGetter* getter) { |
| return base::MakeUnique<GaiaAuthFetcherIOS>(consumer, source, getter, |
| browser_state_); |
| } |