2

I am getting FileNotFoundException when making GET call to REST API. Here HTTP status code I get is 403.
For POST call I get IOException : No authentication challenges found, whereas I pass Authorization header. Here I get HTTP status code 401.

Look at my already asked question to see the code and logcat screen shot for POST call.

Below I am attaching logcat screen shot for GET call :

enter image description here

Note :
1) I have tried using Authenticator.
2) Tried different base64 flags such as NO_WRAP, URL_SAFE, DEFAULT.
3) My simple call to www.google.com works.
4) When I log urlConnection.getErrorStream(), last line in image is printed. I don't understand what is that and what does it mean. I have specified Content-type to application/json in header.

UPDATE : I tried using Burp and found that headers "Accept", "Content-type" were different. I used the same as in iOS app. But still it does not work.

Things to note :
1) It always throws an Exception on the line in = urlConnection.getInputStream();.
2) I logged few things and according to it, content-length is 114, which is not null. content-type is application/json; charser=utf-8.

Community
  • 1
  • 1
Geek
  • 8,280
  • 17
  • 73
  • 137
  • Maybe the server delivers a gzip (compressed) answer and the lib cannot read that stream. – TeTeT Jun 17 '13 at 07:30
  • @TeTeT Ok. I don't think that server sends a gzip because I use same API in iOS app where I get JSON response. And even if server sends it, why I get FileNotFoundException and "No authentication challenges found"? Any idea. BTW thanks. – Geek Jun 17 '13 at 07:40
  • I tried your code and all I got was `404 : Invalid requested action ERROR_INVALID_ACTION_REQUEST` for the URL `http://api.ridesharebuddy.com/rsmobile/user/`. Is it the good URL ? – Raphaël Jun 24 '13 at 20:48
  • @Raphaël That URL is not enough to make request. You have to set method to GET and pass 2 header which I have not shown in code as they have not anything related to the problem. By the way I solved the problem and going to put as an answer so that others with similar issue can try that. – Geek Jun 25 '13 at 04:52
  • I think Raphael is right – bright Jun 26 '13 at 07:05
  • @bright I have solved my problem and you can it posted as an answer. – Geek Jun 26 '13 at 07:07

4 Answers4

3

There's a difference between your HTTP traffic for iOS and for Android. This is guaranteed, otherwise you'd get identical behaviour from the server. The difference is probably in HTTP header(s) &/or parameter(s).

This is very difficult to debug remotely via SO Q&A - E.g. we don't know what headers & parameters your iOS client is successfully using nor how your server is configured & programmed.

How to diagnose the problem & correct yourself:

  1. Trace your working HTTP traffic: iOS client <-> server
  2. Trace your non-working HTTP traffic: Android client <-> server
  3. Compare (2) and (3). For the most thorough comparison, save each HTTP request and response message as a separate file for (2) and (3), then diff the corresponding files.

Recommended HTTP tracing tools:

UPDATE

Seems you have the same problem for both GET and POST: the server is configured for BASIC authentication, but the client is not following the authentication protocol correctly. I think it just shows as a slightly different sympton in the two cases: for GET it says 'resource not found' (because you're not authenticated) and for POST the resource is given by you, but the server says you're not authorized to change the resource on the server. I suggest you've done enough (good!) debugging of request contents and now you should stop and focus on getting authentication working.

  1. Send you GET/POST request to the server without Authorization header
  2. Allow the server to prompt you for authentication with a 401 response with an WWW-Authenticate header containing a challenge string (e.g. WWW-Authenticate: Basic realm="Protected" see RFC 2617 HTTP Basic Authentication and Digest Authentication)
  3. Now send an additional GET request to server that (either without/with the original request contents), but includes the Authentication header, with Base 64 encoded username:password (Authorization: Basic ZnJhbms6ZmllZGxlcg==)
Glen Best
  • 22,769
  • 3
  • 58
  • 74
  • Good work. Thanks. :-) Did you see a response message with Burp? – Glen Best Jun 21 '13 at 07:04
  • I just see request in Burp. Do I need to make any change in settings to see response? Thanks to keep helping. – Geek Jun 21 '13 at 07:18
  • I am able to look at response. It always times out with coe 408. Yesterday also when using proxy server I was having this problem. If I turn proxy server off then I never get timeout and get exception as described in my question. – Geek Jun 21 '13 at 07:38
  • When you see the Request message displayed, then on the Interception tab click Forward. This sends the Request to the server, which returns the Response, which should then be displayed by Burp. – Glen Best Jun 21 '13 at 07:38
  • I had to make some changes in settings and I did that. Please look at my previous comment for update. – Geek Jun 21 '13 at 07:42
  • Ok. When you pass the request through a Proxy, the Proxy may insert the Date. If you then get 408, it would very likely be due to big clock time mismatch between Proxy and Server. – Glen Best Jun 21 '13 at 08:35
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/32134/discussion-between-akash-and-glen-best) – Geek Jun 21 '13 at 08:37
  • As I posted in chat message that I tried with what your update says but still problem persists. Another important thing I came to know is that running the same code in another machine gave correct response without any exception. Do you have any idea what can be wrong in this case? Thank you. – Geek Jun 24 '13 at 04:55
  • On one machine the same code works. May be on that machine it does not ask for authentication at all. Because pass `Authorization` header same way as shown in code. – Geek Jun 24 '13 at 05:13
  • To test whether you're authenticating correctly, create a test Servlet & debug by calling request.getRemoteUser() / getUserPrincipal() / isUserInRole(). If this doesn't work, forget everything else & make it work. – Glen Best Jun 24 '13 at 06:00
  • I just noticed that I don't even need to send my server authentication. So basically when user tries to login to my app, I call API to authenticate the user. when user enters correct details then I get response but when it is wrong then all this happens. So the whole question has changed now. Now, from client side it is ok but server side when wrong credentials are received, an exception is thrown and client side I should get that exception message. This happens with iOS app, but not in android. – Geek Jun 24 '13 at 07:25
  • So your app is not configured to use Basic Authentication? Instead you're using Form-Based Authentication? That's a significant difference. Immediately remove all use of Authenticate header. Follow a tutorial on using Servlets with form-based authentication... Make sure your Android app does login correctly before it does anything else. Cheers. – Glen Best Jun 24 '13 at 07:41
  • I solved my issue. To see, take a look at my answer. BTW Thank you for help and explanation. +1 for it. – Geek Jun 25 '13 at 04:53
  • Fabulous. Happy to help. BTW: there definitely would have been a difference between iOS & Android traffic. And the tracing & comparison would have shown that iOS did not use Authorization, but Android did. i.e. Think response above still stands. :) – Glen Best Jun 25 '13 at 06:27
0

I solved my problem and it is something I never tried to focus on while solving the problem.

I need not pass Authorization header. The thing is that there are 2 credentials come into the picture. one is server's authorization and second is credentials for login API. In my app, user creates an account and login to it. To authenticate the user I pass credentials to server and server authenticate it.

So when user enters correct credentials then response received is correct. And, in case of wrong credentials, my server passes a error message You are not authorized person, which I want to display to user(as in my iOS app). So the problem is here that HTTP status code (in case of wrong credentals) is 401 and that is why I don't receive the message sent by the server (and receive No authentication challenges found message).

The reason why I don't receive server message is that HttpUrlConnection don't give server response when HTTP status code is >= 400.

The only option to get error details in case status code 400 and above is to use getErrorStream() method and using that I was receiving No authentication challenges found message.

Finally, either I had to handle each status code, that is equal and above 400, at client side or I can use HttpClient, instead of HttpUrlConnection. And now I am moving to HttpClient.

Geek
  • 8,280
  • 17
  • 73
  • 137
0

I had a similar problem, and solved by passing the authenticated session cookie. Not sure if that is possible in your situation.

0
    AuthUser="foobar"
    AuthPass="password"
    URL targetUrl = new URL("http://www.google.com/");
    HttpURLConnection connection = (HttpURLConnection) targetUrl.openConnection();
    connection.setRequestMethod("GET");
    connection.setDoInput(true);
    String authStr = Base64Variants.MIME_NO_LINEFEEDS.encode((AuthUser+":"+AuthPass).getBytes());
    connection.addRequestProperty("Authorization", "Basic "+authStr);
    InputStream inputStream= connection.getInputStream();

I just run something like this and it worked perfectly for me. Just make sure you use Base64Variants.MIME_NO_LINEFEEDS and you should be able to create a proper authentication header. If that doesn't work, then you might have some problem on the server side.

rausted
  • 951
  • 5
  • 21