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