Thursday, June 19, 2014

AeroGear iOS 1.6 is out!

With AeroGear-iOS 1.6 out, we have a complete OAuth2 authorization code grant support (a few features were started in 1.4). Ready to go social? Take a tour and read our documentation.

What’s new?

  • Refresh token grant was added. Pipe seamlessly integrate with OAuth2, providing transparent refresh token requests when needed.

  • Revoke token request on demand.

  • AccountManager to manage multiple accounts and be able to store them permanently on your local phone allowing the user to grant access only when the application was first launched.

  • Social support tested with Google, Facebook and Keycloak. If you want to compare the different approaches on how to post to Facebook please read this blog post as always plenty of cookbook examples Shoot’sShare enhanced with AccountManager and GoogleDrive with revoke and refresh (Thanks to Yagyesh Agrawal for this contribution).


Coming along with 1.6 announcement, we also have a new 0.9.1 AeroGear Push Registration release which includes static lib and framework packaging with its HelloWorld Demo and a more complete contact app example already taking advantage of.

Enjoy our 1.6 journey and as always, we love hearing from you. Go Social, share with us your AeroGear experience on mailing list.

Wednesday, June 4, 2014

Different ways to manage Facebook OAuth2 for iOS

Take this old Hinduism saying: "There is one truth, reached by many paths". Very often there are many ways to achieve the same end result. In our OAuth2 blog serie, we've seen how to use OAuth2 to grant access to GoogleDrive, how to transparently renew grant after expiration time, let's now focus on another OAuth2 main provider: Facebook.

Let's explore different ways of accessing your Facebook wall.

Let's start with ...

Using Social.framework

Since iOS 6, Apple added the support of Facebook in its Social.framework. With the built-in support, end user has to register their Facebook account into iOS settings and grant access.
- (IBAction)postToFacebook:(id)sender {
    
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];
    ACAccountType *facebookAccountType = [accountStore
                                          accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
    
    __block ACAccount *facebookAccount;
    // Specify App ID and permissions
    NSDictionary *options = @{ACFacebookAppIdKey: @"xxxxx",                        // [1]
                              ACFacebookPermissionsKey: @[@"publish_actions"],     // [2]
                              @"ACFacebookAudienceKey": ACFacebookAudienceFriends};
    
    [accountStore requestAccessToAccountsWithType:facebookAccountType
                                          options:options completion:^(BOOL granted, NSError *e) {
                                              if (granted) {                      // [3]
                                                  NSArray *accounts = [accountStore
                                                                       accountsWithAccountType:facebookAccountType];
                                                  facebookAccount = [accounts lastObject];
                                                  // Get the access token, could be used in other scenarios
                                                  ACAccountCredential *fbCredential = [facebookAccount credential];
                                                  NSString *accessToken = [fbCredential oauthToken];
                                                  
                                                  NSLog(@"...Facebook Access Token: %@", accessToken);
                                                  
                                              } else {
                                                  // Handle Failure
                                              }
                                          }];
   
    if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {   // [4]
        SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
        
        [controller setInitialText:@"First post from my iPhone app"];
        [self presentViewController:controller animated:YES completion:Nil];
    }
}

In [1], you specify your Facebook app id and you specify the permissions needed [2].
In [3], you're in the callback from the authorization. As there is only one callback you need to test for successful grant or not. You can then embed your logic in it. As an exemple I show how you can retrieve access token and just logged them.
In [4], you can wait until the asynch authorization request has ended and do you Facebook post using SLComposeViewController. Note when doing you POST request it's the framework itself that pass the access token into the HTTP header. Easy peasy nothing to do on your side.

Pro and cons:
As a pre-requisite, the end user need to be registered in Setting
Facebook credentials are stored in your phone
Only build-in support provider like Twitter, Facebook (for now)
Note all Facebook actions are supported, for more advanced features you will need to go the 2 other ways.

Using Facebook iOS SDK

The good part of Facebook SDK is that it comes bundled with a bunch of good exemples, install it and follow the instruction as described here. For the purpose of our comparison exercice I've chosen to extract some code snipet from the HelloFacebookSample which shows you how handle OAuth2 authenticate and authorize using external browser. To deal with going back to main app from external browser, you work with URL schema and you need the following setting in your property file:
 CFBundleURLTypes
 
  
   CFBundleURLSchemes
   
    fbCLIENT_APP_ID
   
  
 

The Facebook SDK provides you predefined view and controller to achieve the different actions. For example with FBLoginView you can create a login button. Like shown below:
- (void)viewDidLoad {
    [super viewDidLoad];

    // Create Login View so that the app will be granted "status_update" permission.
    FBLoginView *loginview = [[FBLoginView alloc] init];
    loginview.frame = CGRectOffset(loginview.frame, 5, 5);
    loginview.delegate = self;
    [self.view addSubview:loginview];
    [loginview sizeToFit];
}
Implementing the FBLoginViewDelegate delegate, you can implement the callback method as required. Notice here we use a delegate vs a callback block approach for async call. My preference goes toward block if you remember my previous blog post, but yeah just a matter of preferences ;)
@protocol FBLoginViewDelegate 
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView;

- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
                            user:(id)user;

- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView;

- (void)loginView:(FBLoginView *)loginView
      handleError:(NSError *)error;

@end
Pro and cons:
Another SDK to learn,
a Facebook specific dependency to add

Using AeroGear

Using AeroGear iOS OAuth2 adapter, you can log in to any OAuth2 provider, don't need to include Facebook iOS sdk or Social.framework. The main advantage is if your Shoot'nShare app wants to share a photo to different providers like Google+, Facebook you don't need to work with each sdk.
-(void)oauthFacebook {
    // start up the authorization process
    AGAuthorizer* authorizer = [AGAuthorizer authorizer];
    
    // TODO replace XXX -> secret and YYY -> your app id in this file + plist file
    id _facebookAuthzModule = [authorizer authz:^(id config) {  // [1]
        config.name = @"restAuthMod";
        config.baseURL = [[NSURL alloc] init];
        config.authzEndpoint = @"https://www.facebook.com/dialog/oauth";
        config.accessTokenEndpoint = @"https://graph.facebook.com/oauth/access_token";
        config.clientId = @"YYY";
        config.clientSecret = @"XXX";
        config.redirectURL = @"fbYYY://authorize/";
        config.scopes = @[@"user_friends, publish_actions"];
        config.type = @"AG_OAUTH2_FACEBOOK";
    }];
    [_facebookAuthzModule requestAccessSuccess:^(id response) {              // [2]
        [self shareWithFacebook];
        NSLog(@"Success to authorize %@", response);
        
    } failure:^(NSError *error) {
        NSLog(@"Failure to authorize");
    }];
}
In [1], you configure your OAuth2 provider. In [2], you request the grant access. If this is the first time, the app open an external browser to start OAuth2 danse. Enter login/password if not already logged and grant access. Once access is granted you will be forwarded back to Shoot'nshare app using URL schema. The main advantage of using external browser rather than embedded view is that it's keep your login/password safe. No code in between embedded view and client app that you can't control.
Some configuration is needed in your Shoot-Info.plist for URL schema:
    CFBundleURLTypes
    
        
            CFBundleURLName
            fb240176532852375
            CFBundleURLSchemes
            
                fb240176532852375
            
        
    
Ready to actually work with Pipe objects, also part of AeroGear iOS, Pipe is a connection abstraction that let you do CRUD operation asynchronously over the network:
-(void)shareWithFacebook {
        // extract the image filename
        NSString *filename = ...;
        
        // the Facebook API base URL, you need to
        NSURL *gUrl = [NSURL URLWithString:@"https://graph.facebook.com/me/"];
        
        AGPipeline* gPipeline = [AGPipeline pipelineWithBaseURL:gUrl];
        
        // set up upload pipe
        id uploadPipe = [gPipeline pipe:^(id config) {   // [1]
            [config setName:@"photos"];
            [config setAuthzModule:_facebookAuthzModule];
        }];
        
        // Get currently displayed image
        NSData *imageData = ...;
        
        // set up payload with the image
        AGFileDataPart *dataPart = [[AGFileDataPart alloc] initWithFileData:imageData
                                                                       name:@"image"
                                                                   fileName:filename
                                                                   mimeType:@"image/jpeg"];
        NSDictionary *dict = @{@"data:": dataPart};
        
        // show a progress indicator
        [uploadPipe setUploadProgressBlock:^(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [SVProgressHUD showProgress:(totalBytesSent/(float)totalBytesExpectedToSend) status:@"uploading, please wait"];
            });
        }];
        
        // upload file
        [uploadPipe save:dict success:^(id responseObject) {   // [2]
            [SVProgressHUD showSuccessWithStatus:@"Successfully uploaded!"];
        } failure:^(NSError *error) {
            [SVProgressHUD showErrorWithStatus:@"Failed to upload!"];
        }];
    }

In [1] I just instantiate a Pipe that I can use to save my picture [2].
Pros and cons:
AeroGear OAuth2 dependency to add but cross providers
More verbose in term of configuration but you can do whatever you want once you get the access token, it's just plain HTTP REST calls.

You can find the complete source code in aerogear-ios-cookbook git repo, going to the Shoot recipe.

Conclusion

Because I'm core committer on the AeroGear project, my view is biased of course. I'd go for the AeroGear way :) the main reason being it gives you the most flexibility without having to link to several SDKs. The built-in solution is also very tempting but limited besides the fact it's required the end user a previous registration.
Many ways to achieve the same end result, and looking deeper you may find other ways. I'm curious to hear about your discoveries and how we could improve AeroGear iOS libs. Share your thoughts, email AeroGear.

Monday, June 2, 2014

OAuth2 Refresh

We've been talking in length about authorization code grant in my last previous posts.

If we go back to you GoogleDrive exemple (remember OAuth2 discussion part2) let's see how we can implement refresh grant. From OAuth2 spec, if you request an authorization code grant, you should have received a refresh token at the same time you got your access token. Access token expired in 1 hour (for Google for ex) and if you don't want to prompt again for granting access your end-users, you need to use refresh token.

What are they for?

Quoting from ietf mailing list:
There is a security reason, the refresh_token is only ever exchanged with authorization server whereas the access_token is exchanged with resource servers. This mitigates the risk of a long-lived access_token leaking (query param in a log file on an insecure resource server, beta or poorly coded resource server app, JS SDK client on a non https site that puts the access_token in a cookie, etc) in the "an access token good for an hour, with a refresh token good for a year or good-till-revoked" vs "an access token good-till-revoked without a refresh token." Long live tokens are seeing as a security issue whereas short live token + refresh token mitigates the risk.

How to ask?

Refreshing an access token is trivial, it's just a matter of sending you refresh token with an grant_type set to refresh_token.

Not always available...

Facebook for instance don't go the OAuth2 way. After dropping support for long live access token in offline mode, Facebook goes the path of exchanging short lived access token for long lived user access token (60 days). Not quite a refresh_token. The long lived_token does expired too whereas the refresh token lives until revoked.

Going back to code

Remember GoogleDrive client app which main goal is to connect to google drive and retrieve a list of document. Let's see how AeroGear OAuth2 deal with refreshing tokens.

In the main ViewController file, AGViewController.m:
    AGAuthorizer* authorizer = [AGAuthorizer authorizer];
    
    _restAuthzModule = [authorizer authz:^(id config) {      [1]
        config.name = @"restAuthMod";
        config.baseURL = [[NSURL alloc] initWithString:@"https://accounts.google.com"];
        config.authzEndpoint = @"/o/oauth2/auth";
        config.accessTokenEndpoint = @"/o/oauth2/token";
        config.revokeTokenEndpoint = @"/o/oauth2/revoke";
        config.clientId = @"XXX";
        config.redirectURL = @"org.aerogear.GoogleDrive:/oauth2Callback";
        config.scopes = @[@"https://www.googleapis.com/auth/drive"];
    }];  

    NSString* readGoogleDriveURL = @"https://www.googleapis.com/drive/v2";
    NSURL* serverURL = [NSURL URLWithString:readGoogleDriveURL];
    AGPipeline* googleDocuments = [AGPipeline pipelineWithBaseURL:serverURL];

    id documents = [googleDocuments pipe:^(id config) {       [2]
        [config setName:@"files"];
        [config setAuthzModule:authzModule];                                        [3]
    }];

    [documents read:^(id responseObject) {                                          [4]
        _documents = [[self buildDocumentList:responseObject[0]] copy];
        [self.tableView reloadData];
    } failure:^(NSError *error) {
        // when an error occurs... at least log it to the console..
        NSLog(@"Read: An error occurred! \n%@", error);
    }];


In [1], Create an Authorization module, in [2] create a Pipe to read your Google Drive documents, injecting the authzModule into the pipe, and then we simply read the pipe!
You don't have to explicitly call requestAccessSuccess:failure: before reading a Pipe associated to an authzModule. If you don't call it the request will be done on your first CRUD operation on the pipe. However if you prefer to control when you want to ask the end-user for grant permission, you can call it explicitly.

Behind the hood, what is AeroGear doing for us?

Inside AeroGear iOS code

When you call a Pipe.read, AeroGear implicitly wrapped this call within a requestAccessSuccess:failure: call. But what does this method do? well it depends on you state...
-(void) requestAccessSuccess:(void (^)(id object))success
                     failure:(void (^)(NSError *error))failure {
    if (self.session.accessToken != nil && [self.session tokenIsNotExpired]) {
        // we already have a valid access token, nothing more to be done
        if (success) {
            success(self.session.accessToken);
        }
    } else if (self.session.refreshToken != nil) {
        // need to refresh token
        [self refreshAccessTokenSuccess:success failure:failure];
    } else {
        // ask for authorization code and once obtained exchange code for access token
        [self requestAuthorizationCodeSuccess:success failure:failure];
    }
}
If you already have valid token, you're fine just forward success, if your access token has expired but you have a refresh token, just go for a refresh and last if you don't have any them, you need to go for the full grant pop-up.

Don't want to ask grant at each start-up

Ok fine, I have a mechanism to be able to ask only once at each client start up for access token and refresh token, then if I don't want to ask each time I start the app. Storing the tokens seem the way to go... I'll tell you more about AGAccountManager in my next blog post and how you can safely store your tokens.

To see complete source code for GoogleDrive app go to aerogear-ios-cookbook.

Friday, May 23, 2014

Mobile and lightening talks at JSSophia

Last JSSophia event was hosted at CrossKnowledge (big thank you to Matthieu and Stephane). We had a guest speaker Erik, coming from Switzerland to talk about Cordova. Live demo, always comes with surprise specially when not run on your computer ;)

As always in JSSophia meet-up, a very interactive session where you ask, participate, give your view and share with the speaker and the audience. It was really fun to have you Erik :)

Second part was lightening talks, starring:
Mathieu for a 5 minutes, fast paced introduction on Browserify: Bertrand to carry on with noderjs: Sebastien with the wifi back on time, talking about Firefox OS app: Bertrand show us how to debug on Cordova Android: Fred on MEAN: and last but not least, Yacine on Ionic (trolling on jqm): See you at next JSSophia, stay tuned!

Tuesday, May 20, 2014

OAuth2 grant flows

OAuth2 what is it for?

OAuth 2.0 is an authorization framework commonly used to grant applications limited access to a user's resources without exposing the users credentials to the application.

As simple as that. But guess what, there isn't just one way of granting. Let's visit the different OAuth2 grant types as described in the spec.

To go a bit deeper in details from my previous post on OAuth2-discussion-part1, I would list 4 actors:
  • authz server,
  • resource server, those two are generally separate server from your OAuth2 provider, the later responsible for serving resource checking if there a valid token the former, giving authorisation by providing the hop access token,
  • user (resource owner),
  • client (mobile app).
The most common flow is based on Authorisation code grant. See it explained in my last post with GoogleDrive as an exemple.

Delving deeper in OAuth2 specification, there is several grant types in order to provide an access token. From the spec, we can extract four authorisation grants:
  • Authorisation code grant
  • Implicit grant
  • Resource owner credentials grant
  • Client credentials grant

Authorization Code Grant

As said earlier, without doubt the most popular one and most probably the one you need ;)

On native app, this flow can be achieved either using an embedded browser or redirect the user to the native browser and then are redirected back to the app using a custom protocol (in iOS land, we use URL Schemes). For AeroGear-iOS OAuth2 library we use the latter. We’ll discuss more in details why in next blog post.

The authorisation code grant type is used to obtain both access tokens and refresh tokens. In next blog post, I shall also talk in detail about refreshing token flow;

Implicit grant

Ok this one target pure “web” app. From the spec: “In the implicit flow, instead of issuing the client an authorization code, the client is issued an access token directly (as the result of the resource owner authorization)”.

With the implicit grant you get straight an access token, but you don’t get refresh token. BTW, you can find an exemple of implementation in AeroGear-JS with its demo GoogleDrive cookbook recipe.

Resource Owner Password Credentials Grant

When this grant is implemented the client itself will ask the user for their username and password to get an access token. This is used for trusted client.

Client credentials grant

A variant of the previous one, except only the client credentials are used. Similar use cases. For exemple, Twitter decided to implement client credentials OAuth2 type.

What does it mean?
  • if your application only shows tweets from other users, you can get authorized using OAuth 2.
  • but if you want any users to use your app to post tweets or do anything else on a user's behalf, you should stick to OAuth 1.0a Twitter API.

Here are the 4 basic grant types. At those, you can add Refresh token grant and the extension grant (MAC token, JSON web, SAML). And of course, how much a provider is OAuth2 compliant is also source of variants...
But that will be the subject of another post ;)

Thursday, May 15, 2014

Testing without design footprint

Using OCMock for iOS test

Using mock libraries ease your unit testing in isolation. But as discussed in my previous post, we may end-up with a test oriented (over) layered design. Let's see how to test in isolation using mock but still leave a minimal footprint on your design.

Do your tests:

without checking everything


When a mock object receives a message that hasn't been either stubbed or expected, it throws an exception immediately and your test fails. This is called a strict mock behavior and this is just a pain...

Checking behavior rather than state, you want to write test easy to understand. Using nice mock, any type helps.

NOTE: What is the difference between expect and stub?
You may want to check the original post from Martin Fowler on Mock aren't Stubs.

TD;DR; You expect things that must happen, and stub things that might happen. In OCMock context, when you call verify on your mock (generally at the end of your test), it checks to make sure all of the methods you expected were actually called. If any were not, your test will fail. Methods that were stubbed are not verified.

Here we want to check the OAuth2 HTTP protocol.

        it(@"should issue a request for exchanging authz code for access token", ^{
            __block BOOL wasSuccessCallbackCalled = NO;
            void (^callbackSuccess)(id obj) = ^ void (id object) {wasSuccessCallbackCalled = YES;};
            void (^callbackFailure)(NSError *error) = ^ void (NSError *error) {};
            
            id mockAGHTTPClient = [OCMockObject mockForClass:[AGHttpClient class]]; // [1]
            NSString* code = @"CODE"; 
            
            AGRestOAuth2Module* myRestAuthzModule = [[AGRestOAuth2Module alloc] initWithConfig:config client:mockAGHTTPClient]; // [3]
            
            NSMutableDictionary* paramDict = [@{@"code":code, @"client_id":config.clientId, @"redirect_uri": config.redirectURL, @"grant_type":@"authorization_code"} mutableCopy];
            
            [[mockAGHTTPClient expect] POST:config.accessTokenEndpoint parameters:paramDict success:[OCMArg any] failure:[OCMArg any]]; // [2]
            
            [myRestAuthzModule exchangeAuthorizationCodeForAccessToken:code success:callbackSuccess failure:callbackFailure];
            
            [mockAGHTTPClient verify];
            [mockAGHTTPClient stopMocking];
        });


In [1], we create a mock with an expectation [2], the important part for the test is checking URL endpoint and parameters, for the other arguments I'll simply put any type: [OCMArg any].

without Dependency Injection


In the previous example, in [3] we see an example where we inject our mock within a real object. there is some cases where DI is not easy, could we still mock without injecting?

For example here I want to mock the following call [[UIApplication sharedApplication] openURL:url] within the method under test requestAuthorizationCodeSuccess:failure:, here is a way to
        it(@"should issue a request for authz code when no previous access grant was requested before", ^{
            __block BOOL wasSuccessCallbackCalled = NO;
            void (^callbackSuccess)(id obj) = ^ void (id object) {wasSuccessCallbackCalled = YES;};
            void (^callbackFailure)(NSError *error) = ^ void (NSError *error) {};
            
            //given a mock UIApplication
            id mockApplication = [OCMockObject mockForClass:[UIApplication class]];
            [[[mockApplication stub] andReturn:mockApplication] sharedApplication];
            [[mockApplication expect] openURL:[OCMArg any]];
            
            AGRestOAuth2Module* myRestAuthzModule = [[AGRestOAuth2Module alloc] initWithConfig:config];
            [myRestAuthzModule requestAuthorizationCodeSuccess:callbackSuccess failure:callbackFailure];

            [mockApplication verify];
            [mockApplication stopMocking];
        });


without splitting my classes in several layers


Without debating "one class should do one thing only" suppose, you have a class with several methods, you want to test one method and mock the other ones.

Here requestAccessSuccess:failure: method delegate its call to either refreshAccessTokenSuccess:failure: or exchangeAccessTokenSuccess:failure: depending if an access token and expiration date are present.

       
        it(@"should issue a refresh request when access token has expired", ^{
            
            void (^callbackSuccess)(id obj) = ^ void (id object) {};
            void (^callbackFailure)(NSError *error) = ^ void (NSError *error) {};
            
            restAuthzModule.session.accessTokens = @"ACCESS_TOKEN";
            restAuthzModule.session.refreshTokens = @"REFRESH_TOKEN";
            restAuthzModule.session.accessTokensExpirationDate = 0;
            
            // Create a partial mock of restAuthzModule
            id mock = [OCMockObject partialMockForObject:restAuthzModule];
            
            [[mock expect] refreshAccessTokenSuccess:[OCMArg any] failure:[OCMArg any]];
            
            [restAuthzModule requestAccessSuccess:callbackSuccess failure:callbackFailure];
            
            [mock verify];
            [mock stopMocking];
        });


I guess you got the idea. Test, whatever you need to test, don't go to close to the implementation.
Some may call it TDD vs. BDD, but I simply go: "Use what works best for you".

Wednesday, May 14, 2014

Is TDD dead for real?

After all the buzz around #isTDDDead on twitter, reading post from dhh, listening to RailsConf 2014 keynote, watching live streaming debate, I'm back coding. And I wonder...

After quite a few years spent in the trenches of XP, working with PowerMock/EasyMock/Mockito and all *Mock* pattern libraries, strong advocate of isolation testing, following test pyramid approach, automate testing at all layers as guide, what is this #isTDDDead all about?

It's not about automating test, it's not about unit test, both still seeing as a useful tool for developers. It's more about test first approach whatever your do, it's about 80% coverage criteria, it's about management measurement to make you feel sorry about your "dirty dirty code" (quoting dhh here). Wanting to unit test whatever it costs ie: overuse of mocks, dependency injection or single responsibility principle, refactoring code to make it testable. Test first approach and mockc overuse can lead to too-much layered design. Code where a class is doing just one single little thing and you need to dig deeper to eventually know what's it's all about. Cleaner code? Not so sure...

Back to code, today writing objective-C (I wish I can write french poetry too), I want to unit test my OAuth2 flow, guess what? I need to use mock. And you know what, I'll use OCMock, it might be in a different way though.

I can sleep happy, TDD is not dead or maybe it is but it's more like a Phoenix.

Back to code.

Sculpte, lime, cisèle;
Que ton rêve flottant
Se scelle
Dans le bloc résistant !