Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to persist cookies from WebViewClient to URLConnection, browser, or other file download technique in android

We have a .net forms auth enabled site that the user visits via a WebViewClient in our android app. One of the features of the site is the ability to login and download some PDF files, however you need to be logged in to download the PDFs.

We are currently implementing shouldOverrideUrlLoading and are downloading the pdf via the following code when the correct condition is met.

URL u = new URL(url);
URLConnection conn = u.openConnection();
int contentLength = conn.getContentLength();

DataInputStream stream = new DataInputStream(u.openStream());

byte[] buffer = new byte[contentLength];
stream.readFully(buffer);
stream.close();

DataOutputStream fos = new DataOutputStream(new FileOutputStream("/sdcard/download/file.pdf"));
fos.write(buffer);
fos.flush();
fos.close();

From the IIS logs, its apparent that IIS does not consider this request to be logged in and redirects it to the login page.

What we need is a way to download the file with the auth cookie persisted in the file download request but we are at a loss as to how to persist the cookie.

Another viable solution for us is to persist the auth cookie between the WebViewClient and the android browser. If we could do that, we'd just open the PDF file via the default action in the browser.

Edit: It looks like I can set the auth cookie manually via

conn.setRequestProperty("Cookie", "");

Now I just need to figure out how to read the auth cookie out of the WebViewClient

like image 251
Allen Rice Avatar asked Mar 08 '11 16:03

Allen Rice


2 Answers

Since you're using ASP.NET Forms authentication, you'll need to copy the forms auth cookie from the WebView to the URLConnection. Luckily this is pretty straight forward. This code lives in an implementation of shouldOverrideUrlLoading

string url = "http://site/generatePdfBehindFormsAuth";

// get an instance of a cookie manager since it has access to our auth cookie
CookieManager cookieManager = CookieManager.getInstance();

// get the cookie string for the site.  This looks something like ".ASPXAUTH=data"
String auth = cookieManager.getCookie(url).toString();

URLConnection conn = (URLConnection)new URL(url).openConnection();

// Set the cookie string to be sent for download.  In our case we're just copying the
//   entire cookie string from the previous connection, so all values stored in 
//   cookies are persisted to this new connection.  This includes the aspx auth 
//   cookie, otherwise it would not be authenticated
//   when downloading the file.  
conn.setRequestProperty("Cookie", auth);
conn.setDoOutput(true);
conn.connect();

// get the filename from the servers response, its typical value is something like:
//   attachment; filename="GeneratedPDFFilename.pdf"
String filename = conn.getHeaderField("Content-Disposition").split("\"")[1];

// by default, we'll store the pdf in the external storage directory
String fileRoot = "/sdcard/";

// Complete the download
FileOutputStream f = new FileOutputStream(new File(fileRoot, filename));
InputStream in = conn.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) > 0 ) 
{
    f.write(buffer,0, len1);
}
f.close();
in.close();

NOTE: One thing to be aware of is that you should NOT make a call to getContentLength on your URLConnection. After 4 hours of debugging, wireshark finally showed that, if you call getContentLength, the cookie would be sent for the request that gets the content length, but the cookie will not be sent for subsequent requests, even on the same instance of URLConnection. Maybe I am naive and this is by design (the documentation does not indicate that it is by design), but I was unable to manually set the cookie for the subsequent file request by calling setRequestProperty after calling getContentLength. If I attempted to do that, I'd get a force close.

like image 76
Allen Rice Avatar answered Nov 18 '22 20:11

Allen Rice


Have you looked at the CookieSyncManager class? I believe this is what is needed to persist cookies received from the server and re-use them.

http://developer.android.com/reference/android/webkit/CookieSyncManager.html

like image 37
ktambascio Avatar answered Nov 18 '22 20:11

ktambascio