Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-10.2.1] Fix invalid token on pw reset #35607

Merged
merged 1 commit into from
Jun 20, 2019
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
17 changes: 17 additions & 0 deletions core/Controller/LostController.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use \OCP\IRequest;
use \OCP\IL10N;
use \OCP\IConfig;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Mail\IMailer;
use OCP\Security\ISecureRandom;
Expand Down Expand Up @@ -203,6 +204,22 @@ private function success() {
* @return array
*/
public function email($user) {
try {
$userObject = $this->userManager->get($user);
if ($userObject === null) {
$users = $this->userManager->getByEmail($user);
// we only allow login by email if unique
if (\count($users) === 1) {
$user = $users[0]->getUID();
}
}
if ($userObject instanceof IUser) {
$user = $userObject->getUID();
}
} catch (\Exception $e) {
// Do not disclose any information during User lookup
return $this->success();
}
// FIXME: use HTTP error codes
try {
list($link, $token) = $this->generateTokenAndLink($user);
Expand Down
131 changes: 130 additions & 1 deletion tests/Core/Controller/LostControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ protected function setUp() {
->method('getDisplayName')
->willReturn('Existing User Name');

$this->existingUser
->expects($this->any())
->method('getUID')
->willReturn('ExistingUser');

$this->config = $this->getMockBuilder('\OCP\IConfig')
->disableOriginalConstructor()->getMock();
$this->l10n = $this->getMockBuilder('\OCP\IL10N')
Expand Down Expand Up @@ -295,7 +300,7 @@ public function testSpamEmail() {
->with($user)
->will($this->returnValue(true));
$this->userManager
->expects($this->once())
->expects($this->exactly(2))
->method('get')
->with($user)
->will($this->returnValue($this->existingUser));
Expand All @@ -320,6 +325,130 @@ public function testSpamEmail() {
$this->assertSame($expectedResponse, $response);
}

public function testExceptionDuringUserLookup() {
$user = 'ExistingUser';
$this->userManager
->expects($this->once())
->method('get')
->with($user)
->willThrowException(new \Exception("User not found"));
$expectedResponse = [
'status' => 'success'
];
$response = $this->lostController->email($user);
$this->assertSame($expectedResponse, $response);
}

public function testEmailUsedForLoginSuccessful() {
$this->config
->expects($this->once())
->method('getUserValue')
->with('ExistingUser', 'owncloud', 'lostpassword')
->will($this->returnValue('12000:AVerySecretToken'));
$this->timeFactory
->expects($this->any())
->method('getTime')
->willReturnOnConsecutiveCalls(12301, 12348);
$this->secureRandom
->expects($this->once())
->method('generate')
->with('21')
->will($this->returnValue('ThisIsMaybeANotSoSecretToken!'));
$this->userManager
->expects($this->once())
->method('userExists')
->with('ExistingUser')
->will($this->returnValue(true));
$this->userManager
->expects($this->any())
->method('get')
->willReturnMap(
[
['[email protected]', null],
['ExistingUser', $this->existingUser]
]
);
$this->userManager
->expects($this->once())
->method('getByEmail')
->with('[email protected]')
->willReturn([$this->existingUser]);

$this->config
->expects($this->once())
->method('setUserValue')
->with('ExistingUser', 'owncloud', 'lostpassword', '12348:ThisIsMaybeANotSoSecretToken!');
$this->urlGenerator
->expects($this->once())
->method('linkToRouteAbsolute')
->with('core.lost.resetform', ['userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!'])
->will($this->returnValue('https://ownCloud.com/index.php/lostpassword/'));
$message = $this->getMockBuilder('\OC\Mail\Message')
->disableOriginalConstructor()->getMock();
$message
->expects($this->at(0))
->method('setTo')
->with(['[email protected]' => 'Existing User Name']);
$message
->expects($this->at(1))
->method('setSubject')
->with(' password reset');
$message
->expects($this->at(2))
->method('setPlainBody')
->with($this->stringContains('Use the following link to reset your password: https://ownCloud.com/index.php/lostpassword/'));
$message
->expects($this->at(3))
->method('setHtmlBody')
->with($this->stringContains('Use the following link to reset your password: <a href="https://ownCloud.com/index.php/lostpassword/">https://ownCloud.com/index.php/lostpassword/</a>'));
$message
->expects($this->at(4))
->method('setFrom')
->with(['lostpassword-noreply@localhost' => null]);
$this->mailer
->expects($this->at(0))
->method('createMessage')
->will($this->returnValue($message));
$this->mailer
->expects($this->at(1))
->method('send')
->with($message);

$response = $this->lostController->email('[email protected]');
$expectedResponse = ['status' => 'success'];
$this->assertSame($expectedResponse, $response);
}

public function testEmailUsedForLoginUnsuccessful() {
$nonExistingUser = 'test2@example,com';
$this->userManager
->expects($this->once())
->method('get')
->with('test2@example,com')
->willReturn(null);
$this->userManager
->expects($this->any())
->method('getByEmail')
->with($nonExistingUser)
->willReturn([]);
$this->userManager
->expects($this->once())
->method('userExists')
->with($nonExistingUser)
->willReturn(false);
$this->logger->expects($this->any())
->method('error')
->with('Could not send reset email because User does not exist. User: {user}');

// With a non existing user
$response = $this->lostController->email($nonExistingUser);
$expectedResponse = [
'status' => 'success'
];

$this->assertSame($expectedResponse, $response);
}

public function testEmailSuccessful() {
$this->config
->expects($this->once())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,16 @@ Feature: reset the password using an email address
Use the following link to reset your password: <a href=
"""

@skipOnEncryption
# consider adding this to the smoke tests when the issue is fixed @smokeTest
@issue-32889
@skipOnEncryption @smokeTest
Scenario: reset password for the ordinary (no encryption) case
When the user requests the password reset link using the webUI
And the user follows the password reset link from email address "[email protected]"
Then the user should be redirected to a webUI page with the title "%productname%"
# The issue is that the system thinks the link token is invalid
And a lost password reset error message with this text should be displayed on the webUI:
"""
Could not reset password because the token is invalid
"""
#When the user resets the password to "%alt3%" using the webUI
#Then the user should be redirected to the login page
#And the email address "[email protected]" should have received an email with the body containing
# """
# Password changed successfully
# """
#When the user logs in with username "user1" and password "%alt3%" using the webUI
#Then the user should be redirected to a webUI page with the title "Files - %productname%"
When the user resets the password to "%alt3%" and confirms with the same password using the webUI
Then the user should be redirected to the login page
And the email address "[email protected]" should have received an email with the body containing
"""
Password changed successfully
"""
When the user logs in with username "user1" and password "%alt3%" using the webUI
Then the user should be redirected to a webUI page with the title "Files - %productname%"