Apache Cordova
  1. Apache Cordova
  2. CB-2415

On iOS the ajax error/fail callback is not called after server returns error code 401/unauthorized

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.2.0
    • Fix Version/s: None
    • Component/s: iOS
    • Labels:
    • Environment:

      OSX 10.8.2, Xcode 4.5.1, iOS Simulator 5.0, 5.1, 6.0, cordova 2.2

      Description

      I am seeing the same issue as reported in CB-2284 also in iOS. Ajax calls with Authorization header set are not returning but are timing out when the authorization credentials are invalid.

        Issue Links

          Activity

          Hide
          Dave Cobb added a comment - - edited

          Additional supporting commentary...

          Notes Regarding the Android fix that was noted as CB-2284:

          Unfortunately the fix (CB-2284) was applied to Cordova 2.4 and there seem to be some compatability issues (deprecated methods) with our project leveraging the (mediawiki) wikipedia app. As the patched version 2.4 of Cordova was still Beta, so unclear when to adopt this version and rectify references to deprecated methods.

          I tried incorporating a snapshot of the Cordova repo with the fix into our project but ran into the compatability issues (deprecated methods). Then I tried implementing the solution they have provided into a Cordova 2.1 build (which is what we are using for Android) and it seems to work for Android 4.* but not Android 2.* and some of the wikipedia plugins seem to fail (which I don't quite understand). Based on the limited scope of success and effort required for compatability I have not persued it farther than this.

          We are using Cordova 2.1 for Android and Cordova 2.2 for iOS

          Show
          Dave Cobb added a comment - - edited Additional supporting commentary... Notes Regarding the Android fix that was noted as CB-2284 : Unfortunately the fix ( CB-2284 ) was applied to Cordova 2.4 and there seem to be some compatability issues (deprecated methods) with our project leveraging the (mediawiki) wikipedia app. As the patched version 2.4 of Cordova was still Beta, so unclear when to adopt this version and rectify references to deprecated methods. I tried incorporating a snapshot of the Cordova repo with the fix into our project but ran into the compatability issues (deprecated methods). Then I tried implementing the solution they have provided into a Cordova 2.1 build (which is what we are using for Android) and it seems to work for Android 4.* but not Android 2.* and some of the wikipedia plugins seem to fail (which I don't quite understand). Based on the limited scope of success and effort required for compatability I have not persued it farther than this. We are using Cordova 2.1 for Android and Cordova 2.2 for iOS
          Hide
          Dave Cobb added a comment -

          Team is apprehensive to upgrade Cordova versions until the mediawiki project updates their version of Cordova and resolves any deprecated methods. Thus, preference would be to get patch to iOS Codova 2.2 and Android Cordova 2.1

          Show
          Dave Cobb added a comment - Team is apprehensive to upgrade Cordova versions until the mediawiki project updates their version of Cordova and resolves any deprecated methods. Thus, preference would be to get patch to iOS Codova 2.2 and Android Cordova 2.1
          Hide
          Dave Cobb added a comment -

          Note: 401 error occurs when invalid credentials are supplied to a reverse-proxy implementing basic authentication.

          Show
          Dave Cobb added a comment - Note: 401 error occurs when invalid credentials are supplied to a reverse-proxy implementing basic authentication.
          Hide
          Andrew Grieve added a comment -

          Some sample code here would go a long way. E.g. what's a test server we can hit, and what should we set the Authorization header to? Is this for XHRs, or for FileTransfer? Also, please confirm that this is an issue on both iOS and Android?

          Show
          Andrew Grieve added a comment - Some sample code here would go a long way. E.g. what's a test server we can hit, and what should we set the Authorization header to? Is this for XHRs, or for FileTransfer? Also, please confirm that this is an issue on both iOS and Android?
          Hide
          Zach White added a comment -

          I have created this project to show the issue. It authenticates against a server which uses Basic Auth as provided by apache .htaccess file. Please clone and try for yourself.

          To answer your questions:
          1. The issue is with XHR (specifically using jQuery but have tried with standard XMLHttpRequest to make sure jQuery was not the problem).
          2. I am seeing this in iOS with Cordova 2.2. Android had the known issue prior to 2.4.0 if I'm not mistaken, according to the bug I have linked in my description.

          Thank you!

          Show
          Zach White added a comment - I have created this project to show the issue. It authenticates against a server which uses Basic Auth as provided by apache .htaccess file. Please clone and try for yourself. To answer your questions: 1. The issue is with XHR (specifically using jQuery but have tried with standard XMLHttpRequest to make sure jQuery was not the problem). 2. I am seeing this in iOS with Cordova 2.2. Android had the known issue prior to 2.4.0 if I'm not mistaken, according to the bug I have linked in my description. Thank you!
          Hide
          Dave Cobb added a comment -

          Great.. Thanks

          Show
          Dave Cobb added a comment - Great.. Thanks
          Hide
          Zach White added a comment - - edited

          Here is the issue description as I have come to understand it

          In an effort to give each application it's own unique feel, Apple did not implement a Basic Authorization popup in their UIWebView. Instead they provided delegate methods (such as didReceiveAuthenticationChallenge for NSURLConnection) for their connection classes so that each application could handle the auth challenge in their own way (as far as prompting the user and such). Since Cordova allows all web requests coming from UIWebView to pass through to the default loading system, and no implementation is given by Cordova to handle an auth challenge; when an auth challenge is given by the server, Cordova (at the JS level) is oblivious and thus the $.ajax or XHR request appears to hang.

          Here is the solution that I would propose

          The solution that I found was to have Cordova handle all of the http(s) requests. I created a class CDVURLConnection to handle connection and delegation of these requests. If an auth challenge is received, it will give the 401 back to the loading system (and thus the JS layer) and then the Cordova developer can decide what to do from there.

          I have updated the project found here with the solution I propose to this issue.

          If handling all http(s) requests seems too scary (though it's working fine for me for everything I've thrown at it), perhaps a flag could be added to the config.xml saying whether your app will use requests with Basic Auth and thus will need this functionality or not.

          Thanks

          PS Again please note that this is only an iOS issue.

          Show
          Zach White added a comment - - edited Here is the issue description as I have come to understand it In an effort to give each application it's own unique feel, Apple did not implement a Basic Authorization popup in their UIWebView. Instead they provided delegate methods (such as didReceiveAuthenticationChallenge for NSURLConnection) for their connection classes so that each application could handle the auth challenge in their own way (as far as prompting the user and such). Since Cordova allows all web requests coming from UIWebView to pass through to the default loading system, and no implementation is given by Cordova to handle an auth challenge; when an auth challenge is given by the server, Cordova (at the JS level) is oblivious and thus the $.ajax or XHR request appears to hang. Here is the solution that I would propose The solution that I found was to have Cordova handle all of the http(s) requests. I created a class CDVURLConnection to handle connection and delegation of these requests. If an auth challenge is received, it will give the 401 back to the loading system (and thus the JS layer) and then the Cordova developer can decide what to do from there. I have updated the project found here with the solution I propose to this issue. If handling all http(s) requests seems too scary (though it's working fine for me for everything I've thrown at it), perhaps a flag could be added to the config.xml saying whether your app will use requests with Basic Auth and thus will need this functionality or not. Thanks PS Again please note that this is only an iOS issue .
          Hide
          Shazron Abdullah added a comment -

          I'm adding a mobile-spec test for this as a first step. Since this is a drastic change (imo) it should be discussed in the dev@cordova.apache.org mailing list as the next step.

          Show
          Shazron Abdullah added a comment - I'm adding a mobile-spec test for this as a first step. Since this is a drastic change (imo) it should be discussed in the dev@cordova.apache.org mailing list as the next step.
          Hide
          Shazron Abdullah added a comment -

          Windows Phone 8 CB-2428 and Android CB-2962 (see related issues section) have this same problem. Mailing list discussion here: http://markmail.org/thread/sbj5oczow2mbfwmr

          Show
          Shazron Abdullah added a comment - Windows Phone 8 CB-2428 and Android CB-2962 (see related issues section) have this same problem. Mailing list discussion here: http://markmail.org/thread/sbj5oczow2mbfwmr
          Hide
          Tim Croydon added a comment -

          I'm still seeing this in 3.1.0 on iOS7. Looks like it's been around for a while - this StackOverflow post has a couple of JS workarounds that may help in certain cases: http://stackoverflow.com/questions/12060619/not-getting-401-unauthorised-with-cordova-jquery-ajax-call-upto-phonegap-1-4-i

          Show
          Tim Croydon added a comment - I'm still seeing this in 3.1.0 on iOS7. Looks like it's been around for a while - this StackOverflow post has a couple of JS workarounds that may help in certain cases: http://stackoverflow.com/questions/12060619/not-getting-401-unauthorised-with-cordova-jquery-ajax-call-upto-phonegap-1-4-i
          Hide
          Bart van Velden added a comment -

          To my latest experiences this issue is still present in cordova 3.2.0-0.2.0.

          Show
          Bart van Velden added a comment - To my latest experiences this issue is still present in cordova 3.2.0-0.2.0.
          Hide
          Edwin Klesman added a comment -

          This is also still present in builds using the Cordova CLI version 3.3.1-0.1.2 under iOS 7.
          Now I know about the origin of this issue but this one cost us quite some hours (simply because there were no symptoms, just an AJAX call that went down the drain without callbacks).

          Using async: false in the $.ajax call handled the issue for our situation (a performant call from a login screen that doesn't really need async) but that is not really a clean workaround.

          At least capturing this issue and make it hookable in the JS layer of Phonegap should be a very nice solution. Like Zach mentioned.

          Show
          Edwin Klesman added a comment - This is also still present in builds using the Cordova CLI version 3.3.1-0.1.2 under iOS 7. Now I know about the origin of this issue but this one cost us quite some hours (simply because there were no symptoms, just an AJAX call that went down the drain without callbacks). Using async: false in the $.ajax call handled the issue for our situation (a performant call from a login screen that doesn't really need async) but that is not really a clean workaround. At least capturing this issue and make it hookable in the JS layer of Phonegap should be a very nice solution. Like Zach mentioned.
          Hide
          Alon Raskin added a comment -

          We are seeing this issue with iOS 7 and Cordova 3.4.0. If anyone wants to fix this we will happily provide a server for them to test against. One thing to note is that it seems to be related to the server returning the "'WWW-Authenticate'" in the response headers. If the server does NOT return this header then the 401 is returned correctly to the JS layer. Unfortunately this header is part of the 401 standard so we cant really control whether this header is returned or not.

          Show
          Alon Raskin added a comment - We are seeing this issue with iOS 7 and Cordova 3.4.0. If anyone wants to fix this we will happily provide a server for them to test against. One thing to note is that it seems to be related to the server returning the "'WWW-Authenticate'" in the response headers. If the server does NOT return this header then the 401 is returned correctly to the JS layer. Unfortunately this header is part of the 401 standard so we cant really control whether this header is returned or not.
          Hide
          Username Password added a comment -

          Guys, please fix this ridiculous bug, unless you're leaving it open intentionally.

          Servers are not under our control. An app developer cannot go around asking clients to turn off WWW-Authenticate headers, since its also part of the RFC.

          Show
          Username Password added a comment - Guys, please fix this ridiculous bug, unless you're leaving it open intentionally. Servers are not under our control. An app developer cannot go around asking clients to turn off WWW-Authenticate headers, since its also part of the RFC.
          Hide
          Username Password added a comment -

          @Zach White, this is not only an IOS issue. It affects Cordova in general. Is this bug enabling you guys to keep a backdoor open somewhere for your friends in Apple?

          Show
          Username Password added a comment - @Zach White, this is not only an IOS issue. It affects Cordova in general. Is this bug enabling you guys to keep a backdoor open somewhere for your friends in Apple?
          Hide
          Ryan Murphy added a comment -

          +1 for this getting fixed soon. For my enterprise clients I have no control over the HTTP responses.
          It's a really bad user experience to do always synchronous requests (especially since iOS 8 shortened the sync timeout). Or to always add a timeout on async requests and say "well, there was a timeout, I better treat it as a 401".

          Show
          Ryan Murphy added a comment - +1 for this getting fixed soon. For my enterprise clients I have no control over the HTTP responses. It's a really bad user experience to do always synchronous requests (especially since iOS 8 shortened the sync timeout). Or to always add a timeout on async requests and say "well, there was a timeout, I better treat it as a 401".
          Hide
          Martin Oss added a comment -

          Run into the same problem on my Cordova/Angular project on iOS. Wanted to redirect the user to the login page after getting a 401 from my Azure Mobile Services backend. Only happens on iOS in my case.
          Hope it will be fixed soon.

          Show
          Martin Oss added a comment - Run into the same problem on my Cordova/Angular project on iOS. Wanted to redirect the user to the login page after getting a 401 from my Azure Mobile Services backend. Only happens on iOS in my case. Hope it will be fixed soon.

            People

            • Assignee:
              Unassigned
              Reporter:
              Zach White
            • Votes:
              7 Vote for this issue
              Watchers:
              13 Start watching this issue

              Dates

              • Created:
                Updated:

                Development