diff --git a/core/Controller/LostController.php b/core/Controller/LostController.php
index 325975bdd5b7..4a1f6ccc712a 100644
--- a/core/Controller/LostController.php
+++ b/core/Controller/LostController.php
@@ -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;
@@ -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);
diff --git a/tests/Core/Controller/LostControllerTest.php b/tests/Core/Controller/LostControllerTest.php
index 93f56a0c320f..d668592c67ee 100644
--- a/tests/Core/Controller/LostControllerTest.php
+++ b/tests/Core/Controller/LostControllerTest.php
@@ -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')
@@ -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));
@@ -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(
+ [
+ ['test@example.com', null],
+ ['ExistingUser', $this->existingUser]
+ ]
+ );
+ $this->userManager
+ ->expects($this->once())
+ ->method('getByEmail')
+ ->with('test@example.com')
+ ->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(['test@example.com' => '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: https://ownCloud.com/index.php/lostpassword/'));
+ $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('test@example.com');
+ $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())
diff --git a/tests/acceptance/features/webUILogin/resetPasswordUsingEmail.feature b/tests/acceptance/features/webUILogin/resetPasswordUsingEmail.feature
index 79590e7feb5f..38b0f8e78e01 100644
--- a/tests/acceptance/features/webUILogin/resetPasswordUsingEmail.feature
+++ b/tests/acceptance/features/webUILogin/resetPasswordUsingEmail.feature
@@ -23,23 +23,16 @@ Feature: reset the password using an email address
Use the following link to reset your password: