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)
...
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.
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');
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());
}
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.
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);
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
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.
There is one Solution
In your code Remove this
HttpConnection.setDoOutput(true);
It will work on ICS or Jelly Bean
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.
Related
I am testing an Android app which is connected to my local router. On the same WiFi network are also running some Java web services using Restlets. I verified that the Android app can hit the service filter and even receive a response from the service filter. However, it cannot seem to hit the Restlet service in question.
The full URL to the service is:
http://192.168.0.148:8080/MyApp/service/login
where 192.168.0.148 is the local IP address of the computer running the Restlet web services.
I have the service mapped in my Restlet Application class as follows:
router.attach("/login", LoginResource.class);
My web.xml file has the appropriate mappings to route anything with the pattern /service/ to the Restlet servlet.
I can successfully hit this service when testing from SOAP UI using precisely the same URL I gave above. In fact, all web services have been tested end-to-end using SOAP UI and are completely functional.
For some reason, the Android app can hit the service filter, when but when it reaches:
chain.doFilter(request, response);
the request ends up lost in space, and nothing gets returned.
I suspect that this is largely a Reslets configuration problem, though I don't know exactly what is happening here.
I got virtually no feedback, either from the SO community or from Restlets, which actually makes sense given that everything I reported in the question is correct. I decided to attach the Restlet sources to my IntelliJ IDE, and step through the code. I had seen that the Tomcat logs contained a response code of 415, and by inspecting the actual exception inside Restlets, I saw an error stating that the media type I posted was unexpected. Upon seeing this, I immediately knew what I had done wrong, which was:
not sending proper JSON to the login service
not declaring the content type to be JSON in the header of the POSt
and using Restlet services all of which expect JSON
For anyone who faces as similar problem using Restlets with JSON, the following Android code got everything working with no issues:
String endpoint = "http://192.168.0.148:8080/MyApp/service/login";
URL obj = new URL(endpoint);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
JSONObject json = new JSONObject();
json.put("username", username);
json.put("password", password);
// etc.
I tried looking for answers for this since last few days with no luck, Even some of the stackoverflow answers did not help.
I am trying to checkin a user after receiving his UserToken via Android. I get a FileNotfoundException at getInputStream(), non authenticated APIs like
"https://api.foursquare.com/v2/venues/categories" work well. Am i missing something?
URL url = new URL("https://api.foursquare.com/v2/checkins/add?oauth_token="+token);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.addRequestProperty("venueId","12238");
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setAllowUserInteraction(true);
conn.connect();
InputStream is = conn.getInputStream();
String response = streamToString(is);
return response;
Managed to solve this after lot of effort. See my answer below.
Try adding the oauth_token using the same method you use to add the venueid. Also, your venueid is invalid, so make sure you are checking the user in to a real venue.
The HttpURLConnection class is misleading in that it will throw a FileNotFoundException for any HTTP error code of 400 or above.
So it's not necessarily an incorrect URL (404) it could be 400 (bad request), 403 (forbidden), 500 (internal server error) etc.
Use the getResponseCode method to get a more precise indication of the problem.
first: Yoy have https url, and trying to create HttpURLConnection. You should use HttpsURLConnection.
Second: You can try to add conn.setDoOutput(true), "post" request requires it. And without it server can try give a get request from you despite on conn.setRequestMethod("POST"). Also you can check headers from your browser plugin, and put them into your request.
Okie I finally managed to solve the problem, I don't know what exactly was the problem with my code above but the following worked.
This API requires a POST call but even the venueID must be part of the URL and addRequestProperty does not seem to be sending the venueID properly. Hence I changed the code to
URL url = new URL("https://api.foursquare.com/v2/checkins/add?venueId=12238&oauth_token="+token);
And this solved the problem. Thanks all
I am having the following API call:
http://rollout.gr/api/?query={%22search%22:%22places%22,%22page%22:1}
This API call is executed correctly in my browser. But when I use a DefaultHttpClient to execute this url in my Android application, I get a null response.
I suppose the problem is the JSON data in the HTTP url. Thus, I would like to ask which is the proper way to handle such url in an Android application?
Thanks a lot in advance!
The accolades aren't valid URL characters. The browser is userfriendly enough to automatically URL-encode them, but DefaultHttpClient isn't. The correct line to use from code is:
http://rollout.gr/api/?query=http://rollout.gr/api/?query=%7b%22search%22:%22places%22,%22page%22:1%7d
Note the encoding for the accolades (%7b, %7d).
Your problem may be the strictmode here.
I recommend to do http request in threads or asynctasks. strictmode doesnt let app do http reauest in uithread. maybe your console shows a warning and you get null from http response because of this.
This project may solve your problem:
http://loopj.com/android-async-http/
Not knowing your particular HTTP initialization code, I'm going to assume you didn't provide an explicit JSON accept header. A lot of REST endpoints require this.
httpget.setHeader("Accept", "application/json");
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)
...
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.
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');
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());
}
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.
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);
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
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.
There is one Solution
In your code Remove this
HttpConnection.setDoOutput(true);
It will work on ICS or Jelly Bean
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.
I'm running into a strange problem using HttpClient. I am using a DefaultHttpClient() with HttpPost. I was using HttpGet with 100% success but now trying to switch to HttpPost as the REST API I'm using wants POST parameters rather than GET. (Only for some API calls though so I know that the GET calls were working fine so it's not a fault of the API).
Also, I tried using HttpPost on a simple php script I wrote that looks for a POST parameter 'var' and echoes it to screen, passing this parameters as follows worked fine:
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
postMethod = new HttpPost("http://www.examplewebsite.com");
nameValuePairs.add(new BasicNameValuePair("var", "lol"));
try {
postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
response = httpClient.execute(postMethod, responseHandler);
Log.i("RESTMethod", response);
...
The problem is that when I tried and do the same call to the API (but with the params changed to the API params obviously) I get the following error:
Authentication error: Unable to respond to any of these challenges: {}
The page I am requesting is an HTTPS page, could this be the problem?
But doing the same type of POST request to a raw HTTP page on the API gives the same error, unless I comment out the StringEntity part and then it runs (but returns xml and I want to pass a parameter to request the data in JSON).
This seems like a really strange problem (the non-https part) but couldn't really find any help on this problem so sorry if the answer is out there.
Any ideas?
Thanks in advance,
Infinitifzz
EDIT: Okay I'm getting nowhere so I thought if I directed you to the API it might shed some light, it's the 8Tracks API and as you can see you need to pass a dev key (api_key) for all requests and I the part I'm stuck on is using https to log a user in with: http://www.8tracks.com/sessions.xml" part.
Hope this helps somehow because I am at a dead end.
Thanks,
Infinitifizz
Authentication error: Unable to
respond to any of these challenges: {}
This error message means that the server responded with 401 (Unauthorized) status code but failed to provide a single auth challenge (WWW-Authenticate header) thus making it impossible for HttpClient to automatically recover from the authentication failure.
Most likely application expects some soft of credentials in the HTML form enclosed in the HTTP POST request.
Don't you have to declare the port and protocol? I'm just swagging this code so please don't be upset if it doesn't immediatley compile correctly. Also, I usually supply a UsernamePasswordCredentials to my setCredentials() but I imagine it's the same.
HttpHost host = new HttpHost("www.foo.com", 443, "https");
// assemble your GET or POST
client.getCredentialsProvider().setCredentials(new AuthScope(host.getHostName(), host.getPort()));
HttpResponse response = client.execute(host, [HttpPost or HttpGet]);
More info about setCredentials here.
Here's how I ended up with similar problem:
DefaultHttpClient client = new DefaultHttpClient();
client.getCredentialsProvider().setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
Thanks to Ryan for right direction.
Not specifying a Callback URL for my Twitter App resulted in the same error for me:
Authentication error: Unable to respond to any of these challenges: {oauth=WWW-Authenticate: OAuth realm="https://api.twitter.com"}
Setting a callback URL on Twitter fixed the problem