Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions src/Extension/Bfstop.php
Original file line number Diff line number Diff line change
Expand Up @@ -748,21 +748,24 @@ private function isPasswordRecoveryRequest()
* Detects a request that actually submits login credentials, for
* "Login Only" block mode (issue #187): on the frontend, credentials
* are submitted to com_users (task=user.login), the backend login form
* posts to com_login (task=login); com_users with task=login is kept
* for backend entry URLs built that way - merely viewing the login
* form (no task, or a display task) doesn't match, so it stays
* reachable.
* posts to com_login (task=login) - merely viewing the login form (no
* task, or a display task) doesn't match, so it stays reachable.
*
* The task is compared as Joomla's dispatcher runs it (see
* requestedTask()): the login method of whatever controller, in any case
* - "task=user.LOGIN", "task=user.login.x" and
* "controller=user&task=login" are all logins. Matching more than
* Joomla would run only blocks a request which wouldn't do anything.
*/
private function isLoginAttemptRequest()
{
$option = $this->requestString('option');
$task = $this->requestString('task');
$result = (strcmp($option, 'com_users') == 0 &&
(strcmp($task, 'user.login') == 0 || strcmp($task, 'login') == 0)) ||
(strcmp($option, 'com_login') == 0 && strcmp($task, 'login') == 0);
$option = strtolower($this->requestString('option'));
list(, $method) = $this->requestedTask();
$result = ($option === 'com_users' || $option === 'com_login') && $method === 'login';
if ($result)
{
$this->logger->log('Detected a login-attempt request (task='.$task.')', Log::DEBUG);
$this->logger->log('Detected a login-attempt request (task='.
$this->requestString('task').')', Log::DEBUG);
}
return $result;
}
Expand Down
19 changes: 19 additions & 0 deletions tests/Integration/BlockedRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,25 @@ public function testLoginOnlyModeOnlyRejectsLoginAttempts()
$this->assertBlocked('option=com_login&task=login');
}

public function testLoginOnlyModeRecognisesEveryWayToLogIn()
{
// Joomla lowercases the method, ignores what follows a second dot and
// takes the controller from its own parameter if the task has no dot:
// each of these runs UserController::login()
$this->configure(array('blockMode' => 'loginonly'));
$this->block();
$this->assertBlocked('option=com_users&task=user.LOGIN');
$this->assertBlocked('option=com_users&task=User.Login');
$this->assertBlocked('option=com_users&task=user.login.x');
$this->assertBlocked('option=com_users&controller=user&task=login');
$this->assertBlocked('option=com_users&task=LOGIN');
$this->assertBlocked('option=com_login&task=LOGIN');
// still no login
$this->assertNotBlocked('option=com_users&task=user.logout');
$this->assertNotBlocked('option=com_users&view=login&task=display');
$this->assertNotBlocked('option=com_content&task=user.login');
}

public function testPasswordRecoveryStaysReachable()
{
// a blocked legitimate user must still be able to reset their password
Expand Down
Loading