chrome_signin_client.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1// Copyright 2014 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.
4
5#include "chrome/browser/signin/chrome_signin_client.h"
6
7#include "base/command_line.h"
8#include "base/guid.h"
9#include "base/prefs/pref_service.h"
10#include "chrome/browser/chrome_notification_types.h"
11#include "chrome/browser/content_settings/cookie_settings.h"
12#include "chrome/browser/net/chrome_cookie_notification_details.h"
13#include "chrome/browser/signin/local_auth.h"
14#include "chrome/browser/webdata/web_data_service_factory.h"
15#include "chrome/common/chrome_version_info.h"
16#include "components/signin/core/common/profile_management_switches.h"
17#include "components/signin/core/common/signin_pref_names.h"
18#include "components/signin/core/common/signin_switches.h"
19#include "content/public/browser/notification_details.h"
20#include "content/public/browser/notification_source.h"
21#include "content/public/browser/render_process_host.h"
22#include "content/public/common/child_process_host.h"
23#include "url/gurl.h"
24
25#if defined(ENABLE_MANAGED_USERS)
26#include "chrome/browser/supervised_user/supervised_user_constants.h"
27#endif
28
29#if defined(OS_CHROMEOS)
30#include "components/user_manager/user_manager.h"
31#endif
32
33using content::ChildProcessHost;
34using content::RenderProcessHost;
35
36namespace {
37
38const char kGoogleAccountsUrl[] = "https://accounts.google.com";
39
40}  // namespace
41
42ChromeSigninClient::ChromeSigninClient(Profile* profile)
43    : profile_(profile), signin_host_id_(ChildProcessHost::kInvalidUniqueID) {
44  callbacks_.set_removal_callback(
45    base::Bind(&ChromeSigninClient::UnregisterForCookieChangedNotification,
46               base::Unretained(this)));
47}
48
49ChromeSigninClient::~ChromeSigninClient() {
50  UnregisterForCookieChangedNotification();
51
52  std::set<RenderProcessHost*>::iterator i;
53  for (i = signin_hosts_observed_.begin(); i != signin_hosts_observed_.end();
54       ++i) {
55    (*i)->RemoveObserver(this);
56  }
57}
58
59// static
60bool ChromeSigninClient::ProfileAllowsSigninCookies(Profile* profile) {
61  CookieSettings* cookie_settings =
62      CookieSettings::Factory::GetForProfile(profile).get();
63  return SettingsAllowSigninCookies(cookie_settings);
64}
65
66// static
67bool ChromeSigninClient::SettingsAllowSigninCookies(
68    CookieSettings* cookie_settings) {
69  return cookie_settings &&
70         cookie_settings->IsSettingCookieAllowed(GURL(kGoogleAccountsUrl),
71                                                 GURL(kGoogleAccountsUrl));
72}
73
74void ChromeSigninClient::SetSigninProcess(int process_id) {
75  if (process_id == signin_host_id_)
76    return;
77  DLOG_IF(WARNING, signin_host_id_ != ChildProcessHost::kInvalidUniqueID)
78      << "Replacing in-use signin process.";
79  signin_host_id_ = process_id;
80  RenderProcessHost* host = RenderProcessHost::FromID(process_id);
81  DCHECK(host);
82  host->AddObserver(this);
83  signin_hosts_observed_.insert(host);
84}
85
86void ChromeSigninClient::ClearSigninProcess() {
87  signin_host_id_ = ChildProcessHost::kInvalidUniqueID;
88}
89
90bool ChromeSigninClient::IsSigninProcess(int process_id) const {
91  return process_id != ChildProcessHost::kInvalidUniqueID &&
92         process_id == signin_host_id_;
93}
94
95bool ChromeSigninClient::HasSigninProcess() const {
96  return signin_host_id_ != ChildProcessHost::kInvalidUniqueID;
97}
98
99void ChromeSigninClient::RenderProcessHostDestroyed(RenderProcessHost* host) {
100  // It's possible we're listening to a "stale" renderer because it was replaced
101  // with a new process by process-per-site. In either case, stop observing it,
102  // but only reset signin_host_id_ tracking if this was from the current signin
103  // process.
104  signin_hosts_observed_.erase(host);
105  if (signin_host_id_ == host->GetID())
106    signin_host_id_ = ChildProcessHost::kInvalidUniqueID;
107}
108
109PrefService* ChromeSigninClient::GetPrefs() { return profile_->GetPrefs(); }
110
111scoped_refptr<TokenWebData> ChromeSigninClient::GetDatabase() {
112  return WebDataServiceFactory::GetTokenWebDataForProfile(
113      profile_, Profile::EXPLICIT_ACCESS);
114}
115
116bool ChromeSigninClient::CanRevokeCredentials() {
117#if defined(OS_CHROMEOS)
118  // UserManager may not exist in unit_tests.
119  if (user_manager::UserManager::IsInitialized() &&
120      user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser()) {
121    // Don't allow revoking credentials for Chrome OS supervised users.
122    // See http://crbug.com/332032
123    LOG(ERROR) << "Attempt to revoke supervised user refresh "
124               << "token detected, ignoring.";
125    return false;
126  }
127#else
128  // Don't allow revoking credentials for supervised users.
129  // See http://crbug.com/332032
130  if (profile_->IsSupervised()) {
131    LOG(ERROR) << "Attempt to revoke supervised user refresh "
132               << "token detected, ignoring.";
133    return false;
134  }
135#endif
136  return true;
137}
138
139std::string ChromeSigninClient::GetSigninScopedDeviceId() {
140  if (CommandLine::ForCurrentProcess()->HasSwitch(
141          switches::kDisableSigninScopedDeviceId)) {
142    return std::string();
143  }
144
145  std::string signin_scoped_device_id =
146      GetPrefs()->GetString(prefs::kGoogleServicesSigninScopedDeviceId);
147  if (signin_scoped_device_id.empty()) {
148    // If device_id doesn't exist then generate new and save in prefs.
149    signin_scoped_device_id = base::GenerateGUID();
150    DCHECK(!signin_scoped_device_id.empty());
151    GetPrefs()->SetString(prefs::kGoogleServicesSigninScopedDeviceId,
152                          signin_scoped_device_id);
153  }
154  return signin_scoped_device_id;
155}
156
157void ChromeSigninClient::ClearSigninScopedDeviceId() {
158  GetPrefs()->ClearPref(prefs::kGoogleServicesSigninScopedDeviceId);
159}
160
161net::URLRequestContextGetter* ChromeSigninClient::GetURLRequestContext() {
162  return profile_->GetRequestContext();
163}
164
165bool ChromeSigninClient::ShouldMergeSigninCredentialsIntoCookieJar() {
166  // If inline sign in is enabled, but account consistency is not, the user's
167  // credentials should be merge into the cookie jar.
168  return !switches::IsEnableWebBasedSignin() &&
169         !switches::IsEnableAccountConsistency();
170}
171
172std::string ChromeSigninClient::GetProductVersion() {
173  chrome::VersionInfo chrome_version;
174  if (!chrome_version.is_valid())
175    return "invalid";
176  return chrome_version.CreateVersionString();
177}
178
179scoped_ptr<SigninClient::CookieChangedCallbackList::Subscription>
180ChromeSigninClient::AddCookieChangedCallback(
181    const CookieChangedCallback& callback) {
182  scoped_ptr<SigninClient::CookieChangedCallbackList::Subscription>
183    subscription = callbacks_.Add(callback);
184  RegisterForCookieChangedNotification();
185  return subscription.Pass();
186}
187
188void ChromeSigninClient::GoogleSigninSucceeded(const std::string& username,
189                                               const std::string& password) {
190#if !defined(OS_ANDROID)
191  // Don't store password hash except for users of account consistency features.
192  if (switches::IsEnableAccountConsistency())
193    chrome::SetLocalAuthCredentials(profile_, password);
194#endif
195}
196
197void ChromeSigninClient::Observe(int type,
198                                 const content::NotificationSource& source,
199                                 const content::NotificationDetails& details) {
200  switch (type) {
201    case chrome::NOTIFICATION_COOKIE_CHANGED: {
202      DCHECK(!callbacks_.empty());
203      const net::CanonicalCookie* cookie =
204          content::Details<ChromeCookieDetails>(details).ptr()->cookie;
205      callbacks_.Notify(cookie);
206      break;
207    }
208    default:
209      NOTREACHED();
210      break;
211  }
212}
213
214void ChromeSigninClient::RegisterForCookieChangedNotification() {
215  if (callbacks_.empty())
216    return;
217  content::Source<Profile> source(profile_);
218  if (!registrar_.IsRegistered(
219      this, chrome::NOTIFICATION_COOKIE_CHANGED, source))
220  registrar_.Add(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
221}
222
223void ChromeSigninClient::UnregisterForCookieChangedNotification() {
224  if (!callbacks_.empty())
225    return;
226  // Note that it's allowed to call this method multiple times without an
227  // intervening call to |RegisterForCookieChangedNotification()|.
228  content::Source<Profile> source(profile_);
229  if (!registrar_.IsRegistered(
230      this, chrome::NOTIFICATION_COOKIE_CHANGED, source))
231    return;
232  registrar_.Remove(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
233}
234