I am trying to log into a site and load a webpage programatically in android. Meaning, I have the password and login and need to submit a webform and get the response page. I tried the code here: Doing HTTP Post with Android
but I think I may be doing it wrong.
If this is the site I'm trying to access: http://goo.gl/eiBhP
and my code is
HttpClient httpclient = new DefaultHttpClient(httpParameters);
HttpPost httppost = new HttpPost(Constants.MAIN_URL);
List<namevaluepair> nameValuePairs = new ArrayList<namevaluepair>(2);
nameValuePairs.add(new BasicNameValuePair("username", "correctusername"));
nameValuePairs.add(new BasicNameValuePair("password", "correctpassword"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(httpost);
Then I should be able to use
BufferedReader br = new BufferedReader(new InputStreamReader(
entity.getContent()), 8096);
to get the response. The id of the login and pass on the site ate username and password. should I also somehow submit the button as a name value pair? I cant seem to get this to work, it just returns the login page. Please Help. I've tried reading over the other similar questions but I can't seem to get it to work.
Basically, you need to make sure that your code is submitting exactly the same information as the webpage.
As Selvin points out, there's a good chance that the website is using some form of tracking - be it in hidden input values, cookies or some other state-based data.
You need to look at the source of the login webpage and understand what it is doing when you submit login details - you don't necessarily need to know what all the values mean, but your code must submit the same POST data.
If the website is using state information, you won't be able to hard-code those input values in your code. You'll probably need to retrieve a new instance of the login webpage each time using a HTTP GET request and then parse the data to extract the relevant state data. Don't forget that they may also be using cookies which you may need to submit.
All in all, you probably need to do a lot more work to get it to a working state. Not trying to dissuade you (and I don't know what you're trying to achieve), but perhaps it's easier just to use the website!
Related
I am trying to login to a site using a login form and submit button in my app. I have been given the following api information:
the api has been set up at consumer.api.mobodev.terryinc.com
Using this api I am trying to login using a username. The following information has been provided for the api call:
Login with Username The Login with Username service is provided for
existing Consumers to login using their username and password. The
username will be either an email address or mobile phone number
depending on how the Consumer had initially registered. Login with
Username will typically be used when logging into a second or
subsequent Device, or via the browser etc. This is because in the
normal process flow, a Consumer will register and the Access Token
will be returned and cache by the Client Application. The Access
Token is then used when starting the application instead of getting
the Consumer to log in again. Calling the Login with Username logs the
Consumer into the system and creates and returns a valid OAuth Access
Token. The returned OAuth Access Token can then be used in for
subsequent API calls to identify the Consumer of the Client
Application. Attributes
Attribute Value
Path /v3/logins Support
Formats JSON, XML HTTP
Method POST
Secure No
Rate Limited
No Cache
Timeout TBC
-HTTP Codes 200 - OK
400 - Bad Request.
500 - Internal Server Error.
Below is the code that I have written in the main activity:
HttpClient httpclient = new DefaultHttpClient();
**HttpPost httppost = new HttpPost("consumer.api.mobodev.terryinc.com");**
try {
// Add user name and password
EditText uname = (EditText)findViewById(R.id.username);
String username = uname.getText().toString();
EditText pword = (EditText)findViewById(R.id.password);
String password = pword.getText().toString();
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
nameValuePairs.add(new BasicNameValuePair("grant_type","password"));
nameValuePairs.add(new BasicNameValuePair("username", username));
nameValuePairs.add(new BasicNameValuePair("password", password));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
Log.w("Post", "Execute HTTP Post Request");
HttpResponse response = httpclient.execute(httppost);
String str = inputStreamToString(response.getEntity().getContent()).toString();
Log.w("Before Post", str.toString());
My question is did I use the correct url when creating my httpPost object?
Please help as I have no idea how to interpret the api documentation.
In Firefox, there's this awesome add-on I use to simulate and test API calls - it's called Rest Client, and I recommend you test the apis here first before you code anything.
I'm writing an Android app that should get data from a certain web application. That web app is based on Servlets and JSP, and it's not mine; it's a public library's service. What is the most elegant way of getting this data?
I tried writing my own Servlet to handle requests and responses, but I can't get it to work. Servlet forwarding cannot be done, due to different contexts, and redirection doesn't work either, since it's a POST method... I mean, sure, I can write my own form that access the library's servlet easily enough, but the result is a jsp page.. Can I turn that page into a string or something? Somehow I don't think I can.. I'm stuck.
Can I do this in some other way? With php or whatever? Or maybe get that jsp page on my web server, and then somehow extract data from it (with jQuery maybe?) and send it to Android? I really don't want to display that jsp page in a browser to my users, I would like to take that data and create my own objects with it..
Just send a HTTP request programmatically. You can use Android's builtin HttpClient API for this. Or, a bit more low level, the Java's java.net.URLConnection (see also Using java.net.URLConnection to fire and handle HTTP requests). Both are capable of sending GET/POST requests and retrieving the response back as an InputStream, byte[] or String.
At most simplest, you can perform a GET as follows:
InputStream responseBody = new URL("http://example.com").openStream();
// ...
A POST is easier to be performed with HttpClient:
List<NameValuePair> params = new ArrayList<NameValuePair>(2);
params.add(new BasicNameValuePair("name1", "value1"));
params.add(new BasicNameValuePair("name2", "value2"));
HttpPost post = new HttpPost("http://example.com");
post.setEntity(new UrlEncodedFormEntity(params));
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
InputStream responseBody = response.getEntity().getContent();
// ...
If you need to parse the response as HTML (I'd however wonder if that "public library service" (is it really public?) doesn't really offer XML or JSON services which are way much easier to parse), Jsoup may be a life saver as to traversing and manipulating HTML the jQuery way. It also supports sending POST requests by the way, only not as fine grained as with HttpClient.
I've found that I can authenticate via OAuth 2.0 when my redirect uri is "urn:ietf:wg:oauth:2.0:oob", BUT the user is forced to copy the code, then go back one activity and paste it into a field. I want the experience to be more elegant than that. When the redirect uri is "http://localhost", (even though an access code is returned) I'm unable to exchange it for an access token to the api. Here's my exchange code:
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
0);
nameValuePairs.add(new BasicNameValuePair("client_id",
OAuth2ClientCredentialsMark1.CLIENT_ID));
nameValuePairs.add(new BasicNameValuePair("client_secret",
OAuth2ClientCredentialsMark1.CLIENT_SECRET));
nameValuePairs.add(new BasicNameValuePair("code", accessCode));
nameValuePairs.add(new BasicNameValuePair("grant_type",
"authorization_code"));
nameValuePairs.add(new BasicNameValuePair("redirect_uri",
OAuth2ClientCredentialsMark1.REDIRECT_URI));
//"http://localhost"
String url = "https://accounts.google.com/o/oauth2/token";
//url += URLEncodedUtils.format(nameValuePairs, "utf-8");
Log.d("print", url);
HttpPost hPost = new HttpPost(
url);
hPost.setHeader("content-type", "application/x-www-form-urlencoded");
hPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
This code always returns {"error" : "invalid_grant"} What gives?
My app is based of the sample # https://github.com/ddewaele/LatitudeOAuth2Sample and I've been following the tutorial # http://code.google.com/apis/accounts/docs/OAuth2InstalledApp.html
It seems that your code is correct. The error come from the OAuth2 spec section-5.2.
The provided authorization grant (e.g. authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.
Most likely, your application has not been authorized yet by the user.
To answer your concern about:
the user is forced to copy the code, then go back one activity and paste it into a field
Can you clarify what kind of oauth2 flow (scenario), are you developing?
As the following thread suggests, it might be a TIMING error. Ensuring your server is in sync with world time clock might just prevent that invalid_grant error altogether.
I had that problem on only one of my servers, and indeed, it was the only one with 40 seconds off the world clock (it was in the future). I used ntpdate to forcefully change the date, and installed the ntp service. It's a Linux box.
https://groups.google.com/forum/?fromgroups=#!topic/google-analytics-data-export-api/4uNaJtquxCs
{
"access_token" : "ya29.AHES6ZTtm7SuokEB-RGtbBty9IIlNiP9-eNMMQKtXdMP3sfjL1Fc",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/HKSmLFXzqP0leUihZp2xUt3-5wkU7Gmu2Os_eBnzw74"
}
you get this above when you first time try to get access_token for your application. And after one hour when your access token expires you can get new access_token using the refresh_token....here is your link for this https://developers.google.com/youtube/2.0/developers_guide_protocol_oauth2#OAuth2_Refreshing_a_Token
Site: http://na.leagueoflegends.com/ladders/solo-5x5
Search for a a player (example: Jaiybe)
You get redirected (in this case to: http://na.leagueoflegends.com/ladders/solo-5x5?highlight=28&page=1)
Read the content
And I want to do that in java/android.
I analyze the sites POST request when searching, result:
op:Search
player:Jaiybe
ladder_id:3
form_build_id:form-fff5e6e2569f1e15e5a5caf2a61c15e2
form_id:ladders_filter_form
Build a simple HTTP POST mixture and lets read the content...
The CODE:
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://na.leagueoflegends.com/ladders/solo-5x5");
// Add your POST METHOD attributes
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("op", "Search"));
nameValuePairs.add(new BasicNameValuePair("player", Jaiybe));
nameValuePairs.add(new BasicNameValuePair("ladder_id", "3"));
nameValuePairs.add(new BasicNameValuePair("form_build_id","form-daca6fff89cedc352ccc3f533afa3804"));
nameValuePairs.add(new BasicNameValuePair("form_id","ladders_filter_form"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
responseBody = EntityUtils.toString(response.getEntity());
return responseBody;
And when I run it - I get so some kind of a offline page...
The number form_build_id - is constantly changing, but this was no problem, to use still the same one, and also If I would like to "test" if this could be the problem, I have no Idea how would I...
OR: Is there any other - FAST - way how to get same results?
What is strange is that the "error" site source code that I get on android is different as if I run the same on my PC (Win7, Eclipse, Java) or in my browser. As if there would be two versions of offline sites - for mobile and for PC - but my question: HOW WOULD the server know that the code runs on a Android device? Is there a way how to set this up in HttpClient?
form_build_id:form-fff5e6e2569f1e15e5a5caf2a61c15e2
This is an auto generated token that is valid for a certain time period. This is probably the source of your problem and the reason the token exists in the first place (to prevent post spams).
As this token does not seem session based, you could actually use an HTTP Get on the page that generates the form and parse out the generated token each time for your HTTP Post.
About OS detection, browsers usually provide information about the OS using the HTTP User-Agent header.
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