Search code examples
androidsessioncakephpcookieswebviewclient

Why Cakephp security cookies is not stored in WebViewClient?


Is there any particular reason why CAKEPHP security cookies is not set on Android WebViewClient?

This is how i setup my webviewclient:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String mTargetHostAddr = "mycakeapp";
    String url = String.format("http://%s/users/login", mTargetHostAddr);
    WebView mWebView = (WebView) findViewById(R.id.mWebView);
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.setWebViewClient(new WebViewClient(){
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            CookieManager manager = CookieManager.getInstance();
            manager.hasCookies();
            manager.getCookie(url);
        }
    });
    CookieManager manager = CookieManager.getInstance();
    manager.setAcceptCookie(true); // I turn it on even if the default is true
    mWebView.loadUrl(url);
}

returns:

manager.hasCookies = false;
manager.getCookie = null;

The cakephp app works fine when I try to access it using my android device browser (chrome, firefox) which lead me to safely assume that the said browser can get the cookies.

I also try to reproduce the cakeapp in my dev box with the same code returning:

manager.hasCookies = true;
manager.getCookie = CAKEPHP=pln5int15o3kp9q1e4c7b3hkt4

More information on the Cakephp configuration

Controller:

public $components = array(
      'Auth',
      'Session',
);

public function login() {
      $this->layout = 'administrator/login';
      $this->set('title_for_layout', 'Login');
      if ($this->request->is('post')) {
         if ($this->Auth->login()) {
            return $this->redirect($this->Auth->redirect());
         } else {
            $this->Session->setFlash(__d('cakephp', 'Invalid username or password'));
            return $this->redirect($this->Auth->loginAction);
         }
      }
  }

Config/core.php

Configure::write('Session', array(
      'defaults' => 'php',
      'ini' => array(
         'session.cookie_httponly' => 1
      )
));

tail -f /var/log/apache2/mycakeapp-access.log

"GET /users/login HTTP/1.1" 200 3104 "-" "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; ******* Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30"

php -v

PHP 5.4.4-14+deb7u11 (cli) (built: Jun 16 2014 13:37:03)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies

Please help I know this probably is some configuration issue but I can't point my finger on where or where to start.

Related Questions

CakePHP Cookie/Session problems

EDIT: it seems I'm able to isolate the problem by inspecting the http response header

[Set-Cookie: CAKEPHP=vigkrm6r9kieo0og7perdh1ga2; expires=Tue, 09-Sep-2014 18:53:08 GMT; Max-Age=14400; path=/; HttpOnly] -- from my dev box
[Set-Cookie: CAKEPHP=r04f7t8f39g8v34370hjvuorg4; expires=Thu, 01-Jan-1970 06:16:19 GMT; path=/; HttpOnly] -- from my production box

Solution

  • expires=Thu, 01-Jan-1970 06:16:19 GMT
    

    Somehow the system time went FUBAR and consequently failing the client parsing for the Cakephp (or any) cookies. Setting the system time should fix it.

    date --set YYYY-MM-DD
    
    // set to hw time
    hwclock --systohc
    

    in addition I (loosely) ignore the invalid expiry date using custom cookie spec from apache HttpClient using this reference.

    The following is my implementation:

    public class MyCookieSpec extends BrowserCompatSpec {
    
        public MyCookieSpec() {
            super();
            registerAttribHandler(ClientCookie.EXPIRES_ATTR,
                    new BasicExpiresHandler(DATE_PATTERNS) {
                        @Override
                        public void parse(SetCookie cookie, String value)
                                throws MalformedCookieException {
                            // Sun, 26-Jul-1970 21:10:20 GMT
                            SimpleDateFormat format = new SimpleDateFormat("E, dd-MMM-yyyy HH:mm:ss z");
                            Date expDate = null;
                            try {
                                expDate = format.parse(value);
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
    
                            if (expDate != null && expDate.after(new Date())) {
                                // Continue if this is a valid value
                                super.parse(cookie, value);
                            } else {
                                // Do whatever you want if the value is not expected
                                long curDate = new Date().getTime();
                                cookie.setExpiryDate(new Date(curDate + 5 * 1000));
                            }
                        }
                    });
        }
    }
    

    Register the spec

    HttpClient client = new DefaultHttpClient();
    client.getParams().setParameter("http.protocol.version", HttpVersion.HTTP_1_1);
    client.getParams().setParameter("http.protocol.cookie-policy", "MY_COOKIE_SPEC");
    client.getParams().setParameter("http.protocol.content-charset", "UTF-8");
    
    ((AbstractHttpClient) client).getCookieSpecs().register("MY_COOKIE_SPEC", new CookieSpecFactory() {
    
          @Override
          public CookieSpec newInstance(HttpParams params) {
              return new MyCookieSpec();
          }
    });