Logging in via HttpPost to a website via an application - android

Hello Stackoverflowers!
I have written a relatively simple application that consists of a login text field, a password text field and a login button.
My goal is that when the user enters the login information and touches the login button, the application will log the user into the website I have specified and open it up in a different intent or WebView. My current implementation opens a new activity with a WebView and passes in the login information. My code is as follows for the new activity:
setContentView(R.layout.web);
try {
//add the users login information(username/pw) to a List
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("email", "random#gmail.com"));
nameValuePairs.add(new BasicNameValuePair("password", "password1"));
//declare a new HttpClient
HttpClient httpclient = new DefaultHttpClient();
//set the HttpPost to the desire URL
HttpPost httppost = new HttpPost(URL_STRING);
//set the entity to a new UrlEncodedForm with the login info and type
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));
//store the response
HttpResponse response = httpclient.execute(httppost);
//get the data from the response
String data = new BasicResponseHandler().handleResponse(response);
//get the webview from the xml
WebView webview = (WebView)findViewById(R.id.webView);
webview.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
view.loadUrl(url);
return true;
}
});
//load the return website from the server
webview.loadDataWithBaseURL(httppost.getURI().toString(), data, "text/html", HTTP.UTF_8, null);
This successfully logs me in to the URL (an https site) and opens the page, however if you try to click on any of the buttons on the website it takes you back to the login page in the WebView, and it does not display many of the attributes on the website (charts/graphs).
Could this be a cookie thing?
So is there a way to send the login info via a new intent? Or is there a solution to my WebView implementation?
(here is a relatively similar(ish) question that never got a definitive answer Android SSO (Single sign-on) for app)
Thank you for your time! I really appreciate you taking a look at my question.
EDIT: So giseks's solution worked for me to get the webpage to stay within the WebView, however the charts/graphs/etc on the page still did not display, the solution for that was as simple as enabling javascript for the WebSettings
webview.getSettings().setJavaScriptEnabled(true);
Here's Google's WebSettings Android API for reference: WebSettings
This helped me, I hope it helps you!

My guess is that your application doesn't handle cookies right. Take a look at this question, it may help.
WebView and Cookies on Android
EDIT
In your code you seem to pass only the html retrieved from request to the WebView. Cookies seem to get lost somewhere. I'd suggest you another approach.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webv = (WebView)findViewById(R.id.MainActivity_webview);
webv.setWebViewClient(new WebViewClient(){
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
String postData = FIELD_NAME_LOGIN + "=" + LOGIN +
"&" + FIELD_NAME_PASSWD + "=" + PASSWD;
// this line logs you in and you stay logged in
// I suppose it works this way because in this case WebView handles cookies itself
webv.postUrl(URL, EncodingUtils.getBytes(postData, "utf-8"));
}

Related

Get the link redirected from webview android

I am trying to implement a payment gateway in android, and the payment processor requires sending some parameters when the "Pay" button is clicked. The sample link is:
https://vpay.com/?p=linkToken&v_merchant_id=qa331322179752&merchant_ref=234-567-890&memo=Bulk+order+from+McAckney+Web+Shop&total=13000&
notify_url=http%3A%2F%2Fwww.example.com%2Fnotification.php&
success_url=http%3A%2F%2Fwww.example.com%2Fthank_you.html&fail_url=http%3A%2F%2Fwww.example.com%2Ffailed.html
Now if the parameters are inputted correctly, the link returns another link in the format: https://vpay.com/pay/bnlink/xxxxxxxx-x0 which when visited brings up VPay payment page that can be used for payment based on the parameters supplied.
The payment processor should have employed an automatic redirection when the new link is generated, instead, it just displays the new link and stays there. Is there a way to get this new "RETURNED" link and then visit it so users can input the payment info.
Thank you!
Following method of Webview will work if you are using your own webview in activity or fragment for the payment stuff. below is the piece of code which will help:
webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i(TAG, "Processing webview url click...");
view.loadUrl(url);
Log.v(TAG,"html content of url:"+ getHtml(String url) );
return true;
}
public void onPageFinished(WebView view, String url) {
Log.i(TAG, "Finished loading URL: " +url);
}
});
in shouldOverrideUrlLoading method you will add your condition according to the url whether to load this url in webview or not.
And to get html content of the url use below Method:
public String getHtml(String url) {
HttpClient vClient = new DefaultHttpClient();
HttpGet vGet = new HttpGet(url);
String response = "";
try {
ResponseHandler<String> vHandler = new BasicResponseHandler();
response = vClient.execute(vGet, vHandler);
} catch (Exception e) {
e.printStackTrace();
}
return response;
}

“Authorization Required” in webview even if POST returned 200

I am trying to access a webpage after successfully logging in, where i get the username and password (from the EditTexts in my app user = (EditText) findViewById(R.id.user); and pass = (EditText) findViewById(R.id.pass); ) and POST it to server.
The problem is that the webview shows the text "Authorization Required.... " (after logging in successfully) only on the phones/tablets that have android 4.2.2 but on 4.4.2, 4.4.4 and 5.0.1 works fine (shows the page intended).
I am running out of ideas and need help.
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("user", user.getText().toString()));
nameValuePairs.add(new BasicNameValuePair("password", pass.getText().toString()));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "utf-8"));
httppost.addHeader("Authorization", "Basic BLA123BLA23BLA32343LSJ");
// Execute HTTP Post Request
response = httpclient.execute();
if (response.getStatusLine().getStatusCode() == 200) {
//WebView
webview_asd = new WebView(MainScreen.this);
webview_asd = (WebView) findViewById(R.id.webview_asd);
webview_asd.getSettings().setLoadsImagesAutomatically(true);
webview_asd.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webview_asd.setWebViewClient( new WebViewClient() );
webview_asd.getSettings().setJavaScriptEnabled(true);
CookieSyncManager.createInstance (webview_asd.getContext());
cookies = ((AbstractHttpClient) httpclient).getCookieStore().getCookies();
if(cookies != null)
{
for(Cookie cookie : cookies)
{
cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();
CookieManager.getInstance().setCookie(cookie.getDomain(), cookieString);
}
}
CookieSyncManager.getInstance().sync();
webview_asd.loadURL(URL);
webview_asd.setVisibility(View.VISIBLE);
( webview shows - "Authorization Required. This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials(e.g., bad password), or your browser doesn't understand how to supply the credentials required." )
Later edit: Just figured out that 4.2.2 doesn't support HTML5 and that's why i got this problem.
I would guess that the webpage required Basic Authentication. Use WebViewClient callback onReceivedHttpAuthRequest. This post shows a good basic example.

How to login and keep cookie for later use of a webpage

So, I have this webpage which I want to access, but first I have to login from another webpage. I want to keep the cookies and then use it for later automatic login. So far what I did:
First, this is the login webpage: https://autenticacao.uvanet.br/autenticacao/pages/login.jsf
It's my university's student's area.
public class Consulta extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
StringBuilder builder = new StringBuilder(100000);
DefaultHttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(urls[0]);
try {
List<NameValuePair> val = new ArrayList<NameValuePair>(2);
val.add(new BasicNameValuePair("form:usuario", "myusername"));
val.add(new BasicNameValuePair("form:senha", "mypass"));
httpPost.setEntity(new UrlEncodedFormEntity(val));
HttpResponse response = client.execute(httpPost);
InputStream content = response.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
builder.append(s);
}
} catch (Exception e) {
e.printStackTrace();
}
return builder.toString();
}
}
This is the class I use to make the HttpPost and this is how I call it:
#Override
public void onClick(View v) {
try{
String html = new Consulta().execute("https://autenticacao.uvanet.br/autenticacao/pages/login.jsf").get();
Document doc = Jsoup.parse(html);
Element link = doc.select("title").first();
String t = link.text();
tv1.setText(t);
}catch(Exception e){
e.printStackTrace();
}
}
I believed it would work this way:
I send the webpage to login to Consulta.java
The class would get the fields "form:usuario" and "form:senha" and fill them with myusername and mypassword and then login
The class would return me html code of the second webpage as string
But what happens is that it returns me the first webpage (the login one). I'm pretty sure I'm doing something wrong, but I don't know what, could someone help me? Also, sorry for my english, it's not my main language.
When you do the login (in https://autenticacao.uvanet.br/autenticacao/pages/login.jsf), I don't think the response is the html code of the second webpage. Are you sure about this?
I think the normal behavior for a login page is to respond with the same page (the login one) but adding the session cookie and the header to do a redirect to the second webpage, but not the second page itself.
In this case, you have to read the http header response to extract these parameters: the cookies and the URL of the second webpage.
Using the object HttpResponse:
Header[] h = response.getAllHeaders();
But I recommend you to use HttpURLConnection class instead of DefaultHttpClient.

Sharing cookies/session from WebView to HttpClient doesn't work

I know this question has been asked a hundred times, and I've read and tried for 2 hours now, but I can't find my error :-(
I am trying to create a simple webbrowser and therefore have a webview, where I login on a site and get access to a picture area. With help of a DefaultHttpClient, I want to make it possible to download pictures in the secured area.
Therefore I am trying to share the cookies from the webview and pass them on to the HttpClient, so that it is authenticated and able to download. But whatever I try and do, I always get a 403 response back...
Basically the steps are the following:
1) Enter URL, webview loads website
2) Enter login details in a form
3) Navigate to picture and long hold for context menu
4) Retrieve the image URL and pass it on to AsynTask for downloading
Here's the code of the AsyncTask with the Cookie stuff:
protected String doInBackground(String... params) {
//params[0] is the URL of the image
try
{
CookieManager cookieManager = CookieManager.getInstance();
String c = cookieManager.getCookie(new URL(params[0]).getHost());
BasicCookieStore cookieStore = new BasicCookieStore();
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
String[] cookieParts = null;
String cookies[] = null;
cookies = c.split(";");
for(int i=0;i<cookies.length;i++)
{
cookieParts = cookies[i].split("=");
BasicClientCookie sessionCookie = new BasicClientCookie(cookieParts[0].trim(), cookieParts[1].trim());
sessionCookie.setDomain(new URL(params[0]).getHost());
cookieStore.addCookie(sessionCookie);
}
DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.setCookieStore(cookieStore);
HttpGet pageGet = new HttpGet(new URL(params[0]).toURI());
HttpResponse response = httpClient.execute(pageGet, localContext);
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
--> NEVER Happens, always get 403
.) One of the problems is that the webview saves some cookies for the host *www.*example.com, but the image-URL to download (params[0]) is *static.*example.com. The line
cookieManager.getCookie(new URL(params[0]).getHost());
returns null, because there is no cookie for static.example.com, but only for www.example.com.
.) When I manually say cookieManager.getCookie("www.example.com"); I get some cookies back, which I add to the HttpClient cookie store:
There are 5 cookies added
- testcookie = 0
- PHPSESSID = 320947238someGibberishSessionId
- email = my#email.net
- pass = 32423te32someEncodedPassGibberish
- user = 345542
So although these cookies, a session ID and other stuff, get added to the HttpClient, it never get's through to download an image. Im totally lost... though I guess that it either has something to do with the cookies domains, or that Im still missing other cookies.
But from where the heck should I know which cookies exist in the webview, when I have to specify a specific URL to get a cookie back?? :-(
Any advice?
I guess we have made it too complicated in above snippet.
Use these easy steps -
1)Retrieve the cookie from webView -wherever your webview is, use this code to re
String cookie = CookieManager.getInstance().getCookie(
url.toString());
Log.d("mytcs", "cookie downloadlistner " + cookie);
2) Pass this in your downloading asyncTask using params -
downloadImageTask = new DownloadImage();
downloadPDFTask.execute(url, cookie);
(I assume you know to retrieve this cookie in asyncTask, you will use params[1],
3) set this cookie in your http request using -
if (cookie != null)
con.setRequestProperty("cookie", cookie);
where con is HttpURLConnection con;
so you can set it to your need, in HttpGet.
You probably figured out the answer already coz it is a pretty late answer. But, just in case...
Try this. When you retrieve the cookie from WebView just use example.com in the domain name. When you set the cookie in BasicClientCookie and set the domain, set the domain name to .example.com. Note the "." in the beginning. Now, i think the session should work across all subdomains in your application.

Maintain cookie session in Android

Okay, I have an android application that has a form in it, two EditText, a spinner, and a login button. The user selects the service from the spinner, types in their user name and password, and clicks login. The data is sent via POST, a response is returned, it's handled, a new WebView is launched, the html string generated from the response is loaded, and I have the home page of whatever service the user selected.
That's all well and good. Now, when the user clicks on a link, the login info can't be found, and the page asks the user to login again. My login session is being dropped somewhere, and I'm not certain how to pass the info from the class that controls the main part of my app to the class that just launches the webview activity.
The onClick handler from the form login button:
private class FormOnClickListener implements View.OnClickListener {
public void onClick(View v) {
String actionURL, user, pwd, user_field, pwd_field;
actionURL = "thePageURL";
user_field = "username"; //this changes based on selections in a spinner
pwd_field = "password"; //this changes based on selections in a spinner
user = "theUserLogin";
pwd = "theUserPassword";
List<NameValuePair> myList = new ArrayList<NameValuePair>();
myList.add(new BasicNameValuePair(user_field, user));
myList.add(new BasicNameValuePair(pwd_field, pwd));
HttpParams params = new BasicHttpParams();
DefaultHttpClient client = new DefaultHttpClient(params);
HttpPost post = new HttpPost(actionURL);
HttpResponse response = null;
BasicResponseHandler myHandler = new BasicResponseHandler();
String endResult = null;
try { post.setEntity(new UrlEncodedFormEntity(myList)); }
catch (UnsupportedEncodingException e) { e.printStackTrace(); }
try { response = client.execute(post); }
catch (ClientProtocolException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
try { endResult = myHandler.handleResponse(response); }
catch (HttpResponseException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
List<Cookie> cookies = client.getCookieStore().getCookies();
if (!cookies.isEmpty()) {
for (int i = 0; i < cookies.size(); i++) {
cookie = cookies.get(i);
}
}
Intent myWebViewIntent = new Intent(MsidePortal.this, MyWebView.class);
myWebViewIntent.putExtra("htmlString", endResult);
myWebViewIntent.putExtra("actionURL", actionURL);
startActivity(myWebViewIntent);
}
}
And here is the WebView class that handles the response display:
public class MyWebView extends android.app.Activity {
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web);
MyWebViewClient myClient = new MyWebViewClient();
WebView webview = (WebView)findViewById(R.id.mainwebview);
webview.getSettings().setBuiltInZoomControls(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(myClient);
Bundle extras = getIntent().getExtras();
if(extras != null)
{
// Get endResult
String htmlString = extras.getString("htmlString");
String actionURL = extras.getString("actionURL");
Cookie sessionCookie = MsidePortal.cookie;
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
if (sessionCookie != null) {
cookieManager.removeSessionCookie();
String cookieString = sessionCookie.getName()
+ "=" + sessionCookie.getValue()
+ "; domain=" + sessionCookie.getDomain();
cookieManager.setCookie(actionURL, cookieString);
CookieSyncManager.getInstance().sync();
}
webview.loadDataWithBaseURL(actionURL, htmlString, "text/html", "utf-8", actionURL);}
}
}
}
I've had mixed success implementing that cookie solution. It seems to work for one service I log into that I know keeps the cookies on the server (old, archaic, but it works and they don't want to change it.) The service I'm attempting now requires the user to keep cookies on their local machine, and it does not work with this setup.
Any suggestions?
You need to keep the cookie from one call to another. Instead of creating a new DefaultHttpClient, use this builder:
private Object mLock = new Object();
private CookieStore mCookie = null;
/**
* Builds a new HttpClient with the same CookieStore than the previous one.
* This allows to follow the http session, without keeping in memory the
* full DefaultHttpClient.
* #author Régis Décamps <decamps#users.sf.net>
*/
private HttpClient getHttpClient() {
final DefaultHttpClient httpClient = new DefaultHttpClient();
synchronized (mLock) {
if (mCookie == null) {
mCookie = httpClient.getCookieStore();
} else {
httpClient.setCookieStore(mCookie);
}
}
return httpClient;
}
And keep the Builder class as a field of your application.
Use this in url login Activity
List<Cookie> cookies = client.getCookieStore().getCookies();
if (!cookies.isEmpty()) {
for (int i = 0; i < cookies.size(); i++) {
cookie = cookies.get(i);
}
}
Cookie sessionCookie = cookie;
if (sessionCookie != null) {
String cookieString = sessionCookie.getName() + "="
+ sessionCookie.getValue() + "; domain="
+ sessionCookie.getDomain();
cookieManager
.setCookie("www.mydomain.com", cookieString);
CookieSyncManager.getInstance().sync();
}
You could store the cookies in a shared preference and load them as needed in other activitys.
Or try this idea from a similar question.
dunno if you still need an answer, but again here comes some additional info that may help
if you want to keep cookies sync'ed
// ensure any cookies set by the dialog are saved
CookieSyncManager.getInstance().sync();
and if you want to clear Cookies
public static void clearCookies(Context context) {
// Edge case: an illegal state exception is thrown if an instance of
// CookieSyncManager has not be created. CookieSyncManager is normally
// created by a WebKit view, but this might happen if you start the
// app, restore saved state, and click logout before running a UI
// dialog in a WebView -- in which case the app crashes
#SuppressWarnings("unused")
CookieSyncManager cookieSyncMngr =
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
}
When any new activity is launched (so I assume this is the same when you launch a new webview) it is effectively launching a new program from scratch. This new activity will not have access to data from any previous activity (unless that data is passed by being attached to the intent).
2 possible solutions:
1) putExtra can only be used to pass primitive data, so to pass something more complex you need to either
a) Wrap the more complex structure in a class that implements the
Parcelable interface, which can be stored in an extra.
b) Wrap the more complex structure in a class that implements the
Serializable interface, which can be stored in an extra.
Either of these approaches is fairly complicated and a fair bit of work.
2)Personally I much prefer the approach suggested by rds. To clarify, when rds says:
keep the Builder class as a field of your application.
I think he means extend the application class. Any properties stored there are available globally to all activities.
This article explains very clearly how to do this:
http://www.screaming-penguin.com/node/7746
You can ignore the stuff about the AsyncTask (although I'm sure you will find a need for that at some point) and just concentrate on the part about extending the application class.
I have this similiar problem several week ago, that is because you create new DefaultHttpClient each time you click the button.. try create one DefaultHttpClient, and using the same DefaultHttpClient for each request you trying to send. it solved my problem
You have used this line -
if (sessionCookie != null) {
cookieManager.removeSessionCookie();
}
To ensure you receive new cookie everytime.
Seems like you have gone through same issue as I faced, check below link -
removeSessionCookie() issue of android (code.google.,com)
it says that removeSessionCookie() is implemented in a thread, so whenever it is called; a thread starts and after your setCookie(url, cookieString); is called, it removes the new cookie you just set.
So for some devices it works well as removeSessionCookie() is already executed, while, for some, it remove the cookie, and we get that problem.
I suggest you remove this removeSessionCookie(); as you are setting only one cookie, so it won't conflict with other cookies. Your code will work seamlessly.
Sever use the sessionID stored in the cookies to identify the specfic user.Every language has a different sessionID name in the http headers.You can use some network tool or browser to see what is the name the sessionID called.
And other way,I GUESS,the facebook and twitter way,you will remove all the session-related code, it's server use Access Token to identify a user.
Am i clear?

Categories

Resources