Ignore auth cookies with value 'deleted'
authorGergő Tisza <tgr.huwiki@gmail.com>
Fri, 22 Jan 2016 06:14:07 +0000 (22:14 -0800)
committerGergő Tisza <tgr.huwiki@gmail.com>
Fri, 22 Jan 2016 22:29:03 +0000 (14:29 -0800)
'deleted' is the value PHP sets when it deletes a cookie (via the
Expires/Max-Age headers). Apparently some clients ignore the
expiration date and send 'deleted' back; these clients now cannot
login due to some slight changes in exactly when cookies are
set/deleted during the login process.

To keep those clients from breaking, ignore this special value.

Bug: T124252
Change-Id: Icd0e1bcd8efe0869da981352763d25e4f8075bf2

includes/session/CookieSessionProvider.php

index f92a519..7854416 100644 (file)
@@ -104,7 +104,7 @@ class CookieSessionProvider extends SessionProvider {
 
        public function provideSessionInfo( WebRequest $request ) {
                $info = array(
-                       'id' => $request->getCookie( $this->params['sessionName'], '' )
+                       'id' => $this->getCookie( $request, $this->params['sessionName'], '' )
                );
                if ( !SessionManager::validateSessionId( $info['id'] ) ) {
                        unset( $info['id'] );
@@ -140,7 +140,7 @@ class CookieSessionProvider extends SessionProvider {
                $info += array(
                        'provider' => $this,
                        'persisted' => isset( $info['id'] ),
-                       'forceHTTPS' => $request->getCookie( 'forceHTTPS', '', false )
+                       'forceHTTPS' => $this->getCookie( $request, 'forceHTTPS', '', false )
                );
 
                return new SessionInfo( $this->priority, $info );
@@ -238,7 +238,7 @@ class CookieSessionProvider extends SessionProvider {
         */
        protected function setLoggedOutCookie( $loggedOut, WebRequest $request ) {
                if ( $loggedOut + 86400 > time() &&
-                       $loggedOut !== (int)$request->getCookie( 'LoggedOut', $this->cookieOptions['prefix'] )
+                       $loggedOut !== (int)$this->getCookie( $request, 'LoggedOut', $this->cookieOptions['prefix'] )
                ) {
                        $request->response()->setCookie( 'LoggedOut', $loggedOut, $loggedOut + 86400,
                                $this->cookieOptions );
@@ -257,7 +257,7 @@ class CookieSessionProvider extends SessionProvider {
        }
 
        public function suggestLoginUsername( WebRequest $request ) {
-                $name = $request->getCookie( 'UserName', $this->cookieOptions['prefix'] );
+                $name = $this->getCookie( $request, 'UserName', $this->cookieOptions['prefix'] );
                 if ( $name !== null ) {
                         $name = User::getCanonicalName( $name, 'usable' );
                 }
@@ -266,17 +266,39 @@ class CookieSessionProvider extends SessionProvider {
 
        /**
         * Fetch the user identity from cookies
-        * @return array (int|null $id, string|null $token)
+        * @param \WebRequest $request
+        * @return array (string|null $id, string|null $username, string|null $token)
         */
        protected function getUserInfoFromCookies( $request ) {
                $prefix = $this->cookieOptions['prefix'];
                return array(
-                       $request->getCookie( 'UserID', $prefix ),
-                       $request->getCookie( 'UserName', $prefix ),
-                       $request->getCookie( 'Token', $prefix ),
+                       $this->getCookie( $request, 'UserID', $prefix ),
+                       $this->getCookie( $request, 'UserName', $prefix ),
+                       $this->getCookie( $request, 'Token', $prefix ),
                );
        }
 
+       /**
+        * Get a cookie. Contains an auth-specific hack.
+        * @param \WebRequest $request
+        * @param string $key
+        * @param string $prefix
+        * @param mixed $default
+        * @return mixed
+        */
+       protected function getCookie( $request, $key, $prefix, $default = null ) {
+               $value = $request->getCookie( $key, $prefix, $default );
+               if ( $value === 'deleted' ) {
+                       // PHP uses this value when deleting cookies. A legitimate cookie will never have
+                       // this value (usernames start with uppercase, token is longer, other auth cookies
+                       // are booleans or integers). Seeing this means that in a previous request we told the
+                       // client to delete the cookie, but it has poor cookie handling. Pretend the cookie is
+                       // not there to avoid invalidating the session.
+                       return null;
+               }
+               return $value;
+       }
+
        /**
         * Return the data to store in cookies
         * @param User $user