Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Better handle ios6 system auth in case user un-tosses app from accoun…
…t settings by calling "ACAccountStore renew" when using ios6 system auth and response contains an invalid session.

Summary:
      Also added overload to FBSession closeAndClearToken: to take an NSError*.
      Also tweaked FBSession close to no-op if already closed.
      Also tweaked Scrumptious example to report login errors from FBUserSettingsView.

     This does NOT address the "code 2" errors from when ios6 users toggle the
     slider in their device Facebook settings though those cases do transition
     to "ClosedLoginFailed" so it can be argued clients can code against it.

     This also does NOT seamlessly fix cases where the ios6 auth user has
     removed the post permission from their account settings; though it does
     allow them to logout and log back in to resolve. Further, this scenario
     does surface the "(facebook#200) Requires extended permission: publish_actions" in the
     startForPostWithGraphPath handler so clients can surface it.

Test Plan:
     Tested many cases with scrumptious, but primary issue was:
     1. using io6 system auth, login and post from scrumptious.
     2. remove scrumptious from account settings.
     3. re-open app (if already on announce page, will transition to login)
     4. click login
     5. with fix, user is prompted via ios6 dialog again.
        (without fix), login would flash to announce view then present login.

     Tested the above in both scenarios where step 1 ends in either announce page
      or if user explicitly logged out (i.e., to verify user does not need to
      click login twice). Updated in revision 2 so that user does click login twice, if they had explicitly logged out of the app (the first login will report the error, the second login will re-surface the ios dialog).

     Tested same scenario with wilde-login on device, and also on ios 4.3 simulator
      to verify no changes in those uses cases.

Revert Plan:

Reviewers: jacl, gregschechte

Reviewed By: jacl

CC: clang, ekoneil

Differential Revision: https://phabricator.fb.com/D587553

Task ID: 1764202
  • Loading branch information
chrisp-fb authored and onebit committed Oct 1, 2012
1 parent 8868dcb commit 9aebe4c
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 17 deletions.
14 changes: 14 additions & 0 deletions samples/Scrumptious/scrumptious/SCViewController.m
Expand Up @@ -314,6 +314,7 @@ -(void)viewWillAppear:(BOOL)animated{
-(void)settingsButtonWasPressed:(id)sender {
if (self.settingsViewController == nil) {
self.settingsViewController = [[FBUserSettingsViewController alloc] init];
self.settingsViewController.delegate = self;
}
[self.navigationController pushViewController:self.settingsViewController animated:YES];
}
Expand Down Expand Up @@ -348,6 +349,19 @@ - (void)setPlaceCacheDescriptorForCoordinates:(CLLocationCoordinate2D)coordinate
fieldsForRequest:nil];
}

#pragma mark - FBUserSettingsDelegate methods

- (void)loginViewController:(id)sender receivedError:(NSError *)error{
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
}
}

#pragma mark UITableViewDataSource methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
Expand Down
5 changes: 4 additions & 1 deletion src/FBRequestConnection.m
Expand Up @@ -1151,7 +1151,10 @@ - (void)completeWithResults:(NSArray *)results

if ([self isInvalidSessionError:itemError
resultIndex:error == itemError ? i : 0]) {
[metadata.request.session closeAndClearTokenInformation];
[metadata.request.session closeAndClearTokenInformation:itemError];
if (metadata.request.session.loginType == FBSessionLoginTypeSystemAccount){
[FBSession renewSystemAuthorization];
}
} else if ([metadata.request.session shouldExtendAccessToken]) {
// If we have not had the opportunity to piggyback a token-extension request,
// but we need to, do so now as a separate request.
Expand Down
2 changes: 2 additions & 0 deletions src/FBSession+Internal.h
Expand Up @@ -20,10 +20,12 @@

- (void)refreshAccessToken:(NSString*)token expirationDate:(NSDate*)expireDate;
- (BOOL)shouldExtendAccessToken;
- (void)closeAndClearTokenInformation:(NSError*) error;

+ (FBSession*)activeSessionIfOpen;

+ (void)deleteFacebookCookies;
+ (NSDate*)expirationDateFromExpirationTimeString:(NSString*)expirationTime;
+ (void)renewSystemAuthorization;

@end
66 changes: 50 additions & 16 deletions src/FBSession.m
Expand Up @@ -403,7 +403,10 @@ - (void)reauthorizeWithPublishPermissions:(NSArray*)writePermissions
- (void)close {
NSAssert(self.affinitizedThread == [NSThread currentThread], @"FBSession: should only be used from a single thread");

FBSessionState state;
FBSessionState state;
if (self.state = FBSessionStateClosed) {
return;
}
if (self.state == FBSessionStateCreatedOpening) {
state = FBSessionStateClosedLoginFailed;
} else {
Expand All @@ -419,20 +422,7 @@ - (void)close {
}

- (void)closeAndClearTokenInformation {
NSAssert(self.affinitizedThread == [NSThread currentThread], @"FBSession: should only be used from a single thread");

[[FBDataDiskCache sharedCache] removeDataForSession:self];
[self.tokenCachingStrategy clearToken];

// If we are not already in a terminal state, go to Closed.
if (!FB_ISSESSIONSTATETERMINAL(self.state)) {
[self transitionAndCallHandlerWithState:FBSessionStateClosed
error:nil
token:nil
expirationDate:nil
shouldCache:NO
loginType:FBSessionLoginTypeNone];
}
[self closeAndClearTokenInformation:nil];
}

- (BOOL)handleOpenURL:(NSURL *)url {
Expand Down Expand Up @@ -622,6 +612,33 @@ + (NSString*)defaultAppID {
return g_defaultAppID;
}

//calls ios6 renewCredentialsForAccount in order to update ios6's worldview of authorization state.
// if not using ios6 system auth, this is a no-op.
+ (void)renewSystemAuthorization {
id accountStore = nil;
id accountTypeFB = nil;

if ((accountStore = [[[ACAccountStore alloc] init] autorelease]) &&
(accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){

NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (fbAccounts && [fbAccounts count] > 0 &&
(account = [fbAccounts objectAtIndex:0])){

[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
//we don't actually need to inspect renewResult or error.
if (error){
[FBLogger singleShotLogEntry:FBLoggingBehaviorAccessTokens
logEntry:[NSString stringWithFormat:@"renewCredentialsForAccount result:%d, error: %@",
renewResult,
error]];
}
}];
}
}
}

#pragma mark -
#pragma mark Private Members

Expand Down Expand Up @@ -681,7 +698,7 @@ - (BOOL)transitionToState:(FBSessionState)state
loginType != FBSessionLoginTypeNone) {
self.loginType = loginType;
}

// invalid transition short circuits
if (!isValidTransition) {
[FBLogger singleShotLogEntry:FBLoggingBehaviorSessionStateTransitions
Expand Down Expand Up @@ -1666,6 +1683,23 @@ + (NSDate*)expirationDateFromExpirationTimeString:(NSString*)expirationTime {
return expirationDate;
}

- (void)closeAndClearTokenInformation:(NSError*) error {
NSAssert(self.affinitizedThread == [NSThread currentThread], @"FBSession: should only be used from a single thread");

[[FBDataDiskCache sharedCache] removeDataForSession:self];
[self.tokenCachingStrategy clearToken];

// If we are not already in a terminal state, go to Closed.
if (!FB_ISSESSIONSTATETERMINAL(self.state)) {
[self transitionAndCallHandlerWithState:FBSessionStateClosed
error:error
token:nil
expirationDate:nil
shouldCache:NO
loginType:FBSessionLoginTypeNone];
}
}

#pragma mark -
#pragma mark Debugging helpers

Expand Down

0 comments on commit 9aebe4c

Please sign in to comment.