HttpURLConnection worked fine in Android 2.x but NOT in 4.1: No authentication challenges found
Asked Answered
L

9

30

I have some typical codes which used HttpURLConnection to get a file with an URL. They worked fine in android 1.x and 2.x. But failed in Android 4.1!

I searched on the web but found little similar information. Would anybody please help to investigate this issue?

private String mURLStr; 
private HttpURLConnection mHttpConnection;

...

url = new URL(mURLStr);

...

mHttpConnection = (HttpURLConnection) url.openConnection();
mHttpConnection.setDoOutput(true);
mHttpConnection.setRequestMethod("GET");

...

InputStream is = mHttpConnection.getInputStream();

The getInputStream method throws an exception:

08-01 15:56:48.856: W/System.err(13613): java.io.IOException: No authentication challenges found
08-01 15:56:48.856: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.getAuthorizationCredentials(HttpURLConnectionImpl.java:427)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.processAuthHeader(HttpURLConnectionImpl.java:407)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.processResponseHeaders(HttpURLConnectionImpl.java:356)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:292)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:168)
...
Lyonnesse answered 4/8, 2012 at 17:9 Comment(2)
It worked after I remove the line of ' mHttpConnection.setDoOutput(true)'! It seemed that this issue has the same reason of millions of others: Android 4.x turns http GET to POST if setDoOutput(true)! For your information: http://webdiary.com/tag/java-net-httpurlconnection/Lyonnesse
I do have the same problem, but I don't use setDoOutput(). Everything works fine on Android 4.0 Ice Cream Sandwich (ICS), but is broken on Android 4.1 Jelly Bean (JB). Btw, that setDoOutput() turns a request into a POST request makes totally sense, since a GET request should not have payload in the body.Rb
H
27

I am currently facing the same problem. On 4.1 Jelly Bean I receive an IOException "No authentication challenges found" when calling getResponseCode() on the HttpURLConnection.

I have searched online to see what has changed in the Android source code and found the following: 4.0.4 (working): https://bitbucket.org/seandroid/libcore/src/7ecbe081ec95/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java 4.1.1 (not working): https://bitbucket.org/seandroid/libcore/src/6b27266a2856/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java

As one can see in 4.1 JB the method getAuthorizationCredentials() throws the IOException. It parses the challenge headers it finds in the response using HeaderParser.parseChallenges(..), if the response code is 401 or 407. If the returned List is empty the Exception is thrown.

https://bitbucket.org/seandroid/libcore/src/6b27266a2856/luni/src/main/java/libcore/net/http/HeaderParser.java

We are currently investigating what exactly causes that List to be empty, but have the suspicion that our server might use realm=... instead of realm="..." in the challenge header. Missing quotation marks might be the cause for this problem. We have to investigate further if that is indeed the case and if we can make it work.

Hersch answered 28/9, 2012 at 16:15 Comment(5)
+1 For a clear explanation and the links to the code. The code also expects realm=" to be the first parameter after the scheme.Comeaux
By now we have been able to verify that the usage of realm= without quotation marks was indeed the reason which caused this error for us. We were able to change this on our backend side and now everything is working as expected.Hersch
I made my app work under android 4.x finally by just removing mHttpConnection.setDoOutput(true);。But I still had not knewn clearly about the root cause.Lyonnesse
+1 for Excellent response. Problem on my side was the server return of realm=... instead of realm="..." . Fixed that and app started working on both ICS and JBMastery
did you find a workaround for this? It works on kitkat, but not on JBResidue
C
26

Per RFC2617:

The 401 (Unauthorized) response message is used by an origin server to challenge the authorization of a user agent. This response MUST include a WWW-Authenticate header field containing at least one challenge applicable to the requested resource.

In Android, the HttpURLConnection getResponseCode() method throws java.io.IOException: No authentication challenges found when the server returns either a 401 Unauthorized or 407 Proxy Authentication Required status code without the WWW-Authenticate header set.

If you own the server-side API, then you can fix it by adding the required WWW-Authenticate header when you return 401 or 407. In my case, I fixed it in PHP as follows:

header('WWW-Authenticate: OAuth realm="users"');
header('HTTP/1.1 401 Unauthorized');
Candice answered 26/2, 2013 at 1:24 Comment(0)
D
6

I have the same problem. I found this workaround, but it is not working on Android 2. On Jelly Bean, it works fine. Just use getErrorStream() instead of getInputStream().

try
{
    responseStream = new BufferedInputStream(connection.getInputStream());
}
catch(IOException e)
{
    responseStream = new BufferedInputStream(connection.getErrorStream());
}
Diametrically answered 29/11, 2012 at 11:21 Comment(0)
M
1

Heading

I have fixed the problem for the Jelly bean. Please use the below code for the above scenario

DefaultHttpClient client = new DefaultHttpClient();
client.getCredentialsProvider().setCredentials(new AuthScope(null, -1), new UsernamePasswordCredentials(userName,userPass));
HttpGet request = new HttpGet();
request.addHeader("Accept", "application/xml");
request.setURI(new URI(service));
HttpResponse response = client.execute(request);

you got the proper response as you needed.

Maraca answered 14/2, 2013 at 6:34 Comment(0)
B
0

I ran into a similar issue with a web service that required cookies to operate correctly. Apparently Jelly Bean doesn't automatically create a cookie store by default (unlike previous versions), so the service wasn't able to find my session and threw a 401 every time I tried to access it. Adding the following lines of code to my application initialization fixed the problem:

// enable VM-wide cookie support for HttpUrlConnection
// see http://developer.android.com/reference/java/net/HttpURLConnection.html for details
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
Bedford answered 4/1, 2013 at 22:21 Comment(0)
I
0

When using Basic authentication and not calling setDoOutput(true) we still had this issue:

Here is the solution:

HTTP Basic Authentication issue on Android Jelly Bean 4.1 using HttpURLConnection

Intracellular answered 27/1, 2013 at 20:0 Comment(0)
C
0

Check if your server is returning an Error 401 - Not Authorised. I believe the Android code sees that response and believes it was meant to provide authentication details. In my case I was just providing the wrong token to my server.

Commence answered 7/5, 2013 at 10:55 Comment(0)
B
0

There is one Solution

In your code Remove this

HttpConnection.setDoOutput(true);

It will work on ICS or Jelly Bean

Bursiform answered 16/7, 2013 at 7:51 Comment(0)
P
0

A solution I used for this (I'm using Android's Volley library) was to use Square's OkHttp library. Their implementation correctly handles this issue and will return the 401 as expected.

Penitent answered 16/8, 2013 at 22:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.