1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ios/chrome/browser/signin/signin_client_impl.h"
7 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/content_settings/core/browser/cookie_settings.h"
13 #include "components/keyed_service/core/service_access_type.h"
14 #include "components/metrics/metrics_service.h"
15 #include "components/signin/core/browser/profile_oauth2_token_service.h"
16 #include "components/signin/core/browser/signin_cookie_changed_subscription.h"
17 #include "components/signin/core/browser/signin_header_helper.h"
18 #include "components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h"
19 #include "google_apis/gaia/gaia_constants.h"
20 #include "google_apis/gaia/gaia_urls.h"
21 #include "ios/chrome/browser/application_context.h"
22 #include "ios/chrome/browser/content_settings/cookie_settings_factory.h"
23 #include "ios/chrome/browser/signin/gaia_auth_fetcher_ios.h"
24 #include "ios/chrome/browser/web_data_service_factory.h"
25 #include "ios/chrome/common/channel_info.h"
26 #include "ios/public/provider/chrome/browser/browser_state/browser_state_info_cache.h"
27 #include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h"
28 #include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h"
29 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
30 #include "net/url_request/url_request_context_getter.h"
33 SigninClientImpl::SigninClientImpl(
34 ios::ChromeBrowserState
* browser_state
,
35 SigninErrorController
* signin_error_controller
)
36 : OAuth2TokenService::Consumer("signin_client_impl"),
37 browser_state_(browser_state
),
38 signin_error_controller_(signin_error_controller
) {
39 signin_error_controller_
->AddObserver(this);
40 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
43 SigninClientImpl::~SigninClientImpl() {
44 signin_error_controller_
->RemoveObserver(this);
47 void SigninClientImpl::Shutdown() {
48 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
51 void SigninClientImpl::DoFinalInit() {
55 bool SigninClientImpl::AllowsSigninCookies(
56 ios::ChromeBrowserState
* browser_state
) {
57 scoped_refptr
<content_settings::CookieSettings
> cookie_settings
=
58 ios::CookieSettingsFactory::GetForBrowserState(browser_state
);
59 return signin::SettingsAllowSigninCookies(cookie_settings
.get());
62 PrefService
* SigninClientImpl::GetPrefs() {
63 return browser_state_
->GetPrefs();
66 scoped_refptr
<TokenWebData
> SigninClientImpl::GetDatabase() {
67 return ios::WebDataServiceFactory::GetTokenWebDataForBrowserState(
68 browser_state_
, ServiceAccessType::EXPLICIT_ACCESS
);
71 bool SigninClientImpl::CanRevokeCredentials() {
75 std::string
SigninClientImpl::GetSigninScopedDeviceId() {
76 return GetOrCreateScopedDeviceIdPref(GetPrefs());
79 void SigninClientImpl::OnSignedOut() {
80 ios::BrowserStateInfoCache
* cache
= GetApplicationContext()
81 ->GetChromeBrowserStateManager()
82 ->GetBrowserStateInfoCache();
83 size_t index
= cache
->GetIndexOfBrowserStateWithPath(
84 browser_state_
->GetOriginalChromeBrowserState()->GetStatePath());
86 // If sign out occurs because Sync setup was in progress and the browser state
87 // got deleted, then it is no longer in the cache.
88 if (index
== std::string::npos
)
91 cache
->SetLocalAuthCredentialsOfBrowserStateAtIndex(index
, std::string());
92 cache
->SetAuthInfoOfBrowserStateAtIndex(index
, std::string(),
94 cache
->SetBrowserStateSigninRequiredAtIndex(index
, false);
97 net::URLRequestContextGetter
* SigninClientImpl::GetURLRequestContext() {
98 return browser_state_
->GetRequestContext();
101 bool SigninClientImpl::ShouldMergeSigninCredentialsIntoCookieJar() {
105 std::string
SigninClientImpl::GetProductVersion() {
106 return GetVersionString();
109 bool SigninClientImpl::IsFirstRun() const {
113 base::Time
SigninClientImpl::GetInstallDate() {
114 return base::Time::FromTimeT(
115 GetApplicationContext()->GetMetricsService()->GetInstallDate());
118 bool SigninClientImpl::AreSigninCookiesAllowed() {
119 return AllowsSigninCookies(browser_state_
);
122 void SigninClientImpl::AddContentSettingsObserver(
123 content_settings::Observer
* observer
) {
124 browser_state_
->GetHostContentSettingsMap()->AddObserver(observer
);
127 void SigninClientImpl::RemoveContentSettingsObserver(
128 content_settings::Observer
* observer
) {
129 browser_state_
->GetHostContentSettingsMap()->RemoveObserver(observer
);
132 scoped_ptr
<SigninClient::CookieChangedSubscription
>
133 SigninClientImpl::AddCookieChangedCallback(
135 const std::string
& name
,
136 const net::CookieStore::CookieChangedCallback
& callback
) {
137 scoped_refptr
<net::URLRequestContextGetter
> context_getter
=
138 browser_state_
->GetRequestContext();
139 DCHECK(context_getter
.get());
140 scoped_ptr
<SigninCookieChangedSubscription
> subscription(
141 new SigninCookieChangedSubscription(context_getter
, url
, name
, callback
));
142 return subscription
.Pass();
145 void SigninClientImpl::OnSignedIn(const std::string
& account_id
,
146 const std::string
& gaia_id
,
147 const std::string
& username
,
148 const std::string
& password
) {
149 ios::ChromeBrowserStateManager
* browser_state_manager
=
150 GetApplicationContext()->GetChromeBrowserStateManager();
151 ios::BrowserStateInfoCache
* cache
=
152 browser_state_manager
->GetBrowserStateInfoCache();
153 size_t index
= cache
->GetIndexOfBrowserStateWithPath(
154 browser_state_
->GetOriginalChromeBrowserState()->GetStatePath());
155 if (index
!= std::string::npos
) {
156 cache
->SetAuthInfoOfBrowserStateAtIndex(index
, gaia_id
,
157 base::UTF8ToUTF16(username
));
161 // TODO(msarda): http://crbug.com/522454 The account info is seeded by the token
162 // service each timea new account is added. Remove the method
163 // UpdateAccountInfo| as it is now obsolete.
164 bool SigninClientImpl::UpdateAccountInfo(AccountInfo
* out_account_info
) {
165 DCHECK(!out_account_info
->account_id
.empty());
166 ProfileOAuth2TokenServiceIOSProvider
* provider
=
167 ios::GetChromeBrowserProvider()
168 ->GetProfileOAuth2TokenServiceIOSProvider();
169 ProfileOAuth2TokenServiceIOSProvider::AccountInfo account_info
;
170 if (!out_account_info
->gaia
.empty()) {
171 account_info
= provider
->GetAccountInfoForGaia(out_account_info
->gaia
);
172 } else if (!out_account_info
->email
.empty()) {
173 account_info
= provider
->GetAccountInfoForEmail(out_account_info
->email
);
175 if (account_info
.gaia
.empty()) {
176 // There is no account information for this account, so there is nothing
177 // to be updated here.
181 bool updated
= false;
182 if (out_account_info
->gaia
.empty()) {
183 out_account_info
->gaia
= account_info
.gaia
;
185 } else if (out_account_info
->gaia
!= account_info
.gaia
) {
186 // The GAIA id of an account never changes. Avoid updating the wrong
187 // account if this occurs somehow.
188 NOTREACHED() << "out_account_info->gaia = '" << out_account_info
->gaia
189 << "' ; account_info.gaia = '" << account_info
.gaia
<< "'";
192 if (out_account_info
->email
!= account_info
.email
) {
193 out_account_info
->email
= account_info
.email
;
199 void SigninClientImpl::OnErrorChanged() {
200 ios::BrowserStateInfoCache
* cache
= GetApplicationContext()
201 ->GetChromeBrowserStateManager()
202 ->GetBrowserStateInfoCache();
203 size_t index
= cache
->GetIndexOfBrowserStateWithPath(
204 browser_state_
->GetOriginalChromeBrowserState()->GetStatePath());
205 if (index
== std::string::npos
)
208 cache
->SetBrowserStateIsAuthErrorAtIndex(
209 index
, signin_error_controller_
->HasError());
212 void SigninClientImpl::OnGetTokenInfoResponse(
213 scoped_ptr
<base::DictionaryValue
> token_info
) {
214 if (!token_info
->HasKey("error")) {
216 if (token_info
->GetString("token_handle", &handle
)) {
217 ios::BrowserStateInfoCache
* cache
= GetApplicationContext()
218 ->GetChromeBrowserStateManager()
219 ->GetBrowserStateInfoCache();
220 size_t index
= cache
->GetIndexOfBrowserStateWithPath(
221 browser_state_
->GetOriginalChromeBrowserState()->GetStatePath());
222 cache
->SetPasswordChangeDetectionTokenAtIndex(index
, handle
);
227 oauth_request_
.reset();
230 void SigninClientImpl::OnOAuthError() {
231 // Ignore the failure. It's not essential and we'll try again next time.
232 oauth_request_
.reset();
235 void SigninClientImpl::OnNetworkError(int response_code
) {
236 // Ignore the failure. It's not essential and we'll try again next time.
237 oauth_request_
.reset();
240 void SigninClientImpl::OnGetTokenSuccess(
241 const OAuth2TokenService::Request
* request
,
242 const std::string
& access_token
,
243 const base::Time
& expiration_time
) {
244 // Exchange the access token for a handle that can be used for later
245 // verification that the token is still valid (i.e. the password has not
247 if (!oauth_client_
) {
249 new gaia::GaiaOAuthClient(browser_state_
->GetRequestContext()));
251 oauth_client_
->GetTokenInfo(access_token
, 3 /* retries */, this);
254 void SigninClientImpl::OnGetTokenFailure(
255 const OAuth2TokenService::Request
* request
,
256 const GoogleServiceAuthError
& error
) {
257 // Ignore the failure. It's not essential and we'll try again next time.
258 oauth_request_
.reset();
261 void SigninClientImpl::OnNetworkChanged(
262 net::NetworkChangeNotifier::ConnectionType type
) {
263 if (type
>= net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE
)
266 for (const base::Closure
& callback
: delayed_callbacks_
)
269 delayed_callbacks_
.clear();
272 void SigninClientImpl::DelayNetworkCall(const base::Closure
& callback
) {
273 // Don't bother if we don't have any kind of network connection.
274 if (net::NetworkChangeNotifier::IsOffline()) {
275 delayed_callbacks_
.push_back(callback
);
281 GaiaAuthFetcher
* SigninClientImpl::CreateGaiaAuthFetcher(
282 GaiaAuthConsumer
* consumer
,
283 const std::string
& source
,
284 net::URLRequestContextGetter
* getter
) {
285 return new GaiaAuthFetcherIOS(consumer
, source
, getter
, browser_state_
);