New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 614555 link

Starred by 2 users

Issue metadata

Status: WontFix
Owner:
Closed: Jun 2017
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Android
Pri: 3
Type: Bug



Sign in to add a comment

Android WebViewClient's onReceivedHttpAuthRequest should provide previous failure count information for a site or resource

Reported by ssivakum...@gmail.com, May 24 2016

Issue description

Example URL:

Steps to reproduce the problem:
This bug is about a specific scenario that the WebView's authentication mechanism does not handle. Suppose there is a site (say site A) that fetches multiple resources from another authenticated site (say site B). Auth mechanism can be Basic or NTLM (both fail). The WebView fails to authenticate to the second site in this specific case when it tries to attempt authentication with "domain\username" first and if it fails, it tries with "username" alone without the domain. This is a common set up in enterprise scenarios where the WebView needs to first try with one option and fallback to another. 

The core of the problem is - when the WebView needs to authenticate to multiple requests in quick succession from the same host and if there is a fallback logic in the onReceivedHttpAuthRequest callback method, then the onReceivedHttpAuthRequest callback does not provide enough information to determine if the current callback is a fallback attempt for the first resource or a new attempt for the second resource. This mixes up the auth sequence in the callback method body.

This might sound convoluted, but the iOS WebView works fine in this scenario because it provides a "previousFailureCount" for every resource it tries to authenticate to. This way the application can identify the attempt count and change its behavior. Links to the iOS WebView API - 

This is the callback API - https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionDelegate_protocol/#//apple_ref/occ/intfm/NSURLSessionDelegate/URLSession:didReceiveChallenge:completionHandler:

One of its parameters is "challenge" which has a "previousFailureCount" object that can help the application understand the failure count - 

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSURLAuthenticationChallenge_Class/index.html#//apple_ref/occ/instp/NSURLAuthenticationChallenge/previousFailureCount

I have attached a replicator even though it is a little difficult to understand the problem. Steps - 

1. Download the rs-server.zip, extract the rs-server.jar and run it with: java -jar rs-server.jar 8123
   This starts a webserver on port 8123 that will serve images. This server expects requests to be authenticated using Basic authentication. Username : aryastark Password : gostarks!

2. Download the main-server.zip, extract the main-server.jar and run it with: java -jar main-server.jar 8124 10.20.30.40 8123
   Here the first argument is the port where the main server should run. The next two arguments are the host and port of the resource server which we ran in step 1. Running this step 2 will start another webserver which serves a page at "/authtest" which will fetch 3 images from the resource server and display them in a page.

3. Access the main server URL in a browser to test - http://main-server-ip:8124/authtest
  You will be prompted for authentication. Enter UN: aryastark PW: gostarks! and page will load with 3 images. So the site works!

4. Access the same site with the WebView in the sample application attached (AuthWebView.apk). Access the same URL and the page loading fails even though the code in the onReceivedHttpAuthRequest is expected to work (the auth credentials are provided). The code for the application is attached in AuthWebView_Source.zip. The code in onReceivedHttpAuthRequest first tries to authenticate using "domain\username" and when it gets a request again, it tries with "username" alone. Since the callback is called multiple times for the 3 different resources, the auth sequence is messed up and the authentication fails (the promptUser() method will be called).

Attachments - 

1) rs-server.zip - https://drive.google.com/open?id=0B215hnrL-RwOVTlmMGZFMkpBSmc
2) main-server.zip - https://drive.google.com/open?id=0B215hnrL-RwOeVRzaXN6bWxQSW8
3) AuthWebView.apk - Attached
4) AuthWebView_Source.zip - https://drive.google.com/open?id=0B215hnrL-RwOeVdDWXh4N2tFT3c

Possible Fix - 

The HttpAuthHandler in the onReceivedHttpAuthRequest callback can provide a method called getPreviousFailureCount() which can let the calling application know how many times the WebView has failed before in authenticating to this resource. This is similar to the API in iOS WebView. Based on this count, the application can change behavior. 

What is the expected behavior?

What went wrong?
See "Steps to reproduce" above.

Did this work before? No 

Chrome version: All  Channel: stable
OS Version: All
Flash Version: 

This is a companion bug for the Android WebView bug - https://code.google.com/p/android/issues/detail?id=211113

Basically, the onReceivedHttpAuthRequest API in the WebView should provide one more parameter. I am not sure if changes need to be made in Chromium engine for this to work. So I have created this bug/change request.
 
AuthWebView.apk
1.1 MB Download
Components: -Internals>Network Mobile>WebView

Comment 2 by torne@chromium.org, May 27 2016

This seems reasonable, but it will require an Android API change, which means that it will only be possible to get this extra information on future Android releases. You'll still have this problem on existing OS versions, unfortunately :/

Maybe we can think of a way to work around the lack of this information though?
Yeah, the old Android versions are a problem. But we need to fix it at least in the newer versions. Sooner the better.

I tried to alternate ways of fixing this problem, but I have run out of ideas. Any ideas are surely welcome.
Also, I have created an Android bug to track the API changes required - 

https://code.google.com/p/android/issues/detail?id=211113

Comment 5 by sgu...@chromium.org, May 27 2016

no need for android bug. we don't use them in webview team. this one is enough.

Comment 6 by boliu@chromium.org, Aug 15 2016

Owner: sgu...@chromium.org
Status: Assigned (was: Unconfirmed)
Cc: sgu...@chromium.org
Owner: ntfschr@chromium.org
WebView already has an API:

https://developer.android.com/reference/android/webkit/HttpAuthHandler.html#useHttpAuthUsernamePassword()

isn't it suitable for this case?

Nate, please investigate and add a new API if useHttpAuthUsernamePassword does not work for this case.
 
ssivakumaraw@: I'm trying out your sample server (running both servers locally on my desktop, and trying to log in with an incognito window from the desktop), but I'm running into issues.

Upon opening the page, I'm prompted to provide a username and password, as expected. After entering credentials, the image doesn't properly load (I see the image-not-found icon). I'm then prompted to enter credentials 2 more times, each time one more image-not-found appears, until I'm no longer prompted for credentials and there are 3 of the icons on the page.

Is it correct for me to be prompted 3 times, and for the images to not render? This seems a little different from your steps above, and I'm not sure if it could be a factor in the issue. Thanks.
Hi @ntfschr

I noticed that the "image not displayed" issue is because of a content length mismatch issue. There must be a bug in the way the image is server by the web server. I will check that. But the authentication succeeds and the data is sent. For now, you can ignore the missing images. Firefox manages to display the images.

As for the 3 prompts, I need to check. I think it is expected. In the WebView, the onReceivedHttpAuthRequest is supposed to be called thrice (once for every resource), but since incorrect credentials are sent the first time, there will be three more prompts. Going by this, then 3 prompts are expected in the desktop browser (one for every resource). However Firefox prompts only once (I am guessing it sends cached credentials instead of prompting the user). I will check what is happening on the server side and confirm the expected behavior in a day. 

Thanks.
ssivakumaraw@, thanks for the quick reply. It's strange that chrome and firefox behave differently with the images, but aside from that it looks like the desktop behavior makes sense.

I'll look into spinning up the server sometime tomorrow and testing it with the android app you provided and see if I can reproduce those results. Let me know if you make any changes to the app or java servers in the meantime.
ssivakumaraw@, also I just took a look at the app code (haven't run it yet). I don't know much about domains and usernames, but are you intending to separate the domain and username with 1 backslash, or with 2? In your app code (authtestwebview/MainActivity.java) line 61, you're using 1 backslash, but in line 72 you're using 2 backslashes.

Was this intentional? If so, could you explain what's the intended behavior in these parts? Thanks.
Hi @ntfschr - The four slashes in username.split("\\\\") (line 72) is intentional because the input to split() is a regex and "\" needs to be escaped in a regex. 

Here's the background behind the code in onReceivedHttpAuthRequest - 

I want my WebView to authenticate to a bunch of sites on an Enterprise network. Some of these sites accept the username ONLY WITH domain ("acmeinc\johndoe"). Some of the sites accept the username ONLY WITHOUT domain ("johndoe"). 

Given this, I also want to implement a user-friendly auth cache in my app. The purpose of this cache is to store credentials for reuse to other sites. If the user enters credentials for one site, I wish to reuse it for other sites. But since I don't know which sites require the domain, I always try with "domain\username" first and if it fails, I try with "username" alone. The code tries to achieve this. 

Note that handler.useHttpAuthUsernamePassword() returns true when the previously used credentials to that host were successful. It also returns true for the first callback to that host.

This is all the information we have and this is insufficient when the WebView tries to authenticate to multiple resources in quick succession within the same host. There is no way to tell if the second callback is for a new resource or for a re-attempt for the first resource.

Please do let me know if you require any other info regarding the code. I am working on checking the web server behavior. Will update soon.
I have fixed the content length issue on the rs-server jar. You can download the updated jar from the same link - https://drive.google.com/open?id=0B215hnrL-RwOVTlmMGZFMkpBSmc

The images are still messed up, but at least they are displayed. 

I also tried to understand why there were 3 prompts on Chrome. Chrome creates 3 TCP connections and makes one HTTP request on each connection to get the 3 resources. The webserver requires correct authentication headers on all HTTP requests. Hence Chrome prompts the user 3 times (one for every connection). I see the same server side behavior for Firefox. It creates 3 TCP connections and sends a HTTP request on every connection. The server requests for authentication on all. However, Firefox seems to reuse the credentials it received from the user on the first prompt. It does not prompt the user again.

Hope this helps. Please do let me know if you any more questions.
ssivakumaraw@, our corporate network makes peer-to-peer connections very difficult to set up. I thought one of our tools would work for getting around this, but I believe it does not support HTTP Authentication.

A public-facing server might work better for me to reproduce and test the issue. Would httpbin.org/basic-auth/ be a suitable server alternative, or is there something special about how your servers work? (It seems like the site may be down right now, but hopefully it'll be running smoothly soon). Thanks.
Labels: Needs-Feedback
ssivakumaraw@, is this still something that needs to be investigated? If so, are there are any end points at httpbin.org/ (or another public facing server) that would be suitable for testing this?
Hi @ntfschr, I could not dedicate time for this due to work. I will set this up in the next few days. 
Any further update on setting up a public facing server?
Labels: -Pri-2 Pri-3
Status: WontFix (was: Assigned)
Closing this due to lack of response. Please ping this bug if there's still a need for this and I'll gladly investigate.

Sign in to add a comment