| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/ui/authentication/authentication_flow.h" | 5 #import "ios/chrome/browser/ui/authentication/authentication_flow.h" |
| 6 | 6 |
| 7 #include "base/ios/weak_nsobject.h" | |
| 8 #include "base/logging.h" | 7 #include "base/logging.h" |
| 9 #include "base/mac/objc_property_releaser.h" | |
| 10 #include "base/mac/scoped_block.h" | 8 #include "base/mac/scoped_block.h" |
| 11 #include "base/mac/scoped_nsobject.h" | |
| 12 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" | 9 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| 13 #include "ios/chrome/browser/signin/authentication_service.h" | 10 #include "ios/chrome/browser/signin/authentication_service.h" |
| 14 #include "ios/chrome/browser/signin/authentication_service_factory.h" | 11 #include "ios/chrome/browser/signin/authentication_service_factory.h" |
| 15 #include "ios/chrome/browser/signin/constants.h" | 12 #include "ios/chrome/browser/signin/constants.h" |
| 16 #import "ios/chrome/browser/ui/authentication/authentication_flow_performer.h" | 13 #import "ios/chrome/browser/ui/authentication/authentication_flow_performer.h" |
| 17 #include "ios/chrome/grit/ios_strings.h" | 14 #include "ios/chrome/grit/ios_strings.h" |
| 18 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" | 15 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
| 19 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" | 16 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" |
| 20 #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" | 17 #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" |
| 21 #include "ios/public/provider/chrome/browser/signin/signin_error_provider.h" | 18 #include "ios/public/provider/chrome/browser/signin/signin_error_provider.h" |
| 22 #include "ui/base/l10n/l10n_util.h" | 19 #include "ui/base/l10n/l10n_util.h" |
| 23 | 20 |
| 21 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 22 #error "This file requires ARC support." |
| 23 #endif |
| 24 |
| 24 using signin_ui::CompletionCallback; | 25 using signin_ui::CompletionCallback; |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 // The states of the sign-in flow state machine. | 29 // The states of the sign-in flow state machine. |
| 29 enum AuthenticationState { | 30 enum AuthenticationState { |
| 30 BEGIN, | 31 BEGIN, |
| 31 CHECK_SIGNIN_STEPS, | 32 CHECK_SIGNIN_STEPS, |
| 32 FETCH_MANAGED_STATUS, | 33 FETCH_MANAGED_STATUS, |
| 33 CHECK_MERGE_CASE, | 34 CHECK_MERGE_CASE, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 - (void)cancelFlow; | 74 - (void)cancelFlow; |
| 74 | 75 |
| 75 // Handles an authentication error and show an alert to the user. | 76 // Handles an authentication error and show an alert to the user. |
| 76 - (void)handleAuthenticationError:(NSError*)error; | 77 - (void)handleAuthenticationError:(NSError*)error; |
| 77 | 78 |
| 78 @end | 79 @end |
| 79 | 80 |
| 80 @implementation AuthenticationFlow { | 81 @implementation AuthenticationFlow { |
| 81 ShouldClearData _shouldClearData; | 82 ShouldClearData _shouldClearData; |
| 82 PostSignInAction _postSignInAction; | 83 PostSignInAction _postSignInAction; |
| 83 base::scoped_nsobject<UIViewController> _presentingViewController; | 84 UIViewController* _presentingViewController; |
| 84 base::mac::ScopedBlock<CompletionCallback> _signInCompletion; | 85 CompletionCallback _signInCompletion; |
| 85 base::scoped_nsobject<AuthenticationFlowPerformer> _performer; | 86 AuthenticationFlowPerformer* _performer; |
| 86 | 87 |
| 87 // State machine tracking. | 88 // State machine tracking. |
| 88 AuthenticationState _state; | 89 AuthenticationState _state; |
| 89 BOOL _didSignIn; | 90 BOOL _didSignIn; |
| 90 BOOL _failedOrCancelled; | 91 BOOL _failedOrCancelled; |
| 91 BOOL _shouldSignIn; | 92 BOOL _shouldSignIn; |
| 92 BOOL _shouldSignOut; | 93 BOOL _shouldSignOut; |
| 93 BOOL _shouldShowManagedConfirmation; | 94 BOOL _shouldShowManagedConfirmation; |
| 94 BOOL _shouldStartSync; | 95 BOOL _shouldStartSync; |
| 95 ios::ChromeBrowserState* _browserState; | 96 ios::ChromeBrowserState* _browserState; |
| 96 base::scoped_nsobject<ChromeIdentity> _browserStateIdentity; | 97 ChromeIdentity* _browserStateIdentity; |
| 97 base::scoped_nsobject<ChromeIdentity> _identityToSignIn; | 98 ChromeIdentity* _identityToSignIn; |
| 98 base::scoped_nsobject<NSString> _identityToSignInHostedDomain; | 99 NSString* _identityToSignInHostedDomain; |
| 99 | 100 |
| 100 // This AuthenticationFlow keeps a reference to |self| while a sign-in flow is | 101 // This AuthenticationFlow keeps a reference to |self| while a sign-in flow is |
| 101 // is in progress to ensure it outlives any attempt to destroy it in | 102 // is in progress to ensure it outlives any attempt to destroy it in |
| 102 // |_signInCompletion|. | 103 // |_signInCompletion|. |
| 103 base::scoped_nsobject<AuthenticationFlow> _selfRetainer; | 104 AuthenticationFlow* _selfRetainer; |
| 104 | |
| 105 base::mac::ObjCPropertyReleaser _propertyReleaser_AuthenticationFlow; | |
| 106 } | 105 } |
| 107 | 106 |
| 108 @synthesize handlingError = _handlingError; | 107 @synthesize handlingError = _handlingError; |
| 109 | 108 |
| 110 #pragma mark - Public methods | 109 #pragma mark - Public methods |
| 111 | 110 |
| 112 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState | 111 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState |
| 113 identity:(ChromeIdentity*)identity | 112 identity:(ChromeIdentity*)identity |
| 114 shouldClearData:(ShouldClearData)shouldClearData | 113 shouldClearData:(ShouldClearData)shouldClearData |
| 115 postSignInAction:(PostSignInAction)postSignInAction | 114 postSignInAction:(PostSignInAction)postSignInAction |
| 116 presentingViewController: | 115 presentingViewController: |
| 117 (UIViewController*)presentingViewController { | 116 (UIViewController*)presentingViewController { |
| 118 if ((self = [super init])) { | 117 if ((self = [super init])) { |
| 119 DCHECK(browserState); | 118 DCHECK(browserState); |
| 120 DCHECK(presentingViewController); | 119 DCHECK(presentingViewController); |
| 121 _browserState = browserState; | 120 _browserState = browserState; |
| 122 _identityToSignIn.reset([identity retain]); | 121 _identityToSignIn = identity; |
| 123 _shouldClearData = shouldClearData; | 122 _shouldClearData = shouldClearData; |
| 124 _postSignInAction = postSignInAction; | 123 _postSignInAction = postSignInAction; |
| 125 _presentingViewController.reset([presentingViewController retain]); | 124 _presentingViewController = presentingViewController; |
| 126 _state = BEGIN; | 125 _state = BEGIN; |
| 127 _propertyReleaser_AuthenticationFlow.Init(self, [AuthenticationFlow class]); | |
| 128 } | 126 } |
| 129 return self; | 127 return self; |
| 130 } | 128 } |
| 131 | 129 |
| 132 - (void)startSignInWithCompletion:(CompletionCallback)completion { | 130 - (void)startSignInWithCompletion:(CompletionCallback)completion { |
| 133 DCHECK_EQ(BEGIN, _state); | 131 DCHECK_EQ(BEGIN, _state); |
| 134 DCHECK(!_signInCompletion); | 132 DCHECK(!_signInCompletion); |
| 135 DCHECK(completion); | 133 DCHECK(completion); |
| 136 _signInCompletion.reset(completion, base::scoped_policy::RETAIN); | 134 _signInCompletion = completion; |
| 137 _selfRetainer.reset([self retain]); | 135 _selfRetainer = self; |
| 138 // Kick off the state machine. | 136 // Kick off the state machine. |
| 139 if (!_performer) { | 137 if (!_performer) { |
| 140 _performer.reset( | 138 _performer = [[AuthenticationFlowPerformer alloc] initWithDelegate:self]; |
| 141 [[AuthenticationFlowPerformer alloc] initWithDelegate:self]); | |
| 142 } | 139 } |
| 143 [self continueSignin]; | 140 [self continueSignin]; |
| 144 } | 141 } |
| 145 | 142 |
| 146 - (void)cancelAndDismiss { | 143 - (void)cancelAndDismiss { |
| 147 if (_state == DONE) | 144 if (_state == DONE) |
| 148 return; | 145 return; |
| 149 | 146 |
| 150 [_performer cancelAndDismiss]; | 147 [_performer cancelAndDismiss]; |
| 151 if (_state != DONE) { | 148 if (_state != DONE) { |
| 152 // The performer might not have been able to continue the flow if it was | 149 // The performer might not have been able to continue the flow if it was |
| 153 // waiting for a callback (e.g. waiting for AccountReconcilor). In this | 150 // waiting for a callback (e.g. waiting for AccountReconcilor). In this |
| 154 // case, we force the flow to finish synchronously. | 151 // case, we force the flow to finish synchronously. |
| 155 [self cancelFlow]; | 152 [self cancelFlow]; |
| 156 } | 153 } |
| 157 | 154 |
| 158 DCHECK_EQ(DONE, _state); | 155 DCHECK_EQ(DONE, _state); |
| 159 } | 156 } |
| 160 | 157 |
| 161 - (void)setPresentingViewController: | 158 - (void)setPresentingViewController: |
| 162 (UIViewController*)presentingViewController { | 159 (UIViewController*)presentingViewController { |
| 163 _presentingViewController.reset([presentingViewController retain]); | 160 _presentingViewController = presentingViewController; |
| 164 } | 161 } |
| 165 | 162 |
| 166 #pragma mark State machine management | 163 #pragma mark State machine management |
| 167 | 164 |
| 168 - (AuthenticationState)nextStateFailedOrCancelled { | 165 - (AuthenticationState)nextStateFailedOrCancelled { |
| 169 DCHECK(_failedOrCancelled); | 166 DCHECK(_failedOrCancelled); |
| 170 switch (_state) { | 167 switch (_state) { |
| 171 case BEGIN: | 168 case BEGIN: |
| 172 case CHECK_SIGNIN_STEPS: | 169 case CHECK_SIGNIN_STEPS: |
| 173 case FETCH_MANAGED_STATUS: | 170 case FETCH_MANAGED_STATUS: |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 | 305 |
| 309 case COMPLETE_WITH_FAILURE: | 306 case COMPLETE_WITH_FAILURE: |
| 310 if (_didSignIn) { | 307 if (_didSignIn) { |
| 311 [_performer signOutImmediatelyFromBrowserState:_browserState]; | 308 [_performer signOutImmediatelyFromBrowserState:_browserState]; |
| 312 // Enabling/disabling sync does not take effect in the sync backend | 309 // Enabling/disabling sync does not take effect in the sync backend |
| 313 // until committing changes. | 310 // until committing changes. |
| 314 [_performer commitSyncForBrowserState:_browserState]; | 311 [_performer commitSyncForBrowserState:_browserState]; |
| 315 } | 312 } |
| 316 [self completeSignInWithSuccess:NO]; | 313 [self completeSignInWithSuccess:NO]; |
| 317 return; | 314 return; |
| 318 case CLEANUP_BEFORE_DONE: | 315 case CLEANUP_BEFORE_DONE: { |
| 319 // Clean up asynchronously to ensure that |self| does not die while | 316 // Clean up asynchronously to ensure that |self| does not die while |
| 320 // the flow is running. | 317 // the flow is running. |
| 321 DCHECK([NSThread isMainThread]); | 318 DCHECK([NSThread isMainThread]); |
| 322 dispatch_async(dispatch_get_main_queue(), ^{ | 319 dispatch_async(dispatch_get_main_queue(), ^{ |
| 323 _selfRetainer.reset(); | 320 _selfRetainer = nil; |
| 324 }); | 321 }); |
| 325 [self continueSignin]; | 322 [self continueSignin]; |
| 326 return; | 323 return; |
| 324 } |
| 327 case DONE: | 325 case DONE: |
| 328 return; | 326 return; |
| 329 } | 327 } |
| 330 NOTREACHED(); | 328 NOTREACHED(); |
| 331 } | 329 } |
| 332 | 330 |
| 333 - (void)checkSigninSteps { | 331 - (void)checkSigninSteps { |
| 334 _browserStateIdentity.reset( | 332 _browserStateIdentity = |
| 335 [AuthenticationServiceFactory::GetForBrowserState(_browserState) | 333 AuthenticationServiceFactory::GetForBrowserState(_browserState) |
| 336 ->GetAuthenticatedIdentity() retain]); | 334 ->GetAuthenticatedIdentity(); |
| 337 if (_browserStateIdentity) | 335 if (_browserStateIdentity) |
| 338 _shouldSignOut = YES; | 336 _shouldSignOut = YES; |
| 339 | 337 |
| 340 _shouldSignIn = YES; | 338 _shouldSignIn = YES; |
| 341 _shouldStartSync = _postSignInAction == POST_SIGNIN_ACTION_START_SYNC; | 339 _shouldStartSync = _postSignInAction == POST_SIGNIN_ACTION_START_SYNC; |
| 342 } | 340 } |
| 343 | 341 |
| 344 - (void)signInIdentity:(ChromeIdentity*)identity { | 342 - (void)signInIdentity:(ChromeIdentity*)identity { |
| 345 if (ios::GetChromeBrowserProvider() | 343 if (ios::GetChromeBrowserProvider() |
| 346 ->GetChromeIdentityService() | 344 ->GetChromeIdentityService() |
| 347 ->IsValidIdentity(identity)) { | 345 ->IsValidIdentity(identity)) { |
| 348 [_performer signInIdentity:identity | 346 [_performer signInIdentity:identity |
| 349 withHostedDomain:_identityToSignInHostedDomain | 347 withHostedDomain:_identityToSignInHostedDomain |
| 350 toBrowserState:_browserState]; | 348 toBrowserState:_browserState]; |
| 351 _didSignIn = YES; | 349 _didSignIn = YES; |
| 352 [self continueSignin]; | 350 [self continueSignin]; |
| 353 } else { | 351 } else { |
| 354 // Handle the case where the identity is no longer valid. | 352 // Handle the case where the identity is no longer valid. |
| 355 [self handleAuthenticationError:IdentityMissingError()]; | 353 [self handleAuthenticationError:IdentityMissingError()]; |
| 356 } | 354 } |
| 357 } | 355 } |
| 358 | 356 |
| 359 - (void)completeSignInWithSuccess:(BOOL)success { | 357 - (void)completeSignInWithSuccess:(BOOL)success { |
| 360 DCHECK(_signInCompletion) | 358 DCHECK(_signInCompletion) |
| 361 << "|completeSignInWithSuccess| should not be called twice."; | 359 << "|completeSignInWithSuccess| should not be called twice."; |
| 362 _signInCompletion.get()(success); | 360 _signInCompletion(success); |
| 363 _signInCompletion.reset(); | 361 _signInCompletion = nil; |
| 364 [self continueSignin]; | 362 [self continueSignin]; |
| 365 } | 363 } |
| 366 | 364 |
| 367 - (void)cancelFlow { | 365 - (void)cancelFlow { |
| 368 if (_failedOrCancelled) { | 366 if (_failedOrCancelled) { |
| 369 // Avoid double handling of cancel or error. | 367 // Avoid double handling of cancel or error. |
| 370 return; | 368 return; |
| 371 } | 369 } |
| 372 _failedOrCancelled = YES; | 370 _failedOrCancelled = YES; |
| 373 [self continueSignin]; | 371 [self continueSignin]; |
| 374 } | 372 } |
| 375 | 373 |
| 376 - (void)handleAuthenticationError:(NSError*)error { | 374 - (void)handleAuthenticationError:(NSError*)error { |
| 377 if (_failedOrCancelled) { | 375 if (_failedOrCancelled) { |
| 378 // Avoid double handling of cancel or error. | 376 // Avoid double handling of cancel or error. |
| 379 return; | 377 return; |
| 380 } | 378 } |
| 381 DCHECK(error); | 379 DCHECK(error); |
| 382 _failedOrCancelled = YES; | 380 _failedOrCancelled = YES; |
| 383 self.handlingError = YES; | 381 self.handlingError = YES; |
| 384 base::WeakNSObject<AuthenticationFlow> weakSelf(self); | 382 __weak AuthenticationFlow* weakSelf = self; |
| 385 [_performer showAuthenticationError:error | 383 [_performer showAuthenticationError:error |
| 386 withCompletion:^{ | 384 withCompletion:^{ |
| 387 base::scoped_nsobject<AuthenticationFlow> strongSelf( | 385 AuthenticationFlow* strongSelf = weakSelf; |
| 388 [weakSelf retain]); | |
| 389 if (!strongSelf) | 386 if (!strongSelf) |
| 390 return; | 387 return; |
| 391 [strongSelf setHandlingError:NO]; | 388 [strongSelf setHandlingError:NO]; |
| 392 [strongSelf continueSignin]; | 389 [strongSelf continueSignin]; |
| 393 } | 390 } |
| 394 viewController:_presentingViewController]; | 391 viewController:_presentingViewController]; |
| 395 } | 392 } |
| 396 | 393 |
| 397 #pragma mark AuthenticationFlowPerformerDelegate | 394 #pragma mark AuthenticationFlowPerformerDelegate |
| 398 | 395 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 411 [self continueSignin]; | 408 [self continueSignin]; |
| 412 } | 409 } |
| 413 | 410 |
| 414 - (void)didChooseCancel { | 411 - (void)didChooseCancel { |
| 415 [self cancelFlow]; | 412 [self cancelFlow]; |
| 416 } | 413 } |
| 417 | 414 |
| 418 - (void)didFetchManagedStatus:(NSString*)hostedDomain { | 415 - (void)didFetchManagedStatus:(NSString*)hostedDomain { |
| 419 DCHECK_EQ(FETCH_MANAGED_STATUS, _state); | 416 DCHECK_EQ(FETCH_MANAGED_STATUS, _state); |
| 420 _shouldShowManagedConfirmation = [hostedDomain length] > 0; | 417 _shouldShowManagedConfirmation = [hostedDomain length] > 0; |
| 421 _identityToSignInHostedDomain.reset([hostedDomain retain]); | 418 _identityToSignInHostedDomain = hostedDomain; |
| 422 [self continueSignin]; | 419 [self continueSignin]; |
| 423 } | 420 } |
| 424 | 421 |
| 425 - (void)didFailFetchManagedStatus:(NSError*)error { | 422 - (void)didFailFetchManagedStatus:(NSError*)error { |
| 426 DCHECK_EQ(FETCH_MANAGED_STATUS, _state); | 423 DCHECK_EQ(FETCH_MANAGED_STATUS, _state); |
| 427 NSError* flowError = | 424 NSError* flowError = |
| 428 [NSError errorWithDomain:kAuthenticationErrorDomain | 425 [NSError errorWithDomain:kAuthenticationErrorDomain |
| 429 code:AUTHENTICATION_FLOW_ERROR | 426 code:AUTHENTICATION_FLOW_ERROR |
| 430 userInfo:@{ | 427 userInfo:@{ |
| 431 NSLocalizedDescriptionKey : | 428 NSLocalizedDescriptionKey : |
| (...skipping 11 matching lines...) Expand all Loading... |
| 443 [self cancelFlow]; | 440 [self cancelFlow]; |
| 444 } | 441 } |
| 445 | 442 |
| 446 - (UIViewController*)presentingViewController { | 443 - (UIViewController*)presentingViewController { |
| 447 return _presentingViewController; | 444 return _presentingViewController; |
| 448 } | 445 } |
| 449 | 446 |
| 450 #pragma mark - Used for testing | 447 #pragma mark - Used for testing |
| 451 | 448 |
| 452 - (void)setPerformerForTesting:(AuthenticationFlowPerformer*)performer { | 449 - (void)setPerformerForTesting:(AuthenticationFlowPerformer*)performer { |
| 453 _performer.reset([performer retain]); | 450 _performer = performer; |
| 454 } | 451 } |
| 455 | 452 |
| 456 @end | 453 @end |
| OLD | NEW |