Cookies created by a webview aren't being deleted with a HttpRequest - android

I have a Xamarin Forms app where I share cookies between the Webview and HttpClient by grabbing them after a login. On iOS this works fine, on Android I have the following issue:
If the cookie is created as the result of a HTTPClinet Api call, then deleted (expired) using either a WebView or HttpClient the cookie is no longer in the cookie list. When using HttpClient the HttpClientHandler.CookieContainer has a count of 0.
If the cookie is created using a WebView and deleted using another WebView the cookie is no longer in the cookie list.
If the cookie is created using a WebView and deleted using a HTTPClient Api call the expiration does not happen and the cookie is still in the HttpClinet's HttpClinetHandler's CookieContainer, I can see that the count is not 0.
If I look at the HttpResponse I see the expired cookie in the header:
"MyTestCookie=; expires=Wed, 28-Feb-2018 21:25:08 GMT; path=/; HttpOnly"
If I look further into the CookieContainer the m_domainTable has 2 entries, one for my ip with no cookies, and one for my ip preceded with a "." that contains the cookie that should be expired/deleted but it is not expired and has the original value.
The server code that creates the cookie for both the Api call and MVC Page is:
var cookie = new HttpCookie("MyTestCookie");
cookie.HttpOnly = true;
cookie.Values["token"] = "309d530f956ac04";
cookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cookie);
and the code that Deletes / Expires it is:
if (Request.Cookies["MyTestCookie"] != null)
{
var cookie = new HttpCookie("MyTestCookie");
cookie.HttpOnly = true;
cookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(cookie);
}
Is this a bug, or am I missing something?

Related

Xamarin Android CookieManager doesn't store all cookies

I am using Android Web View in my Xamarin Project to perform third party authentication. Once the login is successful I need to extract the authentication cookies. This cookies I am storing in persistent storage and then I am using them for passing to subsequent requests.
For example:
Android App >(opens) webview > Loads (idp provider) url > User provides credentials and saml request is sent to my backend server > backend server validates saml and returns authentication cookies.
It returns two cookies.
Now everything works fine. And in OnPageFinished method of the WebClient of webview I am trying to extract the cookies using the method.
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
var handler = OnPageCompleted;
var uri = new Uri(url);
AllowCookies(view);
var cookies = CookieManager.Instance.GetCookie(url);
var onPageCompletedEventArgs = new OnPageCompletedEventArgs { Cookies = cookies, Url = uri.AbsolutePath, RelativeUrl = uri.PathAndQuery, Host = uri.Host };
handler?.Invoke(this, onPageCompletedEventArgs);
}
private void AllowCookies(WebView view)
{
CookieManager.Instance.Flush();
CookieManager.AllowFileSchemeCookies();
CookieManager.SetAcceptFileSchemeCookies(true);
CookieManager.Instance.AcceptCookie();
CookieManager.Instance.AcceptThirdPartyCookies(view);
CookieManager.Instance.SetAcceptCookie(true);
CookieManager.Instance.SetAcceptThirdPartyCookies(view, true);
}
The problem is, I am able to get just one cookie(wc_cookie_ps_ck
), I am unable to see the other authentication cookie(.AspNetCore.Cookies
).
Here's how the cookies appear in browser.
Please note that in postman and in chrome browser both the cookies appear.
But in android webview only cookie with name ".AspNetCore.Cookies" is not appearing at all.
As per Java document,"When retrieving cookies from the cookie store, CookieManager also enforces the path-match rule from section 3.3.4 of RFC 2965 . So, a cookie must also have its “path” attribute set so that the path-match rule can be applied before the cookie is retrieved from the cookie store."
Since both of my cookies have different path, is that the reason the one with path set as "/project" is not appearing?
After days and days of finding the answer to the question. I finally have found an answer.
I did remote debugging of the webview with the desktop chrome and I found out that all the cookies that I needed were present in the webview.
However the method,
var cookies = CookieManager.Instance.GetCookie(url);
doesn't return the cookie which has the same site variable set.
This looks like a bug from Xamarin Android. I have already raised an issue in Xamarin Android github.
In the xamarin android github issue I have mentioned the steps to reproduce.
For me, the workaround to resolve the issue was to set the samesite cookie varibale off in my asp.net core back end project.
As follows:
In order to configure the application cookie when using Identity, you can use the ConfigureApplicationCookie method inside your Startup’s ConfigureServices:
// add identity
services.AddIdentity<ApplicationUser, IdentityRole>();
// configure the application cookie
services.ConfigureApplicationCookie(options =>
{
options.Cookie.SameSite = SameSiteMode.None;
});
Link for the above solution mentioned. Here.

Getting Google Play Games player ID on server

The post Play Games Permissions are changing in 2016 explains how to get the Play Games player ID on a server. I can successfully get the access token on the server, but I can't get this step to work:
Once you have the access token, call www.googleapis.com/games/v1/applications/yourAppId/verify/ using that
access token. Pass the auth token in a header as follows:
“Authorization: OAuth ” The response value will contain
the player ID for the user.
I'm trying to do that in Google App Engine using:
accessToken = ...; //-- I can always get this successfully
URL url = new URL(String.format("https://www.googleapis.com/games/v1/applications/%s/verify/",myAppId));
HTTPRequest request = new HTTPRequest(url, HTTPMethod.GET);
HTTPHeader httpHeader = new HTTPHeader("Authorization: OAuth",accessToken);
request.addHeader(httpHeader);
HTTPResponse httpResponse = urlFetchService.fetch(request);
The response always return code 401. How can I debug?
An identical issue (sort of) indicates that you'll have to set the header differently (not using HttpHeader).
httppost.setHeader("Authorization", "Bearer "+accessToken);
Hopefully this can fix your issue.
The problem was with the header, it should be added like this:
HTTPHeader httpHeader = new HTTPHeader("Authorization","OAuth " + accessToken);

Perform HTTP requests using cookies from webview

I have this scenario which my app shows in a webView a 2-page login process.
The first page asks only to which domain to you plan on connecting.
The second page asks for the credentials.
I'm trying to perform the login in the webView and then execute requests from my native code.
I realize I need to get the stored cookie from the webView (but from which url? from the first page or the second one?), and then use the cookie for the native code requests.
Can someone please tell me how to go about it? The login process is easy - the user logs in through the webview - fine. Now, I know how to use the cookie manage but I dont know which cookie am I suppose to look for - is it the url of the first login page? is it the second one? does it matter?
Next, how do I use the cookie to send back to server with a GET request so the server will know I'm authenticated?
I appreciate the answers I'm clueless and begging for help :)
Since the accepted answer does not really describe how it is done:
Put these lines somewhere where your app starts:
CookieHandler.setDefault(new CookieManager()); // Apparently for some folks this line works already, for me on Android 17 it does not.
CookieSyncManager.createInstance(yourContext); // or app will crash when requesting cookie
And then in your connection:
String cookies = CookieManager.getInstance().getCookie(urlString);
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
// conn.setRequestMethod("GET");
// conn.setDoInput(true);
if (cookies != null)
conn.setRequestProperty("Cookie", cookies);
// Starts the query
conn.connect();
I have done the opposite of you: I log in with loopj Android Asynchronous Http Client, and want the session cookies to apply to a webview, for the same website. I don't know if it will help you, but, I am going to post my code for copying over the cookies. Maybe seeing the process will help you to look for the items you need... to copy cookies from webview, to HTTP. I can't offer further help, since I'm fairly new at Android. (And, of course, I adapted my code from other people's posts.)
Class variable declarations:
private AsyncHttpClient loopjClient = new AsyncHttpClient();
private PersistentCookieStore myCookieStore;
onCreate() initialization:
myCookieStore = new PersistentCookieStore(this);
loopjClient.setCookieStore(myCookieStore);
After HTTP login:
// get cookies from the generic http session, and copy them to the webview
CookieSyncManager.createInstance(getActivity().getApplicationContext());
CookieManager.getInstance().removeAllCookie();
CookieManager cookieManager = CookieManager.getInstance();
List<Cookie> cookies = myCookieStore.getCookies();
for (Cookie eachCookie : cookies) {
String cookieString = eachCookie.getName() + "=" + eachCookie.getValue();
cookieManager.setCookie("http://www.example.com", cookieString);
//System.err.println(">>>>> " + "cookie: " + cookieString);
}
CookieSyncManager.getInstance().sync();
// holy ****, it worked; I am automatically logged in for the webview session
Note that loopj is like the webview, in that all cookie management and sending are automatic. I just copy all cookies for the domain. I think you'd be fine, doing the same... thus, no worry about whether from the first or second page.
At the end I found my way and it was pretty simple.
Once the user logs in through the webview - a cookie is set on the device.
Later on once I want to perform Native api calls on the service I ask the cookie manager for the cookie that was set based on the url.
I then take the important header that is used to authenticate on the server and send it along with my api calls.

App engine java Android get user attribute

I have an android client that receives JSON data from an app engine servlet. I am also able to get the Authentication cookie. Now, I want to get the User from the request to the servlet.
Servlet Code:
`User user = (User) req.getAttribute("user");
String cookie = (String) req.getHeader("Cookie");
if(user == null){
UserService userService = UserServiceFactory.getUserService();
user = userService.getCurrentUser();
}`
Android Post:
HttpGet get = new HttpGet(Setup.PROD_URL+"/viewselectedclass");
SharedPreferences prefs = Util.getSharedPreferences(getBaseContext());
String cookie = prefs.getString(Util.AUTH_COOKIE, null);
get.setHeader("Cookie", cookie);
client = new DefaultHttpClient();
HttpResponse r = client.execute(get);
I'm setting the auth cookie in the header of the HttpGet request. I believe this cookie must be used to identify the user on the server. But in the servlet, it says the users object is null.
How do I send a request from Android to App engine to get the current user. I must be missing something here.
Okay, I solved this by creating my own datastore entity called MyUser, sent the ID generated by the datastore during registration to the android client and used this ID to identify the user in all further requests. I'm not using the UserService from GAE at all.

HttpPost: No "Set-Cookie" Header

I want to get the session cookie of a website. Unfortunately the "Set-Cookie"-Header doesn't show up.
Here's the code I've written:
"commands" is a String[][] and the whole code is wrapped by try/catch.
CookieStore cookieStore = new BasicCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE,cookieStore);
HttpPost httppost = new HttpPost(url);
List<NameValuePair> nvps = new ArrayList<NameValuePair>(0);
for (int i=0;i<commands.length;++i)
nvps.add(new BasicNameValuePair(commands[i][0],commands[i][1]));
httppost.setEntity(new UrlEncodedFormEntity(nvps,HTTP.UTF_8));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
Header[] headers = response.getAllHeaders();
List<Cookie> cookies = cookieStore.getCookies();
String data = EntityUtils.toString(entity);
My understanding of Http Communication tells me that there should be a "Set-Cookie" Header. The only Headers I get from response.getAllHeaders() are Connection:close, X-Powered-By:PHP/4.3.4 and Content-Type:text/html
There is a bit of javascript included in the returned data (response.getEntity()).
<script language = "javascript">
<!--
location.href="/index.php";
function SetCookie(name,value,expire,path){
document.cookie = name + "=" + escape(value) + ((path == null) ? "":(";path="+path))
}
var iad = 461180104
SetCookie("iad",iad,0,"/")
-->
</script>
As far as I understand this, this code is never executed because it's just a comment ?!
But as well this is probably the bit where the cookie should be created.
Any ideas?
UPDATE:
"Opera Mobile" is the only browser for Android I found which has no problem with cookies on this site. "Opera Mini", "Dolphin HD" and the Froyo Stock browser all fail. No Desktop browser has problems connecting. Is this a webkit issue? And if this is the case: how to avoid it?
Using Chrome's developer tools or Firebug, check the HTTP response for the "expires" parameter in the Set-Cookie header field. Make sure the time / date settings on the phone are set correctly. If the browser thinks the cookie is already expired, it won't store it.
If that doesn't work try using wireshark / tshark to grab a trace of the communication from your client, and compare it to a browser that's working the way you expect it to.
By the way, the comment delimiters around that bit of Javascript don't prevent the script from being run; they just prevent older (really old) browsers from trying to render the script in the document. That cookie ("iab") doesn't look like the cookie for authentication. There's likely an http-only cookie with a session identifier; you should be able to see it using the aforementioned Firebug / Dev tools.

Categories

Resources