johannes-staehlin / cordova-client-cert-authentication

Client Certificate Authentication for Android Cordova
Apache License 2.0
6 stars 8 forks source link

iOS Support #5

Open johannes-staehlin opened 7 years ago

johannes-staehlin commented 7 years ago

Currently, the plugin only supports Android. There seems to be a high demand of adding support for iOS. However, for iOS there are several challenges:

The Android implementation uses the android.security.KeyChain, providing access to the central KeyStore where all client certificates of the device are stored. Users are asked for permission and once access is granted to one certificate, it can be used for consecutive requests. Import of new certificates is handled by the Android OS and can be loaded from the device storage (e.g. Download folder).

From what I know, the "central" KeyChain of iOS, storing client certificates for authentication in Safari cannot be accessed from a custom application. Instead, every app can only access its own KeyChain. Other plugins (https://github.com/mwaylabs/cordova-plugin-client-certificate / https://github.com/zxyang/cordova-plugin-clientcertificate) target this problem by including the certificate in the /www folder of the Cordova project or requiring a hard-coded path. I don't like this solution at all for several reasons:

In order to support client-cert-authentication withing Cordova, I recommend having a similar behavior like on Android OS. This means managing (import/dialog to choose a cert) has to be handled programmatically:

  1. The user opens the Cordova app is asked to choose a certificate from the apps KeyChain via a native iOS dialog.
  2. The client cert can then be used for authentication of HTTP requests
  3. If no certificate is present, allow importing of the certificate from a valid source -or-
  4. Register the app to be able to handle *.p12 files --> If the certificate is sent via email, the attached cert can be opened by the Cordova app and storing it securely in its own KeyChain

I am not a good iOS developer so any help is welcome. I think the approach is very doable and also provides a good user experience, but I am also open to other suggestions.

brodycj commented 7 years ago

From some basic research I discovered the following resources:

Other possible resources:

Solving this would help a major client. I will post an initial, relatively small bounty, maybe my client will post an additional bounty.

brodycj commented 7 years ago

Bountysource

KeyCutter2 commented 7 years ago

I managed to combine "this" plugin with the mwaylabs plugin, to create a cross-platform client-certificate cordova solution. The mwaylabs plugin required quite a bit of modification and security improvements from memory.

brodycj commented 7 years ago

@KeyCutter2 do you have something ready to publish?

KeyCutter2 commented 7 years ago

The code is currently used commercially. It would require authorisation from my employer (which is potentially possible) but it would also require work to get it published. I will start the conversation on my end.

brodycj commented 7 years ago

Thanks, it would be much appreciated. Please keep us posted.

KeyCutter2 commented 7 years ago

Seems like my employer is interested in supporting the community, however due to financial restrictions this is less of a priority this side of Xmas. I mentioned about the bounty, which they were interested in, but thought it was not currently worth compromising the momentum unfortunately.

neptsoft commented 7 years ago

Thanks @johannes-staehlin for a great and detailed update. Also, thanks @brodybits , for posting the bounty. And thanks @KeyCutter2 for introducing us to your plugin solution. Dear @KeyCutter2, we are interested in helping make your solution publicly available, and we are willing to increase the bounty. What would be the bounty level which makes it happen before xmas? :)

KeyCutter2 commented 7 years ago

@neptsoft thanks for potentially helping enable this, I have had a quick review of the iOS code and it seems significant (~1000 lines). My employer has agreed to $6000, with a few details, including removal of employer specific code (de-identify) etc.

Also in terms of expectation setting, the code is functional but should be tidied up (a bit ad-hoc), its well commented. I will require some help, especially around creating the npm plugin and Apache license details. Automated tests exist but require a specific infrastructure so not worth publishing. The code supports download of the client-certificate over http/https and optionally "basic auth". There is quite a bit of error handling, it seems quite robust.

Hmmn, looks like I significantly added to the Android code as well and made a simple common code interface for both iOS & Android. I didn't budget for those Android changes when I approached my employer, @neptsoft are we within cost expectations? I don't want to rock the boat with my current employer if I ask for more time to do the Android stuff too. Perhaps $10,000 for both?

johannes-staehlin commented 7 years ago

Thanks for all the comments - this issue raised more attention than I thought. However, my intention of this project is pure of private purpose and driving forward the open source developer community, so I am not interested in any payments or donations.

I do get the point that adding bounties are a good way to reward the great work of others, but would like to ask you to take deeper payment discussions offline 😉

As mentioned, this project is for me on a completely non-commercial base and will stay as Apache 2.0 license, but whatever comes in as PR and has a good code quality, I can directly merge it and publish as a new version on npm (also on regular basis).

If - for any reason - someone insists to publish a new, similar plugin as a sperate repository, feel free to take any code from this repo and include me as a contributor in the README. I am also willing to officially mark this repo/npm plugin then as deprecated an point to the new one.

neptsoft commented 7 years ago

Thanks @KeyCutter2 for the review. Unfortunately those figures are way out of our league :( , it will have to be after Xmas then. And of course I understand: priorities are first.
Thanks again @johannes-staehlin for enabling this. Whatever is the result of this, it will be shared and your name will be there. I agree, guys let's take the bounty conversation in another place, My personal email is arlete2000@yahoo.com.

KeyCutter2 commented 7 years ago

Sorry for the delayed response getting back here, very busy and such!

Firstly to @johannes-staehlin sorry for this noisy conversation in your very pure and worthy project. Your project enabled me, so I was hoping to return the favour with some info about my experience, I guess the conversation changed after I discovered my employer was potentially willing to release the working code, which seems like a valid shortcut. And it is an honourable suggestion that you would graciously re-route the npm plugin from your creation, perhaps we could co-manage it somehow.

In regards to the after Xmas timing I'm hoping that this can happen, it was amazing technology to work on and I realised that it solved the 2-factor authentication problem which is mandated so much in critical communications (corporate, health, gov, public safety, etc) these days.

Providing a seamless common code solution was super difficult and took over 6 months. Also it was very difficult to do it in such a way that it would be e2e testable. So I am happy to try and alleviate other developers of this pain! Anyway I am looking forward to bringing this to the community somehow, I think it would enable a lot of benefits / solutions.

pliablepixels commented 7 years ago

Just added a $50 bounty. A common iOS/Android plugin that can prompt a user to select the right certificate is exactly what I need. Hardcoding the cert is not an option.

Thank you 👍

brodycj commented 6 years ago

After another quick review of the resources I gave in https://github.com/johannes-staehlin/cordova-client-cert-authentication/issues/5#issuecomment-336749494 I am no longer so enthusiastic about supporting this functionality for both Android and iOS within the same plugin. The reason is that the client certificate functionality seems to work differently in Android versus iOS. Here is my understanding right now:

On Android the user can download and install a standard certificate on the device, then use the standard selection mechanism to select the certificate needed to access a server. On iOS this is not really possible.

On iOS, the application has to open the certificate file and configure or store it somehow. But I think the certificate file cannot have the standard p12 extension since iOS has its own handler for that extension. And it may be necessary for the iOS app to handle user password very carefully, meaning never store user password itself.

Given the differences between Android and iOS, I would personally recommend supporting Android and iOS in separate plugins, and leaving it up to the application to deal with differences in platform-specific behavior.

References I used for this information, from https://github.com/johannes-staehlin/cordova-client-cert-authentication/issues/5#issuecomment-336749494:

It may be possible to come up with some kind of a more portable cross-platform solution based on IBM Connections solution as described in:

KeyCutter2 commented 6 years ago

I am terribly sorry for the delays and failed timeline expectations. I still have this project in mind but travelling close to the speed of light, you get relativity problems and gosh half a year has passed back here on earth already.

@brodybits I can help you with some information on that, if you let either the iOS or Android browser handle the certificate, it will override your download and assert it's own reality (place the certificate in the browser section of the key store). So you need to manage your own downloads and files and store the certificates correctly within the platforms key store.

Our test system uses the same .pfx file for testing on both platforms.

brodycj commented 6 years ago

Please post your solution if you can, I think it would help a lot of people.

On Wed, Sep 26, 2018 at 10:06 PM KeyCutter2 notifications@github.com wrote:

I am terribly sorry for the delays and failed timeline expectations. I still have this project in mind but travelling close to the speed of light, you get relativity problems and gosh half a year has passed back here on earth already.

@brodybits I can help you with some information on that, if you let either the iOS or Android browser handle the certificate, it will override your download and assert it's own reality (place the certificate in the browser section of the key store). So you need to manage your own downloads and files and store the certificates correctly within the platforms key store.

Our test system uses the same .pfx file for testing on both platforms.

brodycj commented 5 years ago

I found a possible solution for iOS, with a couple cross-platform forks:

A cross-platform solution based on the addictic/cordova-plugin-client-certificate-addictic fork should be more practical since that plugin uses the p12 key from the file system instead of working with the key chain.

johannes-staehlin commented 5 years ago

@brodybits - With https://github.com/johannes-staehlin/cordova-client-cert-authentication/issues/5#issuecomment-424494990 you exactly hit the point - Android and iOS just handle the client certificate flow completely different. I will probably also link that in the README. I am also not sure if a common cordova plugin makes sense, or you just want to target it differently - but if someone comes up with a good PR, I am open to merge it.

Just in general for: IMHO you should NEVER include a client certificate in the application itself/assets folder. That's not more secure than a hard-coded password. My recommended flow is still as mentioned in https://github.com/johannes-staehlin/cordova-client-cert-authentication/issues/5#issue-265485971.

In addition I want to point out that with Progressive Web Applications I think cordova is becoming more and more obsolete. Modern browsers allow applications access to the camera, microphone, local storage and can even send push notification (yes, not container required!) - Just some examples: https://pwa.rocks/ And the best: client certificate is handled in a "native way".

brodycj commented 5 years ago

Thanks @johannes-staehlin for the response.

In short the addictic/cordova-plugin-client-certificate-addictic seems to solve the problem by allowing the developer to use the certificate from a data directory, instead of forcing the app developer to include the client certificate in an assets folder (which we know is a really bad idea).

My recommended flow is still as mentioned in #5 (comment).

That points to the original description. I think it would be ideal if we could implement it that way. I would rather not build the iOS implementation from scratch if I can avoid it.

I think the right technical approach is described in https://stackoverflow.com/questions/35870572/how-to-implement-client-certificates-and-server-authentication-for-ios, with "part 2" of the solution broken into a second answer on the same question. I will still need some time to try it out.

The client certificate authentication is still pretty new for me and I need to make the best solution I can in a limited amount of time for my client. I think a major part is a callback function to handle the server trust challenge, which already seems to be handled by addictic/cordova-plugin-client-certificate-addictic.

An open question is whether to modify the existing plugin for iOS to register a file type, use a separate plugin to register for the file type (such as jperelli/cordova-plugin-register-filetype - has GPL v3 license which is not desired or cordova-file-association - Android only) and handle it in the app, or just have the app download the certificate on iOS. I will need some time to experiment and discuss with the client before making a final decision.

I am not certain whether or not I will try to integrate the iOS support together with this plugin. This would be nice to have but is not a required part of the scope for me.

brodycj commented 5 years ago

I was able to make a test program that reads the client key and access a test server using mwaylabs/cordova-plugin-client-certificate. I am using a p12 certificate in www for testing but that fork seems to be able to read the p12 certificate from any iOS data directory. This means that it should be possible for an application to use a third-party plugin to retrieve the p12 cert or perhaps even use JavaScript to download it somehow.

I did not have much luck with the addictic/cordova-plugin-client-certificate-addictic fork so far. It seems to have missed some of the updates from mwaylabs/cordova-plugin-client-certificate.

In terms of the file association I discovered that jperelli/cordova-plugin-register-filetype) has GPL v3 license and cordova-file-association is for Android only. j3k0/cordova-plugin-openwith might be able to do the trick, seems to have been designed for something else.

I discovered EbilPanda/cordova-plugin-client-certificate-ebilpanda fork which seems to add file association for iOS and replace the Android implementation with the code from this plugin, it did not seem to work for me.

I will now discuss with the client whether we should continue with the p12-like file association or just access the file system for iOS.

brodycj commented 5 years ago

I made a new iOS plugin version in https://github.com/brodybits/cordova-plugin-client-certificate/tree/myp12-support which supports p12 client certificates that can be registered via the JavaScript API or myp12 file association, with no password capability. This iOS plugin version is a combination of changes from multiple forks based on mwaylabs/cordova-plugin-client-certificate. I also made a quick test app with brief usage directions in https://github.com/brodybits/cordova-client-cert-test-wip. This plugin version has an Android implementation that has gone through multiple changes from multiple forks, which I have not tested so far.

I will now ask my client to validate the new iOS plugin version with the test app, will report whether it satisfies their needs or not.

brodycj commented 5 years ago

For the future I would like to see some improvements such as:

I cannot promise when I will get a chance to work on these improvements without an additional contract.

P.S. A bunch of combined plugin version updates are available in https://github.com/cordova-ccafix/cordova-plugin-client-certificate-support/tree/combined-updates (now pushed into the master branch of cordova-ccafix/cordova-plugin-client-certificate-support) in case they may help anyone.

brodycj commented 5 years ago

The combined version that I made for iOS and Android in https://github.com/cordova-ccafix/cordova-plugin-client-certificate-support was accepted by the customer, will be supported for the foreseeable future.