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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
new file mode 100644
index 0000000000000000000000000000000000000000..6600833e43476a5922757b831fea273eb706f2dc
--- /dev/null
+++ b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
@@ -0,0 +1,452 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/authentication/authentication_flow_performer.h"
+
+#include <memory>
+
+#include "base/ios/block_types.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/metrics/user_metrics.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/common/signin_pref_names.h"
+#include "components/strings/grit/components_strings.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/signin/account_tracker_service_factory.h"
+#include "ios/chrome/browser/signin/authentication_service.h"
+#include "ios/chrome/browser/signin/authentication_service_factory.h"
+#import "ios/chrome/browser/signin/browser_state_data_remover.h"
+#import "ios/chrome/browser/signin/constants.h"
+#include "ios/chrome/browser/signin/signin_manager_factory.h"
+#include "ios/chrome/browser/sync/sync_setup_service.h"
+#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
+#include "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
+#import "ios/chrome/browser/ui/authentication/authentication_ui_util.h"
+#import "ios/chrome/browser/ui/settings/import_data_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
+#include "ios/chrome/grit/ios_chromium_strings.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using signin_ui::CompletionCallback;
+
+namespace {
+
+const int64_t kAuthenticationFlowTimeoutSeconds = 10;
+
+} // namespace
+
+@interface AuthenticationFlowPerformer ()<ImportDataControllerDelegate,
+ SettingsNavigationControllerDelegate>
+
+// Starts the watchdog timer with a timeout of
+// |kAuthenticationFlowTimeoutSeconds| for the fetching managed status
+// operation. It will notify |_delegate| of the failure unless
+// |stopWatchdogTimer| is called before it times out.
+- (void)startWatchdogTimerForManagedStatus;
+
+// Stops the watchdog timer, and doesn't call the |timeoutDelegateSelector|.
+// Returns whether the watchdog was actually running.
+- (BOOL)stopWatchdogTimer;
+
+// Callback for when the alert is dismissed.
+- (void)alertControllerDidDisappear:(AlertCoordinator*)alertCoordinator;
+
+@end
+
+@implementation AuthenticationFlowPerformer {
+ base::WeakNSProtocol<id<AuthenticationFlowPerformerDelegate>> _delegate;
+ base::scoped_nsobject<AlertCoordinator> _alertCoordinator;
+ base::scoped_nsobject<SettingsNavigationController> _navigationController;
+ std::unique_ptr<base::Timer> _watchdogTimer;
+}
+
+- (id<AuthenticationFlowPerformerDelegate>)delegate {
+ return _delegate.get();
+}
+
+- (instancetype)initWithDelegate:
+ (id<AuthenticationFlowPerformerDelegate>)delegate {
+ self = [super init];
+ if (self)
+ _delegate.reset(delegate);
+ return self;
+}
+
+- (void)cancelAndDismiss {
+ [_alertCoordinator executeCancelHandler];
+ [_alertCoordinator stop];
+ if (_navigationController) {
+ [_navigationController settingsWillBeDismissed];
+ _navigationController.reset();
+ [[_delegate presentingViewController] dismissViewControllerAnimated:NO
+ completion:nil];
+ }
+ [self stopWatchdogTimer];
+}
+
+- (void)commitSyncForBrowserState:(ios::ChromeBrowserState*)browserState {
+ SyncSetupServiceFactory::GetForBrowserState(browserState)->CommitChanges();
+}
+
+- (void)startWatchdogTimerForManagedStatus {
+ base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
+ ProceduralBlock onTimeout = ^{
+ base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ [strongSelf stopWatchdogTimer];
+ NSError* error = [NSError errorWithDomain:kAuthenticationErrorDomain
+ code:TIMED_OUT_FETCH_POLICY
+ userInfo:nil];
+ [strongSelf.get()->_delegate didFailFetchManagedStatus:error];
+ };
+ _watchdogTimer.reset(new base::Timer(false, false));
+ _watchdogTimer->Start(FROM_HERE, base::TimeDelta::FromSeconds(
+ kAuthenticationFlowTimeoutSeconds),
+ base::BindBlock(onTimeout));
+}
+
+- (BOOL)stopWatchdogTimer {
+ if (_watchdogTimer) {
+ _watchdogTimer->Stop();
+ _watchdogTimer.reset();
+ return YES;
+ }
+ return NO;
+}
+
+- (void)fetchManagedStatus:(ios::ChromeBrowserState*)browserState
+ forIdentity:(ChromeIdentity*)identity {
+ if (!experimental_flags::IsMDMIntegrationEnabled()) {
+ [_delegate didFetchManagedStatus:nil];
+ return;
+ }
+ if (gaia::ExtractDomainName(gaia::CanonicalizeEmail(
+ base::SysNSStringToUTF8(identity.userEmail))) == "gmail.com") {
+ // Do nothing for @gmail.com addresses as they can't have a hosted domain.
+ // This avoids waiting for this step to complete (and a network call).
+ [_delegate didFetchManagedStatus:nil];
+ return;
+ }
+
+ [self startWatchdogTimerForManagedStatus];
+ base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
+ ios::GetChromeBrowserProvider()
+ ->GetChromeIdentityService()
+ ->GetHostedDomainForIdentity(
+ identity, ^(NSString* hosted_domain, NSError* error) {
+ [weakSelf handleGetHostedDomain:hosted_domain
+ error:error
+ browserState:browserState];
+ });
+}
+
+- (void)handleGetHostedDomain:(NSString*)hostedDomain
+ error:(NSError*)error
+ browserState:(ios::ChromeBrowserState*)browserState {
+ if (![self stopWatchdogTimer]) {
+ // Watchdog timer has already fired, don't notify the delegate.
+ return;
+ }
+ if (error) {
+ [_delegate didFailFetchManagedStatus:error];
+ return;
+ }
+ [_delegate didFetchManagedStatus:hostedDomain];
+}
+
+- (void)signInIdentity:(ChromeIdentity*)identity
+ withHostedDomain:(NSString*)hostedDomain
+ toBrowserState:(ios::ChromeBrowserState*)browserState {
+ AuthenticationServiceFactory::GetForBrowserState(browserState)
+ ->SignIn(identity, base::SysNSStringToUTF8(hostedDomain));
+}
+
+- (void)signOutBrowserState:(ios::ChromeBrowserState*)browserState {
+ AuthenticationServiceFactory::GetForBrowserState(browserState)
+ ->SignOut(signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, ^{
+ [_delegate didSignOut];
+ });
+}
+
+- (void)signOutImmediatelyFromBrowserState:
+ (ios::ChromeBrowserState*)browserState {
+ AuthenticationServiceFactory::GetForBrowserState(browserState)
+ ->SignOut(signin_metrics::ABORT_SIGNIN, nil);
+}
+
+- (void)promptSwitchFromManagedEmail:(NSString*)managedEmail
+ withHostedDomain:(NSString*)hostedDomain
+ toEmail:(NSString*)toEmail
+ viewController:(UIViewController*)viewController {
+ DCHECK(!_alertCoordinator);
+ NSString* title = l10n_util::GetNSString(IDS_IOS_MANAGED_SWITCH_TITLE);
+ NSString* subtitle = l10n_util::GetNSStringF(
+ IDS_IOS_MANAGED_SWITCH_SUBTITLE, base::SysNSStringToUTF16(managedEmail),
+ base::SysNSStringToUTF16(toEmail),
+ base::SysNSStringToUTF16(hostedDomain));
+ NSString* acceptLabel =
+ l10n_util::GetNSString(IDS_IOS_MANAGED_SWITCH_ACCEPT_BUTTON);
+ NSString* cancelLabel = l10n_util::GetNSString(IDS_CANCEL);
+
+ _alertCoordinator.reset([[AlertCoordinator alloc]
+ initWithBaseViewController:viewController
+ title:title
+ message:subtitle]);
+
+ base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
+ base::WeakNSObject<AlertCoordinator> weakAlert(_alertCoordinator);
+ ProceduralBlock acceptBlock = ^{
+ base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ [[strongSelf delegate]
+ didChooseClearDataPolicy:SHOULD_CLEAR_DATA_CLEAR_DATA];
+ [strongSelf alertControllerDidDisappear:weakAlert];
+ };
+ ProceduralBlock cancelBlock = ^{
+ base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ [[strongSelf delegate] didChooseCancel];
+ [strongSelf alertControllerDidDisappear:weakAlert];
+ };
+
+ [_alertCoordinator addItemWithTitle:cancelLabel
+ action:cancelBlock
+ style:UIAlertActionStyleCancel];
+ [_alertCoordinator addItemWithTitle:acceptLabel
+ action:acceptBlock
+ style:UIAlertActionStyleDefault];
+ [_alertCoordinator setCancelAction:cancelBlock];
+ [_alertCoordinator start];
+}
+
+- (void)promptMergeCaseForIdentity:(ChromeIdentity*)identity
+ browserState:(ios::ChromeBrowserState*)browserState
+ viewController:(UIViewController*)viewController {
+ BOOL isSignedIn = YES;
+ NSString* lastSignedInEmail =
+ [AuthenticationServiceFactory::GetForBrowserState(browserState)
+ ->GetAuthenticatedIdentity() userEmail];
+ if (!lastSignedInEmail) {
+ lastSignedInEmail =
+ base::SysUTF8ToNSString(browserState->GetPrefs()->GetString(
+ prefs::kGoogleServicesLastUsername));
+ isSignedIn = NO;
+ }
+
+ if (AuthenticationServiceFactory::GetForBrowserState(browserState)
+ ->IsAuthenticatedIdentityManaged()) {
+ NSString* hostedDomain = base::SysUTF8ToNSString(
+ ios::SigninManagerFactory::GetForBrowserState(browserState)
+ ->GetAuthenticatedAccountInfo()
+ .hosted_domain);
+ [self promptSwitchFromManagedEmail:lastSignedInEmail
+ withHostedDomain:hostedDomain
+ toEmail:[identity userEmail]
+ viewController:viewController];
+ return;
+ }
+ _navigationController.reset([SettingsNavigationController
+ newImportDataController:browserState
+ delegate:self
+ importDataDelegate:self
+ fromEmail:lastSignedInEmail
+ toEmail:[identity userEmail]
+ isSignedIn:isSignedIn]);
+ [_navigationController setShouldCommitSyncChangesOnDismissal:NO];
+ [[_delegate presentingViewController]
+ presentViewController:_navigationController
+ animated:YES
+ completion:nil];
+}
+
+- (void)clearData:(ios::ChromeBrowserState*)browserState {
+ DCHECK(!AuthenticationServiceFactory::GetForBrowserState(browserState)
+ ->GetAuthenticatedUserEmail());
+ BrowserStateDataRemover::ClearData(browserState, ^{
+ [_delegate didClearData];
+ });
+}
+
+- (BOOL)shouldHandleMergeCaseForIdentity:(ChromeIdentity*)identity
+ browserState:
+ (ios::ChromeBrowserState*)browserState {
+ std::string lastSignedInAccountId =
+ browserState->GetPrefs()->GetString(prefs::kGoogleServicesLastAccountId);
+ std::string currentSignedInAccountId =
+ ios::AccountTrackerServiceFactory::GetForBrowserState(browserState)
+ ->PickAccountIdForAccount(
+ base::SysNSStringToUTF8([identity gaiaID]),
+ base::SysNSStringToUTF8([identity userEmail]));
+ if (!lastSignedInAccountId.empty()) {
+ // Merge case exists if the id of the previously signed in account is
+ // different from the one of the account being signed in.
+ return lastSignedInAccountId != currentSignedInAccountId;
+ }
+
+ // kGoogleServicesLastAccountId pref might not have been populated yet,
+ // check the old kGoogleServicesLastUsername pref.
+ std::string lastSignedInEmail =
+ browserState->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername);
+ std::string currentSignedInEmail =
+ base::SysNSStringToUTF8([identity userEmail]);
+ return !lastSignedInEmail.empty() &&
+ !gaia::AreEmailsSame(currentSignedInEmail, lastSignedInEmail);
+}
+
+- (void)showManagedConfirmationForHostedDomain:(NSString*)hostedDomain
+ viewController:
+ (UIViewController*)viewController {
+ DCHECK(!_alertCoordinator);
+ NSString* title = l10n_util::GetNSString(IDS_IOS_MANAGED_SIGNIN_TITLE);
+ NSString* subtitle = l10n_util::GetNSStringF(
+ IDS_IOS_MANAGED_SIGNIN_SUBTITLE, base::SysNSStringToUTF16(hostedDomain));
+ NSString* acceptLabel =
+ l10n_util::GetNSString(IDS_IOS_MANAGED_SIGNIN_ACCEPT_BUTTON);
+ NSString* cancelLabel = l10n_util::GetNSString(IDS_CANCEL);
+
+ _alertCoordinator.reset([[AlertCoordinator alloc]
+ initWithBaseViewController:viewController
+ title:title
+ message:subtitle]);
+
+ base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
+ base::WeakNSObject<AlertCoordinator> weakAlert(_alertCoordinator);
+ ProceduralBlock acceptBlock = ^{
+ base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ [[strongSelf delegate] didAcceptManagedConfirmation];
+ [strongSelf alertControllerDidDisappear:weakAlert];
+ };
+ ProceduralBlock cancelBlock = ^{
+ base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ [[strongSelf delegate] didCancelManagedConfirmation];
+ [strongSelf alertControllerDidDisappear:weakAlert];
+ };
+
+ [_alertCoordinator addItemWithTitle:cancelLabel
+ action:cancelBlock
+ style:UIAlertActionStyleCancel];
+ [_alertCoordinator addItemWithTitle:acceptLabel
+ action:acceptBlock
+ style:UIAlertActionStyleDefault];
+ [_alertCoordinator setCancelAction:cancelBlock];
+ [_alertCoordinator start];
+}
+
+- (void)showAuthenticationError:(NSError*)error
+ withCompletion:(ProceduralBlock)callback
+ viewController:(UIViewController*)viewController {
+ DCHECK(!_alertCoordinator);
+
+ _alertCoordinator.reset(
+ [ios_internal::ErrorCoordinatorNoItem(error, viewController) retain]);
+
+ base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
+ base::WeakNSObject<AlertCoordinator> weakAlert(_alertCoordinator);
+ ProceduralBlock dismissAction = ^{
+ if (callback)
+ callback();
+ [weakSelf alertControllerDidDisappear:weakAlert];
+ };
+
+ NSString* okButtonLabel = l10n_util::GetNSString(IDS_OK);
+ [_alertCoordinator addItemWithTitle:okButtonLabel
+ action:dismissAction
+ style:UIAlertActionStyleDefault];
+
+ [_alertCoordinator setCancelAction:dismissAction];
+
+ [_alertCoordinator start];
+}
+
+- (void)alertControllerDidDisappear:(AlertCoordinator*)alertCoordinator {
+ if (_alertCoordinator.get() != alertCoordinator) {
+ // Do not reset the |_alertCoordinator| if it has changed. This typically
+ // happens when the user taps on any of the actions on "Clear Data Before
+ // Syncing?" dialog, as the sign-in confirmation dialog is created before
+ // the "Clear Data Before Syncing?" dialog is dismissed.
+ return;
+ }
+ _alertCoordinator.reset();
+}
+
+#pragma mark - ImportDataControllerDelegate
+
+- (void)didChooseClearDataPolicy:(ImportDataCollectionViewController*)controller
+ shouldClearData:(ShouldClearData)shouldClearData {
+ DCHECK_NE(SHOULD_CLEAR_DATA_USER_CHOICE, shouldClearData);
+ if (shouldClearData == SHOULD_CLEAR_DATA_CLEAR_DATA) {
+ base::RecordAction(
+ base::UserMetricsAction("Signin_ImportDataPrompt_DontImport"));
+ } else {
+ base::RecordAction(
+ base::UserMetricsAction("Signin_ImportDataPrompt_ImportData"));
+ }
+
+ base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
+ ProceduralBlock block = ^{
+ base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ strongSelf.get()->_navigationController.reset();
+ [[strongSelf delegate] didChooseClearDataPolicy:shouldClearData];
+ };
+ [_navigationController settingsWillBeDismissed];
+ [[_delegate presentingViewController] dismissViewControllerAnimated:YES
+ completion:block];
+}
+
+#pragma mark - SettingsNavigationControllerDelegate
+
+- (void)closeSettings {
+ base::RecordAction(base::UserMetricsAction("Signin_ImportDataPrompt_Cancel"));
+
+ base::WeakNSObject<AuthenticationFlowPerformer> weakSelf(self);
+ ProceduralBlock block = ^{
+ base::scoped_nsobject<AuthenticationFlowPerformer> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ strongSelf.get()->_navigationController.reset();
+ [[strongSelf delegate] didChooseCancel];
+ };
+ [_navigationController settingsWillBeDismissed];
+ [[_delegate presentingViewController] dismissViewControllerAnimated:YES
+ completion:block];
+}
+
+- (void)closeSettingsAndOpenNewIncognitoTab {
+ NOTREACHED();
+}
+
+- (void)closeSettingsAndOpenUrl:(OpenUrlCommand*)command {
+ NOTREACHED();
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698