1 // Copyright 2017 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/signin_util.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/macros.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/task/post_task.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/policy/cloud/user_policy_signin_service_internal.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/profiles/profiles_state.h"
19 #include "chrome/browser/signin/identity_manager_factory.h"
20 #include "chrome/browser/ui/simple_message_box.h"
21 #include "chrome/browser/ui/startup/startup_types.h"
22 #include "chrome/browser/ui/webui/profile_helper.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/common/url_constants.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "components/google/core/common/google_util.h"
27 #include "components/prefs/pref_service.h"
28 #include "components/signin/public/base/signin_metrics.h"
29 #include "components/signin/public/base/signin_pref_names.h"
30 #include "components/signin/public/identity_manager/identity_manager.h"
31 #include "components/signin/public/identity_manager/identity_utils.h"
32 #include "components/signin/public/identity_manager/primary_account_mutator.h"
33 #include "google_apis/gaia/gaia_auth_util.h"
34 #include "ui/base/l10n/l10n_util.h"
35
36 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD) || \
37 defined(OS_MAC)
38 #include "chrome/browser/ui/browser_finder.h"
39 #include "chrome/browser/ui/browser_list.h"
40 #include "chrome/browser/ui/browser_list_observer.h"
41 #include "chrome/browser/ui/browser_window.h"
42 #define CAN_DELETE_PROFILE
43 #endif
44
45 namespace signin_util {
46 namespace {
47
48 constexpr char kSignoutSettingKey[] = "signout_setting";
49 constexpr char kGuestSignedInUserDataKey[] = "guest_signin";
50
51 #if defined(CAN_DELETE_PROFILE)
52 // Manager that presents the profile will be deleted dialog on the first active
53 // browser window.
54 class DeleteProfileDialogManager : public BrowserListObserver {
55 public:
56 class Delegate {
57 public:
58 // Called when the profile was marked for deletion. It is safe for the
59 // delegate to delete |manager| when this is called.
60 virtual void OnProfileDeleted(DeleteProfileDialogManager* manager) = 0;
61 };
62
DeleteProfileDialogManager(Profile * profile,std::string primary_account_email,Delegate * delegate)63 DeleteProfileDialogManager(Profile* profile,
64 std::string primary_account_email,
65 Delegate* delegate)
66 : profile_(profile),
67 primary_account_email_(primary_account_email),
68 delegate_(delegate) {}
69
~DeleteProfileDialogManager()70 ~DeleteProfileDialogManager() override { BrowserList::RemoveObserver(this); }
71
PresentDialogOnAllBrowserWindows()72 void PresentDialogOnAllBrowserWindows() {
73 BrowserList::AddObserver(this);
74 Browser* active_browser = chrome::FindLastActiveWithProfile(profile_);
75 if (active_browser)
76 OnBrowserSetLastActive(active_browser);
77 }
78
OnBrowserSetLastActive(Browser * browser)79 void OnBrowserSetLastActive(Browser* browser) override {
80 DCHECK(profile_);
81 if (browser->profile() != profile_)
82 return;
83
84 DCHECK(browser->window()->GetNativeWindow());
85 chrome::ShowWarningMessageBox(
86 browser->window()->GetNativeWindow(),
87 l10n_util::GetStringUTF16(IDS_PROFILE_WILL_BE_DELETED_DIALOG_TITLE),
88 l10n_util::GetStringFUTF16(
89 IDS_PROFILE_WILL_BE_DELETED_DIALOG_DESCRIPTION,
90 base::ASCIIToUTF16(primary_account_email_),
91 base::ASCIIToUTF16(
92 gaia::ExtractDomainName(primary_account_email_))));
93
94 webui::DeleteProfileAtPath(
95 profile_->GetPath(),
96 ProfileMetrics::DELETE_PROFILE_PRIMARY_ACCOUNT_NOT_ALLOWED);
97 delegate_->OnProfileDeleted(this);
98 }
99
100 private:
101 Profile* profile_;
102 std::string primary_account_email_;
103 Delegate* delegate_;
104
105 DISALLOW_COPY_AND_ASSIGN(DeleteProfileDialogManager);
106 };
107 #endif // defined(CAN_DELETE_PROFILE)
108
109 // Per-profile manager for the signout allowed setting.
110 #if defined(CAN_DELETE_PROFILE)
111 class UserSignoutSetting : public base::SupportsUserData::Data,
112 public DeleteProfileDialogManager::Delegate {
113 #else
114 class UserSignoutSetting : public base::SupportsUserData::Data {
115 #endif // defined(CAN_DELETE_PROFILE)
116 public:
117 enum class State { kUndefined, kAllowed, kDisallowed };
118
119 // Fetch from Profile. Make and store if not already present.
GetForProfile(Profile * profile)120 static UserSignoutSetting* GetForProfile(Profile* profile) {
121 UserSignoutSetting* signout_setting = static_cast<UserSignoutSetting*>(
122 profile->GetUserData(kSignoutSettingKey));
123
124 if (!signout_setting) {
125 profile->SetUserData(kSignoutSettingKey,
126 std::make_unique<UserSignoutSetting>());
127 signout_setting = static_cast<UserSignoutSetting*>(
128 profile->GetUserData(kSignoutSettingKey));
129 }
130
131 return signout_setting;
132 }
133
state() const134 State state() const { return state_; }
set_state(State state)135 void set_state(State state) { state_ = state; }
136
137 #if defined(CAN_DELETE_PROFILE)
138 // Shows the delete profile dialog on the first browser active window.
ShowDeleteProfileDialog(Profile * profile,const std::string & email)139 void ShowDeleteProfileDialog(Profile* profile, const std::string& email) {
140 if (delete_profile_dialog_manager_)
141 return;
142 delete_profile_dialog_manager_ =
143 std::make_unique<DeleteProfileDialogManager>(profile, email, this);
144 delete_profile_dialog_manager_->PresentDialogOnAllBrowserWindows();
145 }
146
OnProfileDeleted(DeleteProfileDialogManager * dialog_manager)147 void OnProfileDeleted(DeleteProfileDialogManager* dialog_manager) override {
148 DCHECK_EQ(delete_profile_dialog_manager_.get(), dialog_manager);
149 delete_profile_dialog_manager_.reset();
150 }
151 #endif
152
153 private:
154 State state_ = State::kUndefined;
155
156 #if defined(CAN_DELETE_PROFILE)
157 std::unique_ptr<DeleteProfileDialogManager> delete_profile_dialog_manager_;
158 #endif
159 };
160
161 enum ForceSigninPolicyCache {
162 NOT_CACHED = 0,
163 ENABLE,
164 DISABLE
165 } g_is_force_signin_enabled_cache = NOT_CACHED;
166
SetForceSigninPolicy(bool enable)167 void SetForceSigninPolicy(bool enable) {
168 g_is_force_signin_enabled_cache = enable ? ENABLE : DISABLE;
169 }
170
171 } // namespace
172
IsForceSigninEnabled()173 bool IsForceSigninEnabled() {
174 if (g_is_force_signin_enabled_cache == NOT_CACHED) {
175 PrefService* prefs = g_browser_process->local_state();
176 if (prefs)
177 SetForceSigninPolicy(prefs->GetBoolean(prefs::kForceBrowserSignin));
178 else
179 return false;
180 }
181 return (g_is_force_signin_enabled_cache == ENABLE);
182 }
183
SetForceSigninForTesting(bool enable)184 void SetForceSigninForTesting(bool enable) {
185 SetForceSigninPolicy(enable);
186 }
187
ResetForceSigninForTesting()188 void ResetForceSigninForTesting() {
189 g_is_force_signin_enabled_cache = NOT_CACHED;
190 }
191
IsUserSignoutAllowedForProfile(Profile * profile)192 bool IsUserSignoutAllowedForProfile(Profile* profile) {
193 return UserSignoutSetting::GetForProfile(profile)->state() ==
194 UserSignoutSetting::State::kAllowed;
195 }
196
EnsureUserSignoutAllowedIsInitializedForProfile(Profile * profile)197 void EnsureUserSignoutAllowedIsInitializedForProfile(Profile* profile) {
198 if (UserSignoutSetting::GetForProfile(profile)->state() ==
199 UserSignoutSetting::State::kUndefined) {
200 SetUserSignoutAllowedForProfile(profile, true);
201 }
202 }
203
SetUserSignoutAllowedForProfile(Profile * profile,bool is_allowed)204 void SetUserSignoutAllowedForProfile(Profile* profile, bool is_allowed) {
205 UserSignoutSetting::State new_state =
206 is_allowed ? UserSignoutSetting::State::kAllowed
207 : UserSignoutSetting::State::kDisallowed;
208 UserSignoutSetting::GetForProfile(profile)->set_state(new_state);
209 }
210
EnsurePrimaryAccountAllowedForProfile(Profile * profile)211 void EnsurePrimaryAccountAllowedForProfile(Profile* profile) {
212 // All primary accounts are allowed on ChromeOS, so this method is a no-op on
213 // ChromeOS.
214 #if !defined(OS_CHROMEOS)
215 auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
216 if (!identity_manager->HasPrimaryAccount())
217 return;
218
219 CoreAccountInfo primary_account = identity_manager->GetPrimaryAccountInfo();
220 if (profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed) &&
221 signin::IsUsernameAllowedByPatternFromPrefs(
222 g_browser_process->local_state(), primary_account.email)) {
223 return;
224 }
225
226 UserSignoutSetting* signout_setting =
227 UserSignoutSetting::GetForProfile(profile);
228 switch (signout_setting->state()) {
229 case UserSignoutSetting::State::kUndefined:
230 NOTREACHED();
231 break;
232 case UserSignoutSetting::State::kAllowed: {
233 // Force clear the primary account if it is no longer allowed and if sign
234 // out is allowed.
235 auto* primary_account_mutator =
236 identity_manager->GetPrimaryAccountMutator();
237 primary_account_mutator->ClearPrimaryAccount(
238 signin::PrimaryAccountMutator::ClearAccountsAction::kDefault,
239 signin_metrics::SIGNIN_NOT_ALLOWED_ON_PROFILE_INIT,
240 signin_metrics::SignoutDelete::IGNORE_METRIC);
241 break;
242 }
243 case UserSignoutSetting::State::kDisallowed:
244 #if defined(CAN_DELETE_PROFILE)
245 // Force remove the profile if sign out is not allowed and if the
246 // primary account is no longer allowed.
247 // This may be called while the profile is initializing, so it must be
248 // scheduled for later to allow the profile initialization to complete.
249 CHECK(profiles::IsMultipleProfilesEnabled());
250 base::ThreadTaskRunnerHandle::Get()->PostTask(
251 FROM_HERE,
252 base::BindOnce(&UserSignoutSetting::ShowDeleteProfileDialog,
253 base::Unretained(signout_setting), profile,
254 primary_account.email));
255 #else
256 CHECK(false) << "Deleting profiles is not supported.";
257 #endif // defined(CAN_DELETE_PROFILE)
258 break;
259 }
260 #endif // !defined(OS_CHROMEOS)
261 }
262
263 // TODO(crbug.com/1134111): Remove GuestSignedInUserData when Ephemeral Guest
264 // sign in functioncality is implemented.
SetIsSignedIn(Profile * profile,bool is_signed_in)265 void GuestSignedInUserData::SetIsSignedIn(Profile* profile, bool is_signed_in) {
266 GuestSignedInUserData* data = GetForProfile(profile);
267 data->is_signed_in_ = is_signed_in;
268 }
269
IsSignedIn(Profile * profile)270 bool GuestSignedInUserData::IsSignedIn(Profile* profile) {
271 return GetForProfile(profile)->is_signed_in_;
272 }
273
GetForProfile(Profile * profile)274 GuestSignedInUserData* GuestSignedInUserData::GetForProfile(Profile* profile) {
275 GuestSignedInUserData* data = static_cast<GuestSignedInUserData*>(
276 profile->GetUserData(kGuestSignedInUserDataKey));
277 if (!data) {
278 profile->SetUserData(kGuestSignedInUserDataKey,
279 std::make_unique<GuestSignedInUserData>());
280 data = static_cast<GuestSignedInUserData*>(
281 profile->GetUserData(kGuestSignedInUserDataKey));
282 }
283 return data;
284 }
285
286 } // namespace signin_util
287