Exemplo n.º 1
0
 public function testNewFromId()
 {
     $id = wfGetDB(DB_MASTER)->selectField('user', 'MAX(user_id)') + 1;
     try {
         UserInfo::newFromId($id);
         $this->fail('Expected exception not thrown');
     } catch (\InvalidArgumentException $ex) {
         $this->assertSame('Invalid ID', $ex->getMessage());
     }
     $user = User::newFromName('UTSysop');
     $userinfo = UserInfo::newFromId($user->getId());
     $this->assertFalse($userinfo->isAnon());
     $this->assertFalse($userinfo->isVerified());
     $this->assertSame($user->getId(), $userinfo->getId());
     $this->assertSame($user->getName(), $userinfo->getName());
     $this->assertSame($user->getToken(true), $userinfo->getToken());
     $this->assertInstanceOf('User', $userinfo->getUser());
     $userinfo2 = $userinfo->verified();
     $this->assertNotSame($userinfo2, $userinfo);
     $this->assertSame("<-:{$user->getId()}:{$user->getName()}>", (string) $userinfo);
     $this->assertFalse($userinfo2->isAnon());
     $this->assertTrue($userinfo2->isVerified());
     $this->assertSame($user->getId(), $userinfo2->getId());
     $this->assertSame($user->getName(), $userinfo2->getName());
     $this->assertSame($user->getToken(true), $userinfo2->getToken());
     $this->assertInstanceOf('User', $userinfo2->getUser());
     $this->assertSame($userinfo2, $userinfo2->verified());
     $this->assertSame("<+:{$user->getId()}:{$user->getName()}>", (string) $userinfo2);
     $userinfo = UserInfo::newFromId($user->getId(), true);
     $this->assertTrue($userinfo->isVerified());
     $this->assertSame($userinfo, $userinfo->verified());
 }
Exemplo n.º 2
0
 /**
  * Load and verify the session info against the store
  *
  * @param SessionInfo &$info Will likely be replaced with an updated SessionInfo instance
  * @param WebRequest $request
  * @return bool Whether the session info matches the stored data (if any)
  */
 private function loadSessionInfoFromStore(SessionInfo &$info, WebRequest $request)
 {
     $key = wfMemcKey('MWSession', $info->getId());
     $blob = $this->store->get($key);
     $newParams = array();
     if ($blob !== false) {
         // Sanity check: blob must be an array, if it's saved at all
         if (!is_array($blob)) {
             $this->logger->warning("Session {$info}: Bad data");
             $this->store->delete($key);
             return false;
         }
         // Sanity check: blob has data and metadata arrays
         if (!isset($blob['data']) || !is_array($blob['data']) || !isset($blob['metadata']) || !is_array($blob['metadata'])) {
             $this->logger->warning("Session {$info}: Bad data structure");
             $this->store->delete($key);
             return false;
         }
         $data = $blob['data'];
         $metadata = $blob['metadata'];
         // Sanity check: metadata must be an array and must contain certain
         // keys, if it's saved at all
         if (!array_key_exists('userId', $metadata) || !array_key_exists('userName', $metadata) || !array_key_exists('userToken', $metadata) || !array_key_exists('provider', $metadata)) {
             $this->logger->warning("Session {$info}: Bad metadata");
             $this->store->delete($key);
             return false;
         }
         // First, load the provider from metadata, or validate it against the metadata.
         $provider = $info->getProvider();
         if ($provider === null) {
             $newParams['provider'] = $provider = $this->getProvider($metadata['provider']);
             if (!$provider) {
                 $this->logger->warning("Session {$info}: Unknown provider, " . $metadata['provider']);
                 $this->store->delete($key);
                 return false;
             }
         } elseif ($metadata['provider'] !== (string) $provider) {
             $this->logger->warning("Session {$info}: Wrong provider, " . $metadata['provider'] . ' !== ' . $provider);
             return false;
         }
         // Load provider metadata from metadata, or validate it against the metadata
         $providerMetadata = $info->getProviderMetadata();
         if (isset($metadata['providerMetadata'])) {
             if ($providerMetadata === null) {
                 $newParams['metadata'] = $metadata['providerMetadata'];
             } else {
                 try {
                     $newProviderMetadata = $provider->mergeMetadata($metadata['providerMetadata'], $providerMetadata);
                     if ($newProviderMetadata !== $providerMetadata) {
                         $newParams['metadata'] = $newProviderMetadata;
                     }
                 } catch (\UnexpectedValueException $ex) {
                     $this->logger->warning("Session {$info}: Metadata merge failed: " . $ex->getMessage());
                     return false;
                 }
             }
         }
         // Next, load the user from metadata, or validate it against the metadata.
         $userInfo = $info->getUserInfo();
         if (!$userInfo) {
             // For loading, id is preferred to name.
             try {
                 if ($metadata['userId']) {
                     $userInfo = UserInfo::newFromId($metadata['userId']);
                 } elseif ($metadata['userName'] !== null) {
                     // Shouldn't happen, but just in case
                     $userInfo = UserInfo::newFromName($metadata['userName']);
                 } else {
                     $userInfo = UserInfo::newAnonymous();
                 }
             } catch (\InvalidArgumentException $ex) {
                 $this->logger->error("Session {$info}: " . $ex->getMessage());
                 return false;
             }
             $newParams['userInfo'] = $userInfo;
         } else {
             // User validation passes if user ID matches, or if there
             // is no saved ID and the names match.
             if ($metadata['userId']) {
                 if ($metadata['userId'] !== $userInfo->getId()) {
                     $this->logger->warning("Session {$info}: User ID mismatch, " . $metadata['userId'] . ' !== ' . $userInfo->getId());
                     return false;
                 }
                 // If the user was renamed, probably best to fail here.
                 if ($metadata['userName'] !== null && $userInfo->getName() !== $metadata['userName']) {
                     $this->logger->warning("Session {$info}: User ID matched but name didn't (rename?), " . $metadata['userName'] . ' !== ' . $userInfo->getName());
                     return false;
                 }
             } elseif ($metadata['userName'] !== null) {
                 // Shouldn't happen, but just in case
                 if ($metadata['userName'] !== $userInfo->getName()) {
                     $this->logger->warning("Session {$info}: User name mismatch, " . $metadata['userName'] . ' !== ' . $userInfo->getName());
                     return false;
                 }
             } elseif (!$userInfo->isAnon()) {
                 // Metadata specifies an anonymous user, but the passed-in
                 // user isn't anonymous.
                 $this->logger->warning("Session {$info}: Metadata has an anonymous user, " . 'but a non-anon user was provided');
                 return false;
             }
         }
         // And if we have a token in the metadata, it must match the loaded/provided user.
         if ($metadata['userToken'] !== null && $userInfo->getToken() !== $metadata['userToken']) {
             $this->logger->warning("Session {$info}: User token mismatch");
             return false;
         }
         if (!$userInfo->isVerified()) {
             $newParams['userInfo'] = $userInfo->verified();
         }
         if (!empty($metadata['remember']) && !$info->wasRemembered()) {
             $newParams['remembered'] = true;
         }
         if (!empty($metadata['forceHTTPS']) && !$info->forceHTTPS()) {
             $newParams['forceHTTPS'] = true;
         }
         if (!$info->isIdSafe()) {
             $newParams['idIsSafe'] = true;
         }
     } else {
         // No metadata, so we can't load the provider if one wasn't given.
         if ($info->getProvider() === null) {
             $this->logger->warning("Session {$info}: Null provider and no metadata");
             return false;
         }
         // If no user was provided and no metadata, it must be anon.
         if (!$info->getUserInfo()) {
             if ($info->getProvider()->canChangeUser()) {
                 $newParams['userInfo'] = UserInfo::newAnonymous();
             } else {
                 $this->logger->info("Session {$info}: No user provided and provider cannot set user");
                 return false;
             }
         } elseif (!$info->getUserInfo()->isVerified()) {
             $this->logger->warning("Session {$info}: Unverified user provided and no metadata to auth it");
             return false;
         }
         $data = false;
         $metadata = false;
         if (!$info->getProvider()->persistsSessionId() && !$info->isIdSafe()) {
             // The ID doesn't come from the user, so it should be safe
             // (and if not, nothing we can do about it anyway)
             $newParams['idIsSafe'] = true;
         }
     }
     // Construct the replacement SessionInfo, if necessary
     if ($newParams) {
         $newParams['copyFrom'] = $info;
         $info = new SessionInfo($info->getPriority(), $newParams);
     }
     // Allow the provider to check the loaded SessionInfo
     $providerMetadata = $info->getProviderMetadata();
     if (!$info->getProvider()->refreshSessionInfo($info, $request, $providerMetadata)) {
         return false;
     }
     if ($providerMetadata !== $info->getProviderMetadata()) {
         $info = new SessionInfo($info->getPriority(), array('metadata' => $providerMetadata, 'copyFrom' => $info));
     }
     // Give hooks a chance to abort. Combined with the SessionMetadata
     // hook, this can allow for tying a session to an IP address or the
     // like.
     $reason = 'Hook aborted';
     if (!\Hooks::run('SessionCheckInfo', array(&$reason, $info, $request, $metadata, $data))) {
         $this->logger->warning("Session {$info}: {$reason}");
         return false;
     }
     return true;
 }
Exemplo n.º 3
0
 public function provideSessionInfo(WebRequest $request)
 {
     $sessionId = $this->getCookie($request, $this->params['sessionName'], '');
     $info = array('provider' => $this, 'forceHTTPS' => $this->getCookie($request, 'forceHTTPS', '', false));
     if (SessionManager::validateSessionId($sessionId)) {
         $info['id'] = $sessionId;
         $info['persisted'] = true;
     }
     list($userId, $userName, $token) = $this->getUserInfoFromCookies($request);
     if ($userId !== null) {
         try {
             $userInfo = UserInfo::newFromId($userId);
         } catch (\InvalidArgumentException $ex) {
             return null;
         }
         // Sanity check
         if ($userName !== null && $userInfo->getName() !== $userName) {
             $this->logger->warning('Session "{session}" requested with mismatched UserID and UserName cookies.', array('session' => $sessionId, 'mismatch' => array('userid' => $userId, 'cookie_username' => $userName, 'username' => $userInfo->getName())));
             return null;
         }
         if ($token !== null) {
             if (!hash_equals($userInfo->getToken(), $token)) {
                 $this->logger->warning('Session "{session}" requested with invalid Token cookie.', array('session' => $sessionId, 'userid' => $userId, 'username' => $userInfo->getName()));
                 return null;
             }
             $info['userInfo'] = $userInfo->verified();
         } elseif (isset($info['id'])) {
             $info['userInfo'] = $userInfo;
         } else {
             // No point in returning, loadSessionInfoFromStore() will
             // reject it anyway.
             return null;
         }
     } elseif (isset($info['id'])) {
         // No UserID cookie, so insist that the session is anonymous.
         // Note: this event occurs for several normal activities:
         // * anon visits Special:UserLogin
         // * anon browsing after seeing Special:UserLogin
         // * anon browsing after edit or preview
         $this->logger->debug('Session "{session}" requested without UserID cookie', array('session' => $info['id']));
         $info['userInfo'] = UserInfo::newAnonymous();
     } else {
         // No session ID and no user is the same as an empty session, so
         // there's no point.
         return null;
     }
     return new SessionInfo($this->priority, $info);
 }
Exemplo n.º 4
0
 public function provideSessionInfo(WebRequest $request)
 {
     $info = array('id' => $this->getCookie($request, $this->params['sessionName'], ''));
     if (!SessionManager::validateSessionId($info['id'])) {
         unset($info['id']);
     }
     list($userId, $userName, $token) = $this->getUserInfoFromCookies($request);
     if ($userId !== null) {
         try {
             $userInfo = UserInfo::newFromId($userId);
         } catch (\InvalidArgumentException $ex) {
             return null;
         }
         // Sanity check
         if ($userName !== null && $userInfo->getName() !== $userName) {
             return null;
         }
         if ($token !== null) {
             if (!hash_equals($userInfo->getToken(), $token)) {
                 return null;
             }
             $info['userInfo'] = $userInfo->verified();
         } elseif (isset($info['id'])) {
             // No point if no session ID
             $info['userInfo'] = $userInfo;
         }
     }
     if (!$info) {
         return null;
     }
     $info += array('provider' => $this, 'persisted' => isset($info['id']), 'forceHTTPS' => $this->getCookie($request, 'forceHTTPS', '', false));
     return new SessionInfo($this->priority, $info);
 }
Exemplo n.º 5
0
 public function provideSessionInfo(WebRequest $request)
 {
     $info = array('id' => $this->getCookie($request, $this->params['sessionName'], ''), 'provider' => $this, 'forceHTTPS' => $this->getCookie($request, 'forceHTTPS', '', false));
     if (!SessionManager::validateSessionId($info['id'])) {
         unset($info['id']);
     }
     $info['persisted'] = isset($info['id']);
     list($userId, $userName, $token) = $this->getUserInfoFromCookies($request);
     if ($userId !== null) {
         try {
             $userInfo = UserInfo::newFromId($userId);
         } catch (\InvalidArgumentException $ex) {
             return null;
         }
         // Sanity check
         if ($userName !== null && $userInfo->getName() !== $userName) {
             return null;
         }
         if ($token !== null) {
             if (!hash_equals($userInfo->getToken(), $token)) {
                 return null;
             }
             $info['userInfo'] = $userInfo->verified();
         } elseif (isset($info['id'])) {
             $info['userInfo'] = $userInfo;
         } else {
             // No point in returning, loadSessionInfoFromStore() will
             // reject it anyway.
             return null;
         }
     } elseif (isset($info['id'])) {
         // No UserID cookie, so insist that the session is anonymous.
         $info['userInfo'] = UserInfo::newAnonymous();
     } else {
         // No session ID and no user is the same as an empty session, so
         // there's no point.
         return null;
     }
     return new SessionInfo($this->priority, $info);
 }