I play with GAE and Android, trying to get a web service application. I will go through the steps to get the authorization token from AccountManager on Android, getting the Cookie as needed, and then attaching this cookie to the GET request that the python GAE application processes. For some reason, the GAE app does not seem to recognize the cookie or anything else. Sorry for the huge post, I thought I would get as much code as possible to help explain.
I have this base class in GAE to check if a user is recognized.
class TestUser(webapp.RequestHandler): def get(self): if users.get_current_user(): self.response.out.write(users.get_current_user().nickname()) else: self.response.out.write('no user') application = webapp.WSGIApplication([ ('/', MainPage), ('/testuser', TestUser) ], debug=True) def main(): run_wsgi_app(application) if __name__ == '__main__': main()
From a browser, this works great. I see a user. When executed on Android, I get "no user".
Here is a bunch of Android code:
onCreate:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); cookieLength = (TextView)findViewById(R.id.cookielength); cookie = ""; AccountManager manager = AccountManager.get(getApplicationContext()); Account[] accounts = manager.getAccountsByType("com.google"); new GetAuthTokenTask().execute(accounts); }
Get the authentication token, revoke it and get it again to avoid expired tokens:
private class GetAuthTokenTask extends AsyncTask<Account, Object, String> { @Override protected String doInBackground(Account... accounts) { AccountManager manager = AccountManager.get(getApplicationContext()); Account account = accounts[0]; String token = this.buildToken(manager, account); Log.d(TAG, "First token: "+token); manager.invalidateAuthToken(account.type, token); return this.buildToken(manager, account); } private String buildToken(AccountManager manager, Account account) { try { AccountManagerFuture<Bundle> future = manager.getAuthToken (account, "ah", false, null, null); Bundle bundle = future.getResult(); return bundle.getString(AccountManager.KEY_AUTHTOKEN); } catch (OperationCanceledException e) { Log.w(TAG, e.getMessage()); } catch (AuthenticatorException e) { Log.w(TAG, e.getMessage()); } catch (IOException e) { Log.w(TAG, e.getMessage()); } return null; } protected void onPostExecute(String authToken) { Log.d(TAG, "Second token: "+authToken); getCookie(authToken); } }
Get the user's cookie stored in the global cookie string.
private void getCookie(final String authToken) { new Thread(new Runnable() { public void run() { String href = "https://someawesomeapp.appspot.com/_ah/login?continue=http://localhost/&auth="+authToken; Log.d(TAG, "href: "+href); DefaultHttpClient httpclient = new DefaultHttpClient(); final HttpParams params = new BasicHttpParams(); HttpClientParams.setRedirecting(params, false); httpclient.setParams(params); HttpGet httpget = new HttpGet(href); try { HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity != null) { entity.consumeContent(); } List<Cookie> cookies = httpclient.getCookieStore().getCookies(); Log.d(TAG, "Cookies"); if (cookies.isEmpty()) { Log.d(TAG, "None"); } else { for (int i = 0; i < cookies.size(); i++) { Log.d(TAG, "- " + cookies.get(i).toString()); Cookie c = cookies.get(i); Log.d(TAG, "cookie.getname(): "+c.getName()); if (c.getName().contentEquals("SACSID")) { Log.d(TAG, "Found SACSID cookie"); cookie = c.getValue(); Log.d(TAG, "cookie now set to: "+cookie); } } } } catch (ClientProtocolException e) {
Now we have a cookie, the user clicked the "Test user" button in the interface, this is done:
public void testUser (View view) {Log.d (TAG, "testUser ()");
String href = "http://someawesomeapp.appspot.com/testuser"; DefaultHttpClient httpclient = new DefaultHttpClient(); final HttpParams params = new BasicHttpParams(); HttpClientParams.setRedirecting(params, false); httpclient.setParams(params); HttpGet httpget = new HttpGet(href); httpget.setHeader("Cookie", cookie); try { HttpResponse response = httpclient.execute(httpget); StatusLine status = response.getStatusLine(); if (status.getStatusCode() != 200) { throw new IOException("Invalid response from server: " + status.toString()); } HttpEntity entity = response.getEntity(); if (entity != null) { //entity.consumeContent(); InputStream inputStream = entity.getContent(); ByteArrayOutputStream content = new ByteArrayOutputStream(); // Read response into a buffered stream int readBytes = 0; byte[] sBuffer = new byte[512]; while ((readBytes = inputStream.read(sBuffer)) != -1) { content.write(sBuffer, 0, readBytes); } String dataAsString = new String(content.toByteArray()); Log.d(TAG, "response: "+dataAsString); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
}
Here's the sniff connection from WireShark:
GET /testuser HTTP/1.1 Cookie: AJKiYcEcp6zZHFUoNU5KVlEII_wcWzlBoRQpo-KQ0T_4lwoo0znXn6t7oKpmpa7ctaVY58GO5BmwxkSZ4yZ-e7EOuwTZxeGAuKwI2YrisqjnNuQB36wuzlyBfdY6c7ECcVXuu7BNYlYJtDoB7zJDUCeSXfBmGzrfSh3fHmVO56C540aRmwZKoftRB0ejkdLB6PhUGRXcBI2rbFdvKwuNKJqB0XIr8W_zcEo9AuMjBQqXkDqDUIaGn_ehKfw9c99kzw8cJNHx1EKxVL5Tc2QIYjXWnzTJAYscITCq6IiTTNSdfzWrkbK6Ys9ZOBYNqooaAOxHM5Urx7Cgg0jo2nWQ-tNyKSHfa9Ur7IxBkp137hW7Ar5pimJYb8Jd8oZGwB4uzNHV5V5yZs9aKCqXcaQoz0wgmT5FjT-zqcGz-JfMpGTeubgPg-tQjSvhwPB6mBaXWsOOyuyZPxNeFFDh51WEv53wQs_5fdTwGQ7rQ7ZTEfoBPZNA-JNfo3ecy54DQMmhflmL_IzGE__pNToBi02WlERFm0LclPXtKm4SsDXfTfMPWAve2W1wp-mP-bwB4PljC6NP98WLPWGizRw7g2NwQ_y0iWIogIq9ag Host: someawesomeapp.appspot.com Connection: Keep-Alive HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Vary: Accept-Encoding Date: Sun, 13 Nov 2011 17:42:34 GMT Server: Google Frontend Transfer-Encoding: chunked 7 no user 0 tNyKSHfa9Ur7IxBkp137hW7Ar5pimJYb8Jd8oZGwB4uzNHV5V5yZs9aKCqXcaQoz0wgmT5FjT-zqcGz-JfMpGTeubgPg-tQjSvhwPB6mBaXWsOOyuyZPxNeFFDh51WEv53wQs_5fdTwGQ7rQ7ZTEfoBPZNA-JNfo3ecy54DQMmhflmL_IzGE__pNToBi02WlERFm0LclPXtKm4SsDXfTfMPWAve2W1wp-mP-bwB4PljC6NP98WLPWGizRw7g2NwQ_y0iWIogIq9ag GET /testuser HTTP/1.1 Cookie: AJKiYcEcp6zZHFUoNU5KVlEII_wcWzlBoRQpo-KQ0T_4lwoo0znXn6t7oKpmpa7ctaVY58GO5BmwxkSZ4yZ-e7EOuwTZxeGAuKwI2YrisqjnNuQB36wuzlyBfdY6c7ECcVXuu7BNYlYJtDoB7zJDUCeSXfBmGzrfSh3fHmVO56C540aRmwZKoftRB0ejkdLB6PhUGRXcBI2rbFdvKwuNKJqB0XIr8W_zcEo9AuMjBQqXkDqDUIaGn_ehKfw9c99kzw8cJNHx1EKxVL5Tc2QIYjXWnzTJAYscITCq6IiTTNSdfzWrkbK6Ys9ZOBYNqooaAOxHM5Urx7Cgg0jo2nWQ-tNyKSHfa9Ur7IxBkp137hW7Ar5pimJYb8Jd8oZGwB4uzNHV5V5yZs9aKCqXcaQoz0wgmT5FjT-zqcGz-JfMpGTeubgPg-tQjSvhwPB6mBaXWsOOyuyZPxNeFFDh51WEv53wQs_5fdTwGQ7rQ7ZTEfoBPZNA-JNfo3ecy54DQMmhflmL_IzGE__pNToBi02WlERFm0LclPXtKm4SsDXfTfMPWAve2W1wp-mP-bwB4PljC6NP98WLPWGizRw7g2NwQ_y0iWIogIq9ag Host: someawesomeapp.appspot.com Connection: Keep-Alive HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Vary: Accept-Encoding Date: Sun, 13 Nov 2011 17:42:34 GMT Server: Google Frontend Transfer-Encoding: chunked 7 no user 0
The answer here is βNo Userβ by GAE. Any thoughts on how to get GAE to accept and act on cookies as a user?
27 seconds later, I think I found the problem. Here's a sniff from the browser, I do not have this ACSID = part.
Cookie: ACSID=AJKiYcFeUHZUP56a
Thanks for your help! Stateful
EDIT: I am corrected. I need to wait a while to answer my own question, although not enough reputation. Basically, since I get a cookie with SSL, the cookie should have the SACSID prefix, not the ACSID, and the testuser URL should also be https, since we use this cookie.