Android HttpURLConnection with HTTP Basic Authorization on RAILS Web Service - android

I'm trying around with the HttpURLConnection for quite some time now and I tried several solution posted here and on other places, but nothing seems to work.
I have the following architecture:
A Ruby on Rails Web Service (Rest interface with JSON)
An iPhone Client with RestKit
An Android Client with HttpURLConnection
The iPhone Client works like a charm. It connects to the web service with RestKit.
Now the Android Client is a completely different story. I always get a 401 Unauthorized message from the server (which results in a local FileNotFoundException).
The strange thing is, that the iPhone Client gets the same error, but RestKit somehow manages the handle it by sending the same request again. I tried that of course, but I just get the same error twice.
On the Rails Log Output it looks like this:
Started POST "/api/v1/login" for 127.0.0.1 at 2012-05-03 12:44:56 +0200
Processing by Api::V1::ApiController#session_login as JSON
Parameters: {"device"=>{"model"=>"Simulator", "system"=>"Android", "version"=>"Hugo", "name"=>"Android Simulator"}, "email"=>"florian.letz#simpliflow.com", "api"=>{"device"=>{"model"=>"Simulator", "system"=>"Android", "version"=>"Hugo", "name"=>"Android Simulator"}, "email"=>"florian.letz#simpliflow.com", "action"=>"session_login", "controller"=>"api/v1/api"}}
Filter chain halted as :require_login_from_http_basic rendered or redirected
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms)
The exact same message occurs when the iPhone Client connect's but then suddenly a magical second request occurs and it goes through.
On the Android Client I do the following:
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod(HTTP_POST);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Accept-Encoding", "gzip, deflate");
String userpassword = email + ":" + password;
con.setRequestProperty("Authorization", "Basic " + new String(Base64.encodeBase64(userpassword.getBytes())));
String body = jsonLogin.toString();
byte[] body_bytes = body.getBytes();
con.setRequestProperty("Content-Length", "" + Integer.toString(body_bytes.length));
con.setRequestProperty("Content-Language", "en-US");
con.setInstanceFollowRedirects(false);
con.setUseCaches (false);
con.setDoInput(true);
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream (con.getOutputStream ());
wr.write(body_bytes);
wr.flush ();
wr.close ();
InputStream is = con.getInputStream();
And on the last line the exception occurs.
I've read some things about redirects, but there is no redirect implemented at the server and I do not receive one on the client. I just get the 401 Unauthorized. The code in the web service and the iphone client indicate a quite simple workflow. Just send the data and receive the answer. I don't know where the SECOND login call comes from when the iPhone connects.
Does anyone here have any idea what the problem could be?
Thanks a lot!
EDIT #1:
I have identified the "magical" second request. The RestKit Log shows the following:
Asked if canAuthenticateAgainstProtectionSpace: with authenticationMethod = NSURLAuthenticationMethodDefault
This then results in the second request with quite a buch of headers I cannot make any sense of.
So do you know a way to implement this in Android?

Related

Android HttpURLConnection xml encoding

I am trying to send XML data with POST request to the server. But getting 500 error.
URL url = new URL(AFConstants.ServerEndPoint);
HttpURLConnection http = (HttpURLConnection) url.openConnection();
http.setRequestMethod("POST");
http.setRequestProperty("Content-Type",
"application/xml;charset=utf-8");
http.setDoOutput(true);
http.setDoInput(true);
http.connect();
DataOutputStream dataOutputStream = new DataOutputStream(http.getOutputStream());
String encoded = URLEncoder.encode(xml,"UTF-8");
dataOutputStream.writeBytes(encoded);
dataOutputStream.flush();
dataOutputStream.close();
Any ideas what is going wrong?
String xml contains this:
<?xml version=“1.0” encoding=“utf-8"?>
<AddSalesOrder revision=“8.0” environment=“Production” lang=“en-US” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=“C:\Data2\Ntp\shoprvparts\AddSalesOrder.xsd”>
<ApplicationArea>
...
</ApplicationArea>
<DataArea>
<Add confirm=“Always”/>
<SalesOrder>
<Header>
</Header>
<Line>
<LineNumber>1</LineNumber>
<OrderItem>
...
</OrderItem>
<OrderQuantity uom=“string”></OrderQuantity>
</Line>
</SalesOrder>
</DataArea>
</AddSalesOrder>
500 Internal Server Error or HTTP 500 - Internal Server Error
Cause of HTTP 500 Errors
Most of the time, "wrong" means an issue with the page or site's programming, but there's certainly a chance that the problem is on your end
so i think there will be error logs on the server and if you have access you can provide the server logs and will be easy to identify the problem

how to set authorization header with android's httpURLconnection

I am attempting to connect to my server using basic authentication, but when I set the Authorization header, it causes getInputStream to throw a fileNotFound exception.
Here is the relevant code:
URL url = new URL(myurl);
//set up the connection
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);//this is in milliseconds
conn.setConnectTimeout(15000);//this is in milliseconds
String authHeader = getAuthHeader(userID,pass);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setRequestProperty("authorization", authHeader);
//starts the query
conn.connect();
int response = conn.getResponseCode();
is = conn.getInputStream(); //throws the fileNotFound exception
Here is the thrown exception:
java.io.FileNotFoundException: http://<myIPaddress>/login/
Weirdly enough, I have found that the fileNotFound exception is only thrown if I try to set the request property to "authorization" or "Authorization" or any variation of that word. it is not thrown if I set it to "content-type" or "authosodifjsodfjs" (a random string), as here:
conn.setRequestProperty("content-type",authHeader)//no exception thrown
conn.setRequestProperty("authosodifjsodfjs",authHeader)//no exception thrown
If I don't set this header, I am able to connect to the server with this code and get the proper access-denied message that I am expecting.
I am also able to connect to the server and login properly if I use python's "requests" module, so it is not a problem with the server.
so my question is as follows:
1) what, if anything, am I doing wrong when setting the request property as "authorization"? how do I set the auth header properly?
2) if this is a bug with HttpURLConnection, how do I file a bug report?
Thank you.
edit: it was recommended to switch from:
conn.setRequestProperty("Authorization", authHeader);
to:
conn.addRequestProperty("Authorization", authHeader);
This did not fix the problem. It is still throwing the same exception.
EDIT:
still not sure why "Authorization" and "authorization" are causing fileNotFounExceptions, but using all caps seems to work properly. here is the shiny new working code:
conn.setRequestProperty("AUTHORIZATION",authHeader);
so it looks like it needs to be all caps. "HTTP_" will be automattically added to the front of this header, so the header that the server will see is "HTTP_AUTHORIZATION", which is what it should be.
Here is part of my OAuth code which sets Authorization header:
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setRequestProperty("User-Agent", "MyAgent");
httpUrlConnection.setConnectTimeout(30000);
httpUrlConnection.setReadTimeout(30000);
String baseAuthStr = APIKEY + ":" + APISECRET;
httpUrlConnection.addRequestProperty("Authorization", "Basic " + baseAuthStr);
httpUrlConnection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpUrlConnection.connect();

Pushbullet API via http in Android

How can I receive Pushbullet notes/images/profile details via API-Key on Android? My main problem is the SSL security in that point. (BTW: I'm pretty much a beginner in Android and only know the basics.)
The auth looks like this:
https://apikey#api.pushbullet.com/v2/users/me
I'm successfully requesting the content of a webpage (e.g. wikipedia.org) via
try {
URL url = new URL("https://www.wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
StringWriter writer = new StringWriter();
IOUtils.copy(in, writer);
theString = writer.toString();
textView.setText(theString);
} catch (Exception e) {
textView.setText("Error: "+e "String content: " +theString);
}
but when I'm requesting, for example, my profile details I'm always getting a
javaio FileNotFoundException
If you run your requests through https://www.runscope.com you can often see what the request is that your client is actually making (they have a free plan for trying it out).
If I had to guess I would say it's likely the authorization is not working correctly. Are you able to get that page using curl? It should look something like:
curl -u <apikey>: https://api.pushbullet.com/v2/users/me
Assuming that works, try something like
urlConnection.setRequestProperty("Authorization", "Bearer <apikey>");
or however it is you set headers on your HTTP requests. This is more explicit than relying on the https://password#domain url thing.

HttpURLConnection with server redirections

i'm trying to get the source code from a site using this code
conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(20000);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.addRequestProperty("User-Agent", "Mozilla/5.0");
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
int response = conn.getResponseCode();
if (response = 307){
String locationHeader = conn.getHeaderField("Location");
URL redirectURL = new URL(locationHeader);
...
}
when the server responds with a 307 code i create a new connection with the same parameters as above with the new url given by the server.
this code works fine while following the first 2 redirects, at the third the server gives a relative url that forces a MalformedURLException when my code executes ' new URL(locationHeader); '.
so i tried to fix that adding the ' http://servername/ ' to the ' locationHeader ' string but doing that creates a loop cause the server then redirects to the first url of his redirection chain.
since my browser gets the source code from that server with no problems is there a way to achieve that with HttpURLConnection?
if someone is interested thanks to Fiddler i worked out a solution to this issue.
first i changed the "User-Agent" property to mimic the one of Mozilla then i manually tweaked the cookie the serer was sending in its reply with the relative path.
that did the trick. thank you Fiddler.

Android POST Message Doesn't get Sent

I've encountered a rather strange error. I've written an android application that uploads an simple text file to a server. The code for the connection is as follows:
try {
URL = new URL(myURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="+"---");
DataOutputStream output = new DataOutPutstream(connection.getOutputStream());
output.writeBytes(<my post request>);
output.flush();
output.close();
connection.connect();
}
When I run this method, the post request is never sent over to the server. Nothing shows up on wireshark and if I look in logcat, there are no errors and the connection gets made fine, the POST message is just never sent. However, if I add a simple line right after the connection.connect() such as:
connection.getResponseCode();
Suddenly the POST message gets sent over no problem. What's going on here? Am I required to get a response code in order for the message to get sent over?
Why do you have to call URLConnection#getInputStream to be able to write out to URLConnection#getOutputStream?
In short you must call getInputStream() and close it. getResponseCode() is also working because it requires an established connection.
You do not need to call
connection.connect();
which is redundant.
You can get working sample from here: http://www.xyzws.com/Javafaq/how-to-use-httpurlconnection-post-data-to-web-server/139
You set doInput to true. Maybe the url connection waits for an input because of that. Try to set it to false. But I could also be wrong. It is just a guess.

Categories

Resources