Merge pull request #35419 from nextcloud/fix/login-csrf-not-logged-in-clear-cookies

Fix login loop if login CSRF fails and user is not logged in
This commit is contained in:
Christoph Wurst 2023-01-18 11:55:24 +01:00 committed by GitHub
commit 9e08e49998
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 14 deletions

View File

@ -303,11 +303,23 @@ class LoginController extends Controller {
string $redirect_url = null,
string $timezone = '',
string $timezone_offset = ''): RedirectResponse {
// If the user is already logged in and the CSRF check does not pass then
// simply redirect the user to the correct page as required. This is the
// case when an user has already logged-in, in another tab.
if (!$this->request->passesCSRFCheck()) {
return $this->generateRedirect($redirect_url);
if ($this->userSession->isLoggedIn()) {
// If the user is already logged in and the CSRF check does not pass then
// simply redirect the user to the correct page as required. This is the
// case when a user has already logged-in, in another tab.
return $this->generateRedirect($redirect_url);
}
// Clear any auth remnants like cookies to ensure a clean login
// For the next attempt
$this->userSession->logout();
return $this->createLoginFailedResponse(
$user,
$user,
$redirect_url,
$this->l10n->t('Please try again')
);
}
$data = new LoginData(

View File

@ -511,7 +511,7 @@ class LoginControllerTest extends TestCase {
$this->assertEquals($expected, $this->loginController->tryLogin($user, $password));
}
public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn() {
public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn(): void {
/** @var IUser|MockObject $user */
$user = $this->createMock(IUser::class);
$user->expects($this->any())
@ -524,7 +524,7 @@ class LoginControllerTest extends TestCase {
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(false);
$this->userSession->expects($this->once())
$this->userSession
->method('isLoggedIn')
->with()
->willReturn(false);
@ -532,13 +532,12 @@ class LoginControllerTest extends TestCase {
->method('deleteUserValue');
$this->userSession->expects($this->never())
->method('createRememberMeToken');
$this->urlGenerator
->expects($this->once())
->method('linkToDefaultPageUrl')
->willReturn('/default/foo');
$expected = new RedirectResponse('/default/foo');
$this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
$response = $this->loginController->tryLogin('Jane', $password, $originalUrl);
$expected = new RedirectResponse('');
$expected->throttle(['user' => 'Jane']);
$this->assertEquals($expected, $response);
}
public function testLoginWithoutPassedCsrfCheckAndLoggedIn() {
@ -555,7 +554,7 @@ class LoginControllerTest extends TestCase {
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(false);
$this->userSession->expects($this->once())
$this->userSession
->method('isLoggedIn')
->with()
->willReturn(true);
@ -572,8 +571,10 @@ class LoginControllerTest extends TestCase {
->with('remember_login_cookie_lifetime')
->willReturn(1234);
$response = $this->loginController->tryLogin('Jane', $password, $originalUrl);
$expected = new RedirectResponse($redirectUrl);
$this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
$this->assertEquals($expected, $response);
}
public function testLoginWithValidCredentialsAndRedirectUrl() {