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