Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(488)

Side by Side Diff: ios/chrome/browser/ui/authentication/authentication_flow_performer.mm

Issue 2586993002: Upstream Chrome on iOS source code [3/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #import "ios/chrome/browser/ui/authentication/authentication_flow_performer.h"
6
7 #include <memory>
8
9 #include "base/ios/block_types.h"
10 #include "base/ios/weak_nsobject.h"
11 #include "base/logging.h"
12 #include "base/mac/bind_objc_block.h"
13 #include "base/mac/scoped_nsobject.h"
14 #include "base/metrics/user_metrics.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "base/time/time.h"
17 #include "base/timer/timer.h"
18 #include "components/prefs/pref_service.h"
19 #include "components/signin/core/browser/account_tracker_service.h"
20 #include "components/signin/core/browser/signin_manager.h"
21 #include "components/signin/core/common/signin_pref_names.h"
22 #include "components/strings/grit/components_strings.h"
23 #include "google_apis/gaia/gaia_auth_util.h"
24 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
25 #include "ios/chrome/browser/experimental_flags.h"
26 #include "ios/chrome/browser/signin/account_tracker_service_factory.h"
27 #include "ios/chrome/browser/signin/authentication_service.h"
28 #include "ios/chrome/browser/signin/authentication_service_factory.h"
29 #import "ios/chrome/browser/signin/browser_state_data_remover.h"
30 #import "ios/chrome/browser/signin/constants.h"
31 #include "ios/chrome/browser/signin/signin_manager_factory.h"
32 #include "ios/chrome/browser/sync/sync_setup_service.h"
33 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
34 #include "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
35 #import "ios/chrome/browser/ui/authentication/authentication_ui_util.h"
36 #import "ios/chrome/browser/ui/settings/import_data_collection_view_controller.h "
37 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
38 #include "ios/chrome/grit/ios_chromium_strings.h"
39 #include "ios/chrome/grit/ios_strings.h"
40 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
41 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
42 #include "ui/base/l10n/l10n_util.h"
43
44 using signin_ui::CompletionCallback;
45
46 namespace {
47
48 const int64_t kAuthenticationFlowTimeoutSeconds = 10;
49
50 } // namespace
51
52 @interface AuthenticationFlowPerformer ()<ImportDataControllerDelegate,
53 SettingsNavigationControllerDelegate>
54
55 // Starts the watchdog timer with a timeout of
56 // |kAuthenticationFlowTimeoutSeconds| for the fetching managed status
57 // operation. It will notify |_delegate| of the failure unless
58 // |stopWatchdogTimer| is called before it times out.
59 - (void)startWatchdogTimerForManagedStatus;
60
61 // Stops the watchdog timer, and doesn't call the |timeoutDelegateSelector|.
62 // Returns whether the watchdog was actually running.
63 - (BOOL)stopWatchdogTimer;
64
65 // Callback for when the alert is dismissed.
66 - (void)alertControllerDidDisappear:(AlertCoordinator*)alertCoordinator;
67
68 @end
69
70 @implementation AuthenticationFlowPerformer {
71 base::WeakNSProtocol<id<AuthenticationFlowPerformerDelegate>> _delegate;
72 base::scoped_nsobject<AlertCoordinator> _alertCoordinator;
73 base::scoped_nsobject<SettingsNavigationController> _navigationController;
74 std::unique_ptr<base::Timer> _watchdogTimer;
75 }
76
77 - (id<AuthenticationFlowPerformerDelegate>)delegate {
78 return _delegate.get();
79 }
80
81 - (instancetype)initWithDelegate:
82 (id<AuthenticationFlowPerformerDelegate>)delegate {
83 self = [super init];
84 if (self)
85 _delegate.reset(delegate);
86 return self;
87 }
88
89 - (void)cancelAndDismiss {
90 [_alertCoordinator executeCancelHandler];
91 [_alertCoordinator stop];
92 if (_navigationController) {
93 [_navigationController settingsWillBeDismissed];
94 _navigationController.reset();
95 [[_delegate presentingViewController] dismissViewControllerAnimated:NO
96 completion:nil];
97 }
98 [self stopWatchdogTimer];
99 }
100
101 - (void)commitSyncForBrowserState:(ios::ChromeBrowserState*)browserState {
102 SyncSetupServiceFactory::GetForBrowserState(browserState)->CommitChanges();
103 }
104
105 - (void)startWatchdogTimerForManagedStatus {
106 base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
107 ProceduralBlock onTimeout = ^{
108 base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
109 [weakSelf retain]);
110 if (!strongSelf)
111 return;
112 [strongSelf stopWatchdogTimer];
113 NSError* error = [NSError errorWithDomain:kAuthenticationErrorDomain
114 code:TIMED_OUT_FETCH_POLICY
115 userInfo:nil];
116 [strongSelf.get()->_delegate didFailFetchManagedStatus:error];
117 };
118 _watchdogTimer.reset(new base::Timer(false, false));
119 _watchdogTimer->Start(FROM_HERE, base::TimeDelta::FromSeconds(
120 kAuthenticationFlowTimeoutSeconds),
121 base::BindBlock(onTimeout));
122 }
123
124 - (BOOL)stopWatchdogTimer {
125 if (_watchdogTimer) {
126 _watchdogTimer->Stop();
127 _watchdogTimer.reset();
128 return YES;
129 }
130 return NO;
131 }
132
133 - (void)fetchManagedStatus:(ios::ChromeBrowserState*)browserState
134 forIdentity:(ChromeIdentity*)identity {
135 if (!experimental_flags::IsMDMIntegrationEnabled()) {
136 [_delegate didFetchManagedStatus:nil];
137 return;
138 }
139 if (gaia::ExtractDomainName(gaia::CanonicalizeEmail(
140 base::SysNSStringToUTF8(identity.userEmail))) == "gmail.com") {
141 // Do nothing for @gmail.com addresses as they can't have a hosted domain.
142 // This avoids waiting for this step to complete (and a network call).
143 [_delegate didFetchManagedStatus:nil];
144 return;
145 }
146
147 [self startWatchdogTimerForManagedStatus];
148 base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
149 ios::GetChromeBrowserProvider()
150 ->GetChromeIdentityService()
151 ->GetHostedDomainForIdentity(
152 identity, ^(NSString* hosted_domain, NSError* error) {
153 [weakSelf handleGetHostedDomain:hosted_domain
154 error:error
155 browserState:browserState];
156 });
157 }
158
159 - (void)handleGetHostedDomain:(NSString*)hostedDomain
160 error:(NSError*)error
161 browserState:(ios::ChromeBrowserState*)browserState {
162 if (![self stopWatchdogTimer]) {
163 // Watchdog timer has already fired, don't notify the delegate.
164 return;
165 }
166 if (error) {
167 [_delegate didFailFetchManagedStatus:error];
168 return;
169 }
170 [_delegate didFetchManagedStatus:hostedDomain];
171 }
172
173 - (void)signInIdentity:(ChromeIdentity*)identity
174 withHostedDomain:(NSString*)hostedDomain
175 toBrowserState:(ios::ChromeBrowserState*)browserState {
176 AuthenticationServiceFactory::GetForBrowserState(browserState)
177 ->SignIn(identity, base::SysNSStringToUTF8(hostedDomain));
178 }
179
180 - (void)signOutBrowserState:(ios::ChromeBrowserState*)browserState {
181 AuthenticationServiceFactory::GetForBrowserState(browserState)
182 ->SignOut(signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, ^{
183 [_delegate didSignOut];
184 });
185 }
186
187 - (void)signOutImmediatelyFromBrowserState:
188 (ios::ChromeBrowserState*)browserState {
189 AuthenticationServiceFactory::GetForBrowserState(browserState)
190 ->SignOut(signin_metrics::ABORT_SIGNIN, nil);
191 }
192
193 - (void)promptSwitchFromManagedEmail:(NSString*)managedEmail
194 withHostedDomain:(NSString*)hostedDomain
195 toEmail:(NSString*)toEmail
196 viewController:(UIViewController*)viewController {
197 DCHECK(!_alertCoordinator);
198 NSString* title = l10n_util::GetNSString(IDS_IOS_MANAGED_SWITCH_TITLE);
199 NSString* subtitle = l10n_util::GetNSStringF(
200 IDS_IOS_MANAGED_SWITCH_SUBTITLE, base::SysNSStringToUTF16(managedEmail),
201 base::SysNSStringToUTF16(toEmail),
202 base::SysNSStringToUTF16(hostedDomain));
203 NSString* acceptLabel =
204 l10n_util::GetNSString(IDS_IOS_MANAGED_SWITCH_ACCEPT_BUTTON);
205 NSString* cancelLabel = l10n_util::GetNSString(IDS_CANCEL);
206
207 _alertCoordinator.reset([[AlertCoordinator alloc]
208 initWithBaseViewController:viewController
209 title:title
210 message:subtitle]);
211
212 base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
213 base::WeakNSObject<AlertCoordinator> weakAlert(_alertCoordinator);
214 ProceduralBlock acceptBlock = ^{
215 base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
216 [weakSelf retain]);
217 if (!strongSelf)
218 return;
219 [[strongSelf delegate]
220 didChooseClearDataPolicy:SHOULD_CLEAR_DATA_CLEAR_DATA];
221 [strongSelf alertControllerDidDisappear:weakAlert];
222 };
223 ProceduralBlock cancelBlock = ^{
224 base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
225 [weakSelf retain]);
226 if (!strongSelf)
227 return;
228 [[strongSelf delegate] didChooseCancel];
229 [strongSelf alertControllerDidDisappear:weakAlert];
230 };
231
232 [_alertCoordinator addItemWithTitle:cancelLabel
233 action:cancelBlock
234 style:UIAlertActionStyleCancel];
235 [_alertCoordinator addItemWithTitle:acceptLabel
236 action:acceptBlock
237 style:UIAlertActionStyleDefault];
238 [_alertCoordinator setCancelAction:cancelBlock];
239 [_alertCoordinator start];
240 }
241
242 - (void)promptMergeCaseForIdentity:(ChromeIdentity*)identity
243 browserState:(ios::ChromeBrowserState*)browserState
244 viewController:(UIViewController*)viewController {
245 BOOL isSignedIn = YES;
246 NSString* lastSignedInEmail =
247 [AuthenticationServiceFactory::GetForBrowserState(browserState)
248 ->GetAuthenticatedIdentity() userEmail];
249 if (!lastSignedInEmail) {
250 lastSignedInEmail =
251 base::SysUTF8ToNSString(browserState->GetPrefs()->GetString(
252 prefs::kGoogleServicesLastUsername));
253 isSignedIn = NO;
254 }
255
256 if (AuthenticationServiceFactory::GetForBrowserState(browserState)
257 ->IsAuthenticatedIdentityManaged()) {
258 NSString* hostedDomain = base::SysUTF8ToNSString(
259 ios::SigninManagerFactory::GetForBrowserState(browserState)
260 ->GetAuthenticatedAccountInfo()
261 .hosted_domain);
262 [self promptSwitchFromManagedEmail:lastSignedInEmail
263 withHostedDomain:hostedDomain
264 toEmail:[identity userEmail]
265 viewController:viewController];
266 return;
267 }
268 _navigationController.reset([SettingsNavigationController
269 newImportDataController:browserState
270 delegate:self
271 importDataDelegate:self
272 fromEmail:lastSignedInEmail
273 toEmail:[identity userEmail]
274 isSignedIn:isSignedIn]);
275 [_navigationController setShouldCommitSyncChangesOnDismissal:NO];
276 [[_delegate presentingViewController]
277 presentViewController:_navigationController
278 animated:YES
279 completion:nil];
280 }
281
282 - (void)clearData:(ios::ChromeBrowserState*)browserState {
283 DCHECK(!AuthenticationServiceFactory::GetForBrowserState(browserState)
284 ->GetAuthenticatedUserEmail());
285 BrowserStateDataRemover::ClearData(browserState, ^{
286 [_delegate didClearData];
287 });
288 }
289
290 - (BOOL)shouldHandleMergeCaseForIdentity:(ChromeIdentity*)identity
291 browserState:
292 (ios::ChromeBrowserState*)browserState {
293 std::string lastSignedInAccountId =
294 browserState->GetPrefs()->GetString(prefs::kGoogleServicesLastAccountId);
295 std::string currentSignedInAccountId =
296 ios::AccountTrackerServiceFactory::GetForBrowserState(browserState)
297 ->PickAccountIdForAccount(
298 base::SysNSStringToUTF8([identity gaiaID]),
299 base::SysNSStringToUTF8([identity userEmail]));
300 if (!lastSignedInAccountId.empty()) {
301 // Merge case exists if the id of the previously signed in account is
302 // different from the one of the account being signed in.
303 return lastSignedInAccountId != currentSignedInAccountId;
304 }
305
306 // kGoogleServicesLastAccountId pref might not have been populated yet,
307 // check the old kGoogleServicesLastUsername pref.
308 std::string lastSignedInEmail =
309 browserState->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername);
310 std::string currentSignedInEmail =
311 base::SysNSStringToUTF8([identity userEmail]);
312 return !lastSignedInEmail.empty() &&
313 !gaia::AreEmailsSame(currentSignedInEmail, lastSignedInEmail);
314 }
315
316 - (void)showManagedConfirmationForHostedDomain:(NSString*)hostedDomain
317 viewController:
318 (UIViewController*)viewController {
319 DCHECK(!_alertCoordinator);
320 NSString* title = l10n_util::GetNSString(IDS_IOS_MANAGED_SIGNIN_TITLE);
321 NSString* subtitle = l10n_util::GetNSStringF(
322 IDS_IOS_MANAGED_SIGNIN_SUBTITLE, base::SysNSStringToUTF16(hostedDomain));
323 NSString* acceptLabel =
324 l10n_util::GetNSString(IDS_IOS_MANAGED_SIGNIN_ACCEPT_BUTTON);
325 NSString* cancelLabel = l10n_util::GetNSString(IDS_CANCEL);
326
327 _alertCoordinator.reset([[AlertCoordinator alloc]
328 initWithBaseViewController:viewController
329 title:title
330 message:subtitle]);
331
332 base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
333 base::WeakNSObject<AlertCoordinator> weakAlert(_alertCoordinator);
334 ProceduralBlock acceptBlock = ^{
335 base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
336 [weakSelf retain]);
337 if (!strongSelf)
338 return;
339 [[strongSelf delegate] didAcceptManagedConfirmation];
340 [strongSelf alertControllerDidDisappear:weakAlert];
341 };
342 ProceduralBlock cancelBlock = ^{
343 base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
344 [weakSelf retain]);
345 if (!strongSelf)
346 return;
347 [[strongSelf delegate] didCancelManagedConfirmation];
348 [strongSelf alertControllerDidDisappear:weakAlert];
349 };
350
351 [_alertCoordinator addItemWithTitle:cancelLabel
352 action:cancelBlock
353 style:UIAlertActionStyleCancel];
354 [_alertCoordinator addItemWithTitle:acceptLabel
355 action:acceptBlock
356 style:UIAlertActionStyleDefault];
357 [_alertCoordinator setCancelAction:cancelBlock];
358 [_alertCoordinator start];
359 }
360
361 - (void)showAuthenticationError:(NSError*)error
362 withCompletion:(ProceduralBlock)callback
363 viewController:(UIViewController*)viewController {
364 DCHECK(!_alertCoordinator);
365
366 _alertCoordinator.reset(
367 [ios_internal::ErrorCoordinatorNoItem(error, viewController) retain]);
368
369 base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
370 base::WeakNSObject<AlertCoordinator> weakAlert(_alertCoordinator);
371 ProceduralBlock dismissAction = ^{
372 if (callback)
373 callback();
374 [weakSelf alertControllerDidDisappear:weakAlert];
375 };
376
377 NSString* okButtonLabel = l10n_util::GetNSString(IDS_OK);
378 [_alertCoordinator addItemWithTitle:okButtonLabel
379 action:dismissAction
380 style:UIAlertActionStyleDefault];
381
382 [_alertCoordinator setCancelAction:dismissAction];
383
384 [_alertCoordinator start];
385 }
386
387 - (void)alertControllerDidDisappear:(AlertCoordinator*)alertCoordinator {
388 if (_alertCoordinator.get() != alertCoordinator) {
389 // Do not reset the |_alertCoordinator| if it has changed. This typically
390 // happens when the user taps on any of the actions on "Clear Data Before
391 // Syncing?" dialog, as the sign-in confirmation dialog is created before
392 // the "Clear Data Before Syncing?" dialog is dismissed.
393 return;
394 }
395 _alertCoordinator.reset();
396 }
397
398 #pragma mark - ImportDataControllerDelegate
399
400 - (void)didChooseClearDataPolicy:(ImportDataCollectionViewController*)controller
401 shouldClearData:(ShouldClearData)shouldClearData {
402 DCHECK_NE(SHOULD_CLEAR_DATA_USER_CHOICE, shouldClearData);
403 if (shouldClearData == SHOULD_CLEAR_DATA_CLEAR_DATA) {
404 base::RecordAction(
405 base::UserMetricsAction("Signin_ImportDataPrompt_DontImport"));
406 } else {
407 base::RecordAction(
408 base::UserMetricsAction("Signin_ImportDataPrompt_ImportData"));
409 }
410
411 base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
412 ProceduralBlock block = ^{
413 base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
414 [weakSelf retain]);
415 if (!strongSelf)
416 return;
417 strongSelf.get()->_navigationController.reset();
418 [[strongSelf delegate] didChooseClearDataPolicy:shouldClearData];
419 };
420 [_navigationController settingsWillBeDismissed];
421 [[_delegate presentingViewController] dismissViewControllerAnimated:YES
422 completion:block];
423 }
424
425 #pragma mark - SettingsNavigationControllerDelegate
426
427 - (void)closeSettings {
428 base::RecordAction(base::UserMetricsAction("Signin_ImportDataPrompt_Cancel"));
429
430 base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
431 ProceduralBlock block = ^{
432 base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
433 [weakSelf retain]);
434 if (!strongSelf)
435 return;
436 strongSelf.get()->_navigationController.reset();
437 [[strongSelf delegate] didChooseCancel];
438 };
439 [_navigationController settingsWillBeDismissed];
440 [[_delegate presentingViewController] dismissViewControllerAnimated:YES
441 completion:block];
442 }
443
444 - (void)closeSettingsAndOpenNewIncognitoTab {
445 NOTREACHED();
446 }
447
448 - (void)closeSettingsAndOpenUrl:(OpenUrlCommand*)command {
449 NOTREACHED();
450 }
451
452 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698