Thursday, April 23, 2015

How well does Swift play with iOS7?

Swift was created with the Objective-C interoperability in mind. It's easy to get that Swift playing nicely with Objective-C was required in order to use existing cocoa API. At first, when trying interoperability, I mostly used Objective-C libs in my Swift app. But as I progress in my Swift immersion, I soon write reusable Swift code.

Apple stated it from day one:
  • you can also use Swift code from Objective-C app
  • as Swift applications compile into standard binaries plus some Xcode bundling Swift bits in your app, you can run Swift code on iOS 7.
You can run Swift code in iOS7 BUT there are several paths to drill down…

Do you want to run a Swift app on iOS7?


Let's talk about runtime


How does iOS7 understand Swift? Does iOS7 operating system includes Swift support?

Nope! It’s the other way around. Application with Swift code bundles Swift specific standard libs.

From Colemancda's blog post:
"With Swift, Apple has changed how standard libraries are shipped. With Objective-C, all of the standard libraries, system frameworks, and the runtime itself, were shipped with the OS. With Swift, Apple wanted the ability to quickly deprecate parts of the Swift Standard Library and also add new features. While these changes do break apps at the source code level, it would be a huge problem if shipped apps started to break because the standard library they are linked against has an incompatible API. Apple’s solution to the problem is to ship a specific version of the standard library with your app."

Besides, reading Swift blog post about Compatibility, I found that this statement is interesting: "When the binary interface stabilizes in a year or two, the Swift runtime will become part of the host OS and this limitation will no longer exist."

iOS8 brings a shinny new langage support: Swift but, the other correlated important change that happens is the way libraries are packaged. Running Swift on iOS7 also brings the question of how well Swift/Objective-C go together.

Let's talk about Objective-C / Swift impedance


So Swift code can be run even when called from Objective-C. Swift is a strongly type-safe language whereas Objective-C is dynamic by essence. It sometimes brings some blurry runtime behaviour (either crash or nothing happen) to watch out for when writing Swift code that aims to run on both Objective-C and Swift:

  • Swift pure object are not supported: you need to add @objc or inherit from NSObject if your class is visible from Objective-C.
  • Pay special attention to optional. I recommend this stackoverflow post for more reading.
  • Same goes when optionally casting.
  • Don’t use iOS8 api: of course… it seems obvious. But it's easy to forget tough and then you run into runtime exception - I say it from experience :))
  • Some enum support is available in Objective-C since Swift1.2.
etc... I will go in more details in a later blog post.

An interesting open source library which used the Swift first approach (code written in Swift first but compatible with Objective-C) is Quick. Most of the code is written in Swift some adapters in Objective-C are required when Swift paradigm won't fit (note: Quick and Nimble are DSL for BDD testing, DSL doe uses langage paradigm a lot).

Let's see an example


Here is an experiment I did: Run an HelloWorld app written in Swift on iOS7. That app registers to UnifiedPush Server. For this first experiment, let's just have one application with all the source code bundled together.

You can clone the Xcode6.3 code source:
git clone https://github.com/corinnekrych/unified-push-helloworld.git
cd unified-push-helloworld
git checkout ios7.experiment
open HelloWorldSwift.xcodeproj
and run it.

To run the app you will need a device with iOS7 installed because push notification can not be run from simulator. Also make sure the UPS instance is live on OpenShift. Alternatively if my OpenShift instance is not running, create your own server following the UPS guide.

Run the app on device. Go to UPS console, login with admin/admin. Go to "send message" right hand tab, and send a message. Your message should be displayed in the list of messages.

Now what about if we want to extract the code related to the UPS registration in an external lib?

Do you want to run Swift libs linked to Swift app on iOS7?


Dynamic framework


Swift libraries can only packaged using dynamic framework (sometimes called cocoa touch framework or embedded framework or bundled framework). Although dynamic frameworks are new to iOS8, they used to be used in OSX though for a while.

With Swift, you can’t package your Swift libs statically because static libs would lead to multiple runtimes in the final executable. We’re back to the point we discussed earlier in …: With Swift evolves quickly and ship its a specific version of the standard library with your app.

So you need to copy/paste your lib source code in your final app?

Cocoapods to the rescue


Or use cocoapods 0.36+ with the use_frameworks! option. I recommend you to read the excellent article from Marius: CocoaPods 0.36 - Framework and Swift Support. Behind the scene, cocoapods ensures all dependant libraries are bundled together with the same set of dylibs, which are embedded into the Frameworks subdirectory of the application bundle.

Using cocoapods brings an easy tooling to support dynamic framework with Swift.

Let's see an example


Let's take an simple app ChuckNorrisJoke (Yes! Chuck Norris is in the place) from aerogear-ios-cookbook written in Swift and let's use aerogear-ios-http (Swift too) an run the app on iOS7.

Originally aerogear-ios-http was designed with minimal deployment target to 8.0, in this experimental branch, I'm going to lower the deployment target to 7.0 and adjust some of the Swift code to fit iOS7.

git clone https://github.com/corinnekrych/aerogear-ios-cookbook
git checkout ios7.support
cd aerogear-ios-cookbook/ChuckNorrisJokes
pod install
open ChuckNorrisJokes.xcworkspace
Run on iOS7 device or on iOS7 simulator and enjoy chuck Norris humour :)

Take away


As we've seen, swift code can run on iOS7 and iOS8 but comes with some compromises:
  • writing code that comply with both Objective-C and Swift.
  • dynamic framework packaging. Using cocoapods takes some of the burden away.
  • last but not least, it certainly requires some extra testing as most of the errors will happen at runtime.
Swift is moving fast, and as we've seen the latest version (Swift 1.2 with iOS that ships with iOS8.3) brings improvement for compatibility with Objective-C (enum case). Interoperability is key to achieve developer's Nirvana of "easy maintenance": write once, deploy on both iOS7 and iOS8.

Thursday, February 26, 2015

Even more fun with playground in Xcode 6.3

I've just installed Xcode 6.3, it brings us even more fun with playground!

Last summer, I blogged about playground and how you can use them to do great interactive tutorial. With playgrounds... It's love at first sight. ❤ ❤ ❤ ❤

I think they are great learning tools. Apple's Guided tour made them popular from day 1.

I even use them in my lib repositories to demo how to use an API. For that simply, create a workspace with your framework code and attach a playground file. See playground has never been so fun for more details and check out Alamofire lib usage of playground.

When I first gave a presentation on Swift, I decided to write it with playground of cource :P
But, how to write your own guided tour?

At first, there was HTML...


Playgrounds are directory that can contain: resources (images, html), swift source (.swift file) and a description file (contents.xcplayground) to help rendering.



You define HTML page in Documentation folder, Swift source file directly under playground folder. Then using contents.xcplayground descriptive file you associate the different fragments together. As you're working with CSS, you can also customize you're own CSS. Don't specify too much the size etc... let Xcode preferences deal with that.

With Xcode 6.2, it renders as:



The annoying part, is when you open your playground and start changing the source file section, Xcode will generate a new file number: section-1.swift will become section-2.swift and so on...
Slightly annoying, I have to confess.

Then markdown-to-playground processing


Then emerged swift-playground-builder an open source project which takes a markdown input and generates a playground out of it. And that indeed, makes your life easier, you don't have to switch between source code and documentation file. But...

I'm afraid there is a 'but'. The main drawback is: as you write your tutorial you can't check your Swift syntax. You're in markdown file!

I personally prefer to stick to real source file and html.

To end up with markdown everywhere!




With markdown directly in swift source code, you can write source code and tutorial text at the same time by using special comment ```//:``` :
//: ### Immutability
//: ```let``` for constants => cannot change once initialized
//: ```var``` for variable => can be changed and can be optional. let name = "julie" let age = 18 println("Hello my name is \(name) and I am \(age) years old")
And it renders as:



The only slight 'but' here is about refreshing...
Difficult to write your comment in Xcode directly and have them refreshed. I usually work with Xcode opened for rendering and another editor for editing, triggering refreshing but switching Xcode current file. Caution when modifying contents.xcplayground, Xcode is picky on this and may get upset (yeah! good old Xcode crash are not gone!)

Writing interactive tutorial is really easy with Xcode 6.3. Follow the links if you want to see the source code of the Swift tutorial I've talked about in xcode 6.1 format or with the latest 6.3 format.
Happy Swifting!

Monday, January 12, 2015

Sharing Keychain access in a Share Extension

I've been wanted to do a blog post on how to achieve SSO on iOS using sharing Keychain for a bit...

And at the same time, I also wanted to try app extension very badly. So in an attempt to get the best of the two worlds, let's talk about writing a share extension to an app which need to store OAuth2 access token in a secure manner. We'll see how to share Keychain content through group-id between an app and its extension.

Remember Shoot'nShare app?
A simple app that takes pictures and allows you to share them with Facebook, GoogleDrive or even your own Keycloak backend. If we want to learn more about it, visit previous blog posts: To simplify, in this blog post we will focus on sharing to Google Drive only. As a pre-requisite, let's start creating a Google project.

OAuth2 Google Set up


If you want to create a google project to use for uploading files to Google Drive, follow the steps below:
  • Have a Google account
  • Go to Google cloud console, create a new project
  • Go to APIs & auth menu, then select APIs and turn on Drive API
  • Always in APIs & auth menu, select Credentials and hit create new client id button Select iOS client and enter your bundle id.
  • NOTES: Enter a correct bundle id as it will be use in URL schema to specify the callback URL. Please use your own unique BUNDLE_ID with format like org.YOUR_DOMAIN.Shoot replacing YOUR_DOMAIN with your actual domain.
Once completed you will have your information displayed as below:

Now that we've got your google project set up, let's add an Share Extension to Shoot app and see what's involved.

Share Extension


What it is?

An App extension add feature to an existing application. There are several types of extensions. The one we're interested in today is the share extensions. As the name says it all, this extension lets you share content with the external world. By default Xcode template will inherit from SLComposeServiceViewController. Therefore when hitting share button, a pop-up appears to send a message with image. Before iOS8, only a handset of providers were available to share content with. Those providers were defined directly in the operating system directly so the list was not flexible at all. Those days are over (yay!), you can now share with your favourite or even your own social networks directly from Photos app. This is exactly what we're going to do: let's share to GoogleDrive from Photos app via Shoot'nShare app.

One important thing to bear in mind extensions are not deployed by themselves. They must be packaged within a container app. Concretely in Xcode extensions are extension target within you container app.

Let's see an example

1. Get the project
Code source can be found in aerogear-ios-cookbook app.extension branch. Clone the repo and select the correct branch:
git clone git@github.com:aerogear/aerogear-ios-cookbook.git
git checkout AGIOS-224.shoot-extension
2. Define you own bundle_id
To be able to work with extension you need to enable App Groups. App Groups are closely linked to bundle identifiers. So let's change the BUNDLE_ID of the project to match your name. Select the Shoot project in the Project Navigator, and then select the Shoot target from the list of targets. On the General tab, update the Bundle Identifier to org.YOUR_DOMAIN.Shoot replacing YOUR_DOMAIN with your actual domain. Do the same for the extension target: select the Shoot project in the Project Navigator and then select the ShootExt target. On the General tab, update the Bundle Identifier to org.YOUR_DOMAIN.Shoot.ShootExt replacing YOUR_DOMAIN with your actual domain.

3. Configure App Group for Shoot target
In order for Shoot'nShare to share content with its extension, you’ll need to set up an App Group. App Groups allow access to group containers that are shared amongst related apps, or in this case your container app and extension. Select the Shoot project, switch to the Capabilities tab and enable App Groups by flicking the switch. Add a new group, name it group.org.YOUR_DOMAIN.Shoot, again replacing YOUR_DOMAIN with your actual domain.

4. Configure your App Group for ShootExt target
Open the Capabilities tab and enable App Groups. Select the group you created when setting up the Shoot project. The App Group simply allows both the extension and container app to share files. This is important because of the way files are uploaded when using the extension. Before uploading, image files are saved to the shared container. Then, they are scheduled for upload via a background task.

Sharing Keychain


With the same idea of sharing group between apps (or app and extension) to be able to have a common space for saving files, we can use Keychain group so that app and extension can share Keychain items. In our case we want a common space for Shoot app and Shoot Ext to share OAuth2 access token.

1. Configure Keychain Sharing for Shoot target
In order for Shoot'nShare to share access tokens with its extensions, you’ll need to set up a Keychain Sharing Group. Select the Shoot project in the Project Navigator, and then select the Shoot target from the list of targets. Now switch to the Capabilities tab and enable Keychain Sharing by flicking the switch. Add a new group, name it org.YOUR_DOMAIN.Shoot, again replacing YOUR_DOMAIN with your actual domain.

2. Configure Keychain Sharing for ShootExt target
Select the Shoot project in the Project Navigator and then select the ShootExt target. Open the Capabilities tab and enable Keychain Sharing. Select the group you created when setting up the Shoot project.

3. Configure Shoot App code
In Shoot/ViewController.swift modify:
    @IBAction func shareWithGoogleDrive() {

        let googleConfig = GoogleConfig(
            clientId: "YOUR_GOOGLE_APP_ID.apps.googleusercontent.com",
            scopes:["https://www.googleapis.com/auth/drive"])
        let ssoKeychainGroup = "YOUR_APP_ID_PREFIX.org.YOUR_DOMAIN.Shoot"
...
where YOUR_APP_ID_PREFIX is a unique alphanumeric identifier, you can view it on dev center:
and org.YOUR_DOMAIN.Shoot is you BUNDLE_ID.

4. Configure ShootExt code
In ShootExt/ViewController.swift modify:
    let ssoKeychainGroup = "357BX7TCT5.org.corinne.Shoot"
    let appGroup = "group.org.corinne.Shoot"

    override func didSelectPost() {      
        // We can not use googleconfig as per default it take your ext bundle id, here we want to takes shoot app bundle id for redirect_uri
        let googleConfig = Config(base: "https://accounts.google.com",
                authzEndpoint: "o/oauth2/auth",
                redirectURL: "org.YOUR_DOMAIN.Shoot:/oauth2Callback",
                accessTokenEndpoint: "o/oauth2/token",
                clientId: "YOUR_GOOGLE_APP_ID.apps.googleusercontent.com",
                refreshTokenEndpoint: "o/oauth2/token",
                revokeTokenEndpoint: "rest/revoke",
                scopes:["https://www.googleapis.com/auth/drive"])"
...
Replace:
the constant ssoKeychainGroup with your YOUR_APP_ID_PREFIX + BUNDLE_ID.
the constant appGroup with your App Group
in google config, redirectURL should match your BUNDLE_ID

5. Run the extension
To run shoot extension, select ShootExt target and run it, select Photos app as host app.
Select a photo, click on share button and select Shoot app. A Pop-up will appear, select send: you photo is uploaded on the background... and we're done. We've done all the configuration needed. Let's look at the code now.

Spot the Difference


Actually what we want to do from Share extension is basically the same as we do from Shoot'nShare app. But we do in an extension to allow us to do from Photos app. What about playing the difference game? What are the differences between uploading from Shoot'nShare app or uploading from ShootExt?

1. you can not trigger the OAuth2 danse from the extension
Extensions have limitations. Some API are not available. An app extension cannot access a sharedApplication object, and so cannot use any of the methods on that object. Difficult to trigger an external browser to launch the OAuth2 danse. Opening the container app in case no access tokens is available could be an alternative... However this alternative is offered only for today widget extension...

Indeed depending on extension type, some actions are allowed or forbidden. For example quoting apple doc : "only a today widget (and no other app extension type) can ask the system to open its containing app by calling the openURL:completionHandler: method of the NSExtensionContext class."

With our ShootExt, it would have been handy to be able to open Shoot'nShare app if no access token is available in the shared keychain. As our extension is a share extension, this is not available. As a result, we take as a pre-requisite that the end user has already shared a photo from Shoot'nShare app before using the extension. To do so we override OAuth2Module's requestAuthorizationCode method:
public class OAuth2ModuleExtension: OAuth2Module {
    // For extension we do not want to be redirected to browser to authenticate
    // As a pre-requisite we should have a valid access_token stored in Keychain
    override public func requestAuthorizationCode(completionHandler: (AnyObject?, NSError?) -> Void) {
        completionHandler("NO_TOKEN", nil)
    }
}
In case there is no token, we will return an error message to the end user asking him to use Shoot'nShare first.

2. you use the same redirect-uri OAuth2 for both extension and app
To do so, in ShootExt/ViewController.swift we can not use GoogleConfig class, we'll have to use Config class ans spscify shoot'nShare's redirect url as shown below:
        let googleConfig = Config(base: "https://accounts.google.com",
                authzEndpoint: "o/oauth2/auth",
                redirectURL: "org.YOUR_DOMAIN.Shoot:/oauth2Callback",
                accessTokenEndpoint: "o/oauth2/token",
                clientId: "YOUR_GOOGLE_APP_ID.apps.googleusercontent.com",
                refreshTokenEndpoint: "o/oauth2/token",
                revokeTokenEndpoint: "rest/revoke",
                scopes:["https://www.googleapis.com/auth/drive"])


3. you need to save in the Keychain using group-id
When we first save the access token in Shoot'nShare app, we need to specified the group-id, in Shoot/Viewcontroller.swift, we modify shareWithGoogleDrive method to accomodate it: In line7-10 we create a TrustedPersistantOAuth2Session object with a keychain group-id:
    @IBAction func shareWithGoogleDrive() {
         let googleConfig = GoogleConfig(
            clientId: "YOUR_GOOGLE_APP_ID.apps.googleusercontent.com",
            scopes:["https://www.googleapis.com/auth/drive"])
        let ssoKeychainGroup = "YOUR_APP_ID_PREFIX.org.YOUR_DOMAIN.Shoot"
        // We specify the keychain groupId, should be the same as the one used in Share extension
        let gdModule = OAuth2Module(config: googleConfig, 
                                    session: TrustedPersistantOAuth2Session(accountId: 
                                               "ACCOUNT_FOR_CLIENTID_\(googleConfig.clientId)", 
                                               groupId: ssoKeychainGroup))
        self.http.authzModule = gdModule
        self.performUpload("https://www.googleapis.com/upload/drive/v2/files", parameters: self.extractImageAsMultipartParams())
    }


4. you upload your photo in the background
Last but not least, when dealing with extension, remember that action will take place in the background! In our case we want to perform a multipart upload (we're using multipart Google endpoint) in the background. using aerogear-ios-http you can perform multipart background upload either using upload method with stream or file as shown line 28. It's also possible to use a POST method with multipart params (behind the scene a NSURSLSession upload is performed):
    override func didSelectPost() {
        let googleConfig = ....
        
        // Create a TrustedPersistantOAuth2Session with a groupId for keychain group sharing
        let gdModule = OAuth2ModuleExtension(config: googleConfig, session: 
TrustedPersistantOAuth2Session(accountId: "ACCOUNT_FOR_CLIENTID_\(googleConfig.clientId)", 
groupId: ssoKeychainGroup))
        
        self.http.authzModule = gdModule
        gdModule.requestAccess { (response: AnyObject?, error: NSError?) -> Void in
            var accessToken = response as? String
            if accessToken == "NO_TOKEN" {
                println("You should go to Shoot app and grant oauth2 access")
            } else {
                let imageURL = self.saveImage(self.imageToShare!, name: NSUUID().UUIDString)
                // multipart upload
                let multiPartData = MultiPartData(url: imageURL!,
                            mimeType: "image/jpg")
                let parameters = ["file": multiPartData]
                // multi-part upload could be achievd either with upload as a stream or using POST
                self.http.upload("https://www.googleapis.com/upload/drive/v2/files", 
                         stream: NSInputStream(URL: imageURL!)!, 
                         parameters: parameters, 
                         method: .POST, 
                         progress: { (ar1:Int64, ar2:Int64, arr3:Int64) -> Void in
                    println("Uploading...")
                    }) { (response: AnyObject?, error: NSError?) -> Void in
                    println("Uploaded: \(response) \(error)")
                }

            }
        }
    }


Hope your find this blog post useful and remember: it's all about Sharing...
Do not hesitate to share this link :)

Saturday, November 15, 2014

Devoxx 2014 in the eyes of a mobile developer

This year was my first Devoxx edition. On Sunday evening, going out of Antwerpen central station, I'm struck by all those sparkling shops on Keyserlei main road: diamonds all over the place!

As I’ll learn it later, Antwerpen is a well-known place for its diamond commerce.

Here is a summary of this Devoxx 2014 cru. As a disclaimer, I shall say that although I’ve been a Java guy for many years as a mobile developer, I very often do JavaScript and when going native, my platform of heart is not Android but iOS… As Ted said in his Swift for busy Java developer: I’m gonna tell you about Swift wearing my .NET T-shirt in a Java conference, it’s how it is nowadays…


With this in mind, I’d like to share with you my take-away sessions:

- “Using Traits, Mixins and Monads in JVM Languages”. What I like best about Venkat’s talks is how he goes from “what's the problem?” to the different solutions implemented in several languages (true polyglotism). And the problem starts with … diamond! (remember this old diamond issue in C++). Through live coding examples in Scala And Groovy we explore how to overcome the inheritance collidance with collaboration chaining behaviour like train wagons. Still on Monad, the very popular session “What Have the Monads Ever Done For Us?” (by Dick Wall) is the place where you learn you don’t need to know about Monads to use them. But to sound smart this winter, powder your tech chat with monoid, functor and monad off course (could be really handy as you talk about Swift actually).

- Swift made some buzz this year with 2 main sessions and being mentioned on several others: an university walk-through with interactive playground where Mike drives us through the intricacies of the language with playground samples. “Busy Java Developer's Guide to Apple's Swift” takes the same playground format with a very personalised style. Yes no cool CSS in playground but plenty of geek humour :) As I didn’t find any of those playground source code here is the link to one of mine.

- Develop your mobile app once in your favourite language and deploy it on iOS and Android. Still the Nirvana mantra for quick-win mobile development… If your language of choice is Java, see “Real cross-platform Java on mobile devices” session and how to use JavaFX to build your app on Android (LodgON) and iOS (RoboVM). UI is not yet native feel but it’s in the pipe for future as well as using Java8. If you’re a JavaScript ninja, go to “Use JavaScript to build Mobile Apps with Native UI” session to hear about Titanium. You have to learn a titanium specific API to build all your app including UI. but, UI get bridged into native widgets. As … stresses a lot no lowest common denominator, When you need to go platform specific use a if/else :))

- “Testing your Android app” to go through all testing layers from unit testing to instrumentation testing. Followed by “Espresso: What else?” makes me feel… jealous: so many testing frameworks for Android and soon Espresso part of development toolkit.

- Wednesday keynotes was done by Red Hat and our team work was show cased #ProudAeroGearDeveloper, let’s see it in picture:

and if you want to read more about it, see Markus’ blog.

- On security topic, I really enjoyed “Death to Cookies, Long Live JSON Web Tokens” from Auth0 team where you learn how to decode a json web token with utilities like jwt.io

- My favourite Java8 talk focuses on hidden gems rather than shining Stream and Lambdas. "50 new things we can do with Java 8": Let's ends this post with José Paumard final word: Diamonds are developer's best friends.

I couldn't agree more!

Corinne
PS: not to forgot the reason why I was there: my tools in action session OAuth2 for native apps ;)

Thursday, November 13, 2014

OAuth2 for Android and iOS with Keycloak

Like Jo, our brave iOS developer, you might have bumped into OAuth2 when writing an app that posts messages on Facebook wall. All cool social apps need to go through OAuth2 or OpenID authentication and authorization. Why?
Because so far it is the only broadly adopted open standard. So you might have heard : "It's complicated etc..". Not really if you use the right tools.

Mary, a cool mobile developer too, knows all about OAuth2. Follow Jo and Mary in their coffee break chat to learn in 5 mins OAuth2 howtos.

What's the problem?



- So Mary, to start with what is the problem we're trying to solve with OAuth?

- Easy. On one hand you have services… in the form of APIs. For example, we have twitter API to get list of followers, tweets etc… Those APIS handle your confidential data. As far as your data are protect by a login/password account, all is fine. But on the other hand, you have lots of apps that need to consume those services. The question is simple: do you trust them all to share your twitter login/password with them?

- I don't want my password all over the Internet!!!

- Therefore, use OAuth. OAuth2 allows users to grant third-party access to their web resources without sharing their passwords. We talk about a “delegated access" between mobile and user resources using a security token called an "access token".

Different actors and grants



- Mary, very often I hear about OAuth2 dance, who's involved? What is it?

- Actually there are 4 actors: authorization server (see our police man), responsible of authentication and authorization by providing an access token. The resource server, responsible for serving resources checking if there a valid token. The resource-owner, the end-user of the app, it could be you. And the client, in our case the mobile app.

- What is the dance all about?

- The interactions between those actors is described in OAuth2 spec as grant flows. This is the dance. There are different grant flows to fit different client app needs. A mobile app has diff needs that a single page browser-based app. In the spec, there are 4 different flows, you can group them in 2 different families:
3-legged flows where you grant permission from user. It includes "implicit grant" for browser based app not capable of keeping tokens secure and the "authorization code grant".
2-legged flows where the credentials are given to the app. In "resources owner credentials", this is the login/password whereas "client credential grant" takes client_id and client_secret.

- How do I know which one to use?

- It actually all boils down to two questions: "Is your client app capable of securely storing access tokens?" and "What is your trust relationship with the client app?" In your case, Jo, you should go for "authorization code grant".

Authorization Code Grant

step0: registration


- One of the pre-requisites you need to go through Jo, is to register your mobile app. For example, you go to Google cloud dev console, you create a project, fill in the form (add your redirect URI). And eventually you get a client_id and client/secret

step1: authz code




- With this client_id you’re all set to develop your OAuth2 app. Your Shoot'nShare app will send a request (including the client_id and the redirect_uri its scope) to the third-party service asking for an Authorization code. The app switches to external browser.

- Do you have to switch context?

- Actually, there are different approaches, you can also embed a web view in your app. It's better from a usability perspective. But from a security point of view it's seen as less secure, as your app sits between the login/password form and the provider.

- With external browser, it's actually the real Facebook login page?

- Exactly. The user logs in (if not already logged in), authz server shows a grant page to the end-user: Shoot’nShare would like to access yours contacts and photos Allow/Deny. If the user clicks on "Allow", the server redirects to the client using the redirect_uri (the one we talked during step0) and sends the Authorization Code to the mobile application.

step2: exchange for access token


- Now that we’ve got this temporary code we can go to the token endpoint to exchange it for a proper access token.

step3: get resources


- Using this token, our mobile app can access protected resources on server. Here you can do your upload!

How to implement OAuth2 on iOS?

- Mary, if I want to start coding the iOS version of Shoot'nShare just after our coffee, what are my options:

- You could use Social.famework from Apple, it will fit well for Facebook and a couple of other providers but it’s limited to those providers defined in settings. Here you actually provide your login/password but you trust your OS don’t you?

- ...

- You could use Facebook sdk but same here, limited to Facebook. If you want to share your photo to Google+, you need to use Google sdk and so on… - But Mary, there must be an open source library to help us…

- Yes! actually let me tell you more about AeroGear OAuth2 library... OAuth2 is one of the lib offers by AeroGear mobile suite. All client sdk are declined in iOS, Android, Windows(work in progress) for native paltforms. There is also a JavaScript sdk (and its Cordova plugins when needed). AeroGear is not only client SDKs, it also offers server bits like its UPS (UnifiedPush Server), if you want to send push notification to iOS/Android/Windows.



Want to see it in action?

- Let's see it in action, follow me in this screencast:


OAuth2 Server Side

- Mary, I try to foresee my product owner needs, what about if he wants an OAuth2 secured rest endpoint, server side? - No worries, I've got an answer for you and it's all Open Source: Keycloak

Shootn'Share demo

- Let's see it in action, follow me in this screencast:



Any feedback please drop us a line on AeroGear mailing list or contact Keycloak mailing list for more in-depth question on OAuth2/SSO server.

Happy OAuth2!

Thursday, October 16, 2014

AeroGear with Keycloak, OAuth2 friends for iOS apps... running with Swift

You might have bumped into OAuth2 when writing an app that posts messages on Facebook wall. All cool social apps need to go through OAuth2 or OpenID authentication and authorization. Why?
Because so far it is the only broadly adopted open standard. So you might have heard : "It's complicated etc..". Not really if you use the right tools.

Want to see it in action?



Shootn'Share demo

You want to take cool photos and share them with friends using GoogleDrive or Facebook account? With Shoot'nShare you can take pictures, browse your camera roll, pick a photo and share it! Photos get uploaded to your GoogleDrive or Facebook wall. You can also run this demo with its associated Keycloak backend and upload photo to your own social network :]

The purpose of this blog is not to show you how to take picture in iOS, so let's work on existing Shoot'nShare. Just clone it from github:


git clone https://github.com/aerogear/aerogear-ios-cookbook
cd aerogear-ios-cookbook
git checkout swift
open Shoot/Shoot.xcodeproj

Shoot'nShare project

In this initial project you will find aerogear-ios-oauth2 as a source dependency in Shoot/libs/AeroGearOAuth2 the library we will use for OAuth2 on iOS.

Google setup (optional)

NOTES: This step is optional if your want to try the GoogleDrive app out of the box. You can reuse the Shoot client id for 'GoogleDrive'. However if you want to create your own app, you will have to go through your provider setup instruction. Here's how to do it for Google Drive.

1. Have a Google account
2. Go to Google cloud console, create a new project
3. Go to APIs & auth menu, then select APIs and turn on Drive API
4. Always in APIs & auth menu, select Credentials and hit create new client id button Select iOS client and enter your bundle id.

NOTES: Enter a correct bundle id as it will be use in URL schema to specify the callback URL.

Once completed, you will have your client id!

Shoot'nShare redirect URI for Google

Open Info.plist of your project as source code to see XML format and define
 CFBundleURLTypes
 
  
   CFBundleURLSchemes
   
         org.aerogear.Shoot
   
  
 
This URL has to be unique (making it match your bundle id ensures unicity) and has to match OAuth2 server side configuration.


Google sharing

Let's start by implementing sharing with Google. In Shoot/shoot/ViewController.swift go to shareWithGoogleDrive:
    func shareWithGoogleDrive() {
        let googleConfig = GoogleConfig(
            clientId: "873670803862-g6pjsgt64gvp7r25edgf4154e8sld5nq.apps.googleusercontent.com",
            scopes:["https://www.googleapis.com/auth/drive"])
        
        let gdModule =  OAuth2Module(config: googleConfig)
        var http = Http()
        http.authzModule = gdModule
        
        gdModule.requestAccess { (response:AnyObject?, error:NSError?) -> Void in
            let filename = self.imageView.accessibilityIdentifier;
            let multiPartData = MultiPartData(data:UIImageJPEGRepresentation(self.imageView.image, 0.2),
                name: "image",
                filename: filename,
                mimeType: "image/jpg")
            http.POST("https://www.googleapis.com/upload/drive/v2/files", parameters: ["data": multiPartData], completionHandler: {(response, error) in
                if (error != nil) {
                    println("Error uploading file: \(error)")
                } else {
                    println("Successfully uploaded: " + response!.description)
                }
            })
        }
    }

In line 3 and 4, we use the client id (associated to Shoot Google app) and we specify the scope, here we share with google drive.

Line 6 and 7, we create an OAuth2 module. By default this module will create a TrustedSessionStorage to permanently store your tokens. Therefore every time your open your shoot app you can share photos without having to grant access everytime (see Notes below on iOS settings pre-requisites). You can choose a less secure MemorySessionStorage but each time you close your app and reopen it you will be prompted the first time to grant access.

Line 7 we initialize an http object and inject it the OAuth2 module.

In line 9, we actually request access. This method checks if the OAuth2Session (here stored in keychain) contains non-expired access token. If there is no token, it will go through the authorization code grant. If the token is expired (which happens every hour), a refreshed token will be asked transparently without any prompt.

NOTES: System requirement iOS8. Because this demo securely stores OAuth2 tokens in your iOS keychain, we've chosen to use WhenPasscodeSet policy for TrustedSessionStorage as a result to run this app you need to have your passcode set. For more details see WhenPasscodeSet blog post and Keychain and WhenPasscodeSet blog post.

Implicit http call

An even easier way to go, is to use aerogear-ios-http implicit grant. In the previous example we explicitly call requestAccess method. In Shoot/shoot/ViewController.swift change shareWithGoogleDrive by:
    func shareWithGoogleDrive() {
       let googleConfig = GoogleConfig(
           clientId: "873670803862-g6pjsgt64gvp7r25edgf4154e8sld5nq.apps.googleusercontent.com",
           scopes:["https://www.googleapis.com/auth/drive"])
        let gdModule = AccountManager.addGoogleAccount(googleConfig)
        self.http.authzModule = gdModule
        self.http.POST("https://www.googleapis.com/upload/drive/v2/files", parameters:  self.extractImageAsMultipartParams(), completionHandler: {(response, error) in
            if (error != nil) {
                self.presentAlert("Error", message: error!.localizedDescription)
            } else {
                self.presentAlert("Success", message: "Successfully uploaded!")
            }
        })
   }

In line 5, we use AccountManager to create an OAuth2 Module an factory method to create OAuth2 module.

In line 7, we just post our image to Google without having ask for access. POST method underneath checks if an OAuth2 module is plugged to http and will make the right call for you:
  • either start authz code grant
  • or refresh access code if needed
  • or simply run the POST if all tokens are already available

  • OAuth2 with Keycloak

    Ready to build your own social network app, let's use Keycloak and build OAuth2 protected service...

    First of all, you can download Keycloak all appliance distribution.

    Then, clone Shoot backend repo:


    git clone https://github.com/aerogear/aerogear-backend-cookbook
    cd aerogear-backend-cookbook/Shoot


    Following README instructions, import shoot-realm into Keycloak, your admin console should look like:



    NOTE: Here too the redirect URI matches our bundle id. For Keycloak, you can put whatever you want but as we have Google config using bundle ID, let's reuse :)

    Similar to the other providers, you can create your Keycloak OAuth2 module using AccountManager, simply use addAccount with the class type of your OAuth2 module, as shown below:
        func shareWithKeycloak() {
            println("Perform photo upload with Keycloak")
            
            var keycloakConfig = Config(base: "http://localhost:8080/auth",
                authzEndpoint: "realms/shoot-realm/tokens/login",
                redirectURL: "org.aerogear.Shoot://oauth2Callback",
                accessTokenEndpoint: "realms/shoot-realm/tokens/access/codes",
                clientId: "shoot-third-party",
                refreshTokenEndpoint: "realms/shoot-realm/tokens/refresh",
                revokeTokenEndpoint: "realms/shoot-realm/tokens/logout")
    
            let gdModule = AccountManager.addAccount(keycloakConfig, moduleClass: KeycloakOAuth2Module.self)
            self.http.authzModule = gdModule
            self.performUpload("http://localhost:8080/shoot/rest/photos", parameters: self.extractImageAsMultipartParams())
        }

    And that's it! Go and check uploaded pictures in shoot web-app:



    Any feedback please drop us a line on AeroGear mailing list or contact Keycloak mailing list for more in-depth question on OAuth2/SSO server.

    Happy OAuth2!

    Saturday, September 27, 2014

    Authenticate with TouchID



    Last blog, you saw how to store sensitive data in keychain and how to trigger touchID authentication when accessing them. In this post, you'll see how to use TouchID API for local authentication. No Keychain here.

    I've used this KeychainWrapper in a small app KeychainTouchIDTest hosted on github very much inspired by the one used on session 711 of WWDC 2014. but this one is written in Swift ;)

    Passcode Set

    TouchId is used in complement to passcode feature. If you want to use it you will need to have your passcode set in your iOS8 settings.

    LocalAuthentication and TouchID

    In your AppDelegate.swift class, define promptTouchId method:
        func promptTouchID() {
            var myContext = LAContext()
            var authError: NSError? = nil
            var myLocalizedReasonString:String = "Authenticate using your finger"
            if (myContext.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error:&authError)) {   // [1]
                
                myContext.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics,         // [2]
                    localizedReason: myLocalizedReasonString,                              // [3]
                    reply: {(success: Bool, error: NSError!)->() in
                        
                        if (success) {
                            println("User authenticated")
                        } else {
                            switch (error.code) {
                            case LAError.AuthenticationFailed.toRaw():
                                println("Authentication Failed")
                                
                            case LAError.UserCancel.toRaw():
                                println("User pressed Cancel button")
                                
                            case LAError.UserFallback.toRaw():                               // [4]
                                println("User pressed \"Enter Password\"")
                                
                            default:
                                
                                println("Touch ID is not configured")
                            }
                            
                        println("Authentication Fails");
                        let alert = UIAlertView(title: "Error", message: "Auth fails!", delegate: nil, cancelButtonTitle:"OK")
                        alert.show()
                    }
                })
            } else {
                println("Can not evaluate Touch ID");
                let alert = UIAlertView(title: "Error", message: "Your passcode should be set!", delegate: nil, cancelButtonTitle:"OK")
                alert.show()
            }
        }
    
    In [1], you first check wether passcode is set and touchId feature is available on this device.

    In [2], you call the authentication process. DeviceOwnerAuthenticationWithBiometrics is an enum which (for now) contains only one value. But future will open room for other means of authentication, let's keep an eye on WWDC next sessions.

    You can add an additional string in [3] which describes why you are doing this operation. You should always inform the user why he is prompted for Touch ID authentication.

    Allow a user fallback in [4]. Your user might want to authenticate by other means than finger recognition. You will have to implement your own password strategy, passcode fallback is not yet available on programmable API.

    To prompt at start-up, call promptTouchID method from application:didFinishLaunchingWithOptions: in AppDelegate:
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            promptTouchID()
            return true
        }
    
    I hope this serie of three posts: helped you get a view on what's new on TouchID and Keychain APIs on iOS8. Feel free to share your experience with it, I'd love to hear it.

    Happy iOS8!