@@ -51,6 +51,8 @@ | |||
namespace OC\User; | |||
use OC\Cache\CappedMemoryCache; | |||
use Symfony\Component\EventDispatcher\EventDispatcher; | |||
use Symfony\Component\EventDispatcher\GenericEvent; | |||
/** | |||
* Class for user management in a SQL Database (e.g. MySQL, SQLite) | |||
@@ -58,12 +60,14 @@ use OC\Cache\CappedMemoryCache; | |||
class Database extends \OC\User\Backend implements \OCP\IUserBackend { | |||
/** @var CappedMemoryCache */ | |||
private $cache; | |||
/** @var EventDispatcher */ | |||
private $eventDispatcher; | |||
/** | |||
* OC_User_Database constructor. | |||
*/ | |||
public function __construct() { | |||
public function __construct($eventDispatcher = null) { | |||
$this->cache = new CappedMemoryCache(); | |||
$this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->getEventDispatcher(); | |||
} | |||
/** | |||
@@ -115,6 +119,8 @@ class Database extends \OC\User\Backend implements \OCP\IUserBackend { | |||
*/ | |||
public function setPassword($uid, $password) { | |||
if ($this->userExists($uid)) { | |||
$event = new GenericEvent($password); | |||
$this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event); | |||
$query = \OC_DB::prepare('UPDATE `*PREFIX*users` SET `password` = ? WHERE `uid` = ?'); | |||
$result = $query->execute(array(\OC::$server->getHasher()->hash($password), $uid)); | |||
@@ -30,6 +30,8 @@ | |||
*/ | |||
namespace OC\Settings\ChangePassword; | |||
use OC\HintException; | |||
class Controller { | |||
public static function changePersonalPassword($args) { | |||
// Check if we are an user | |||
@@ -39,17 +41,22 @@ class Controller { | |||
$username = \OC_User::getUser(); | |||
$password = isset($_POST['personal-password']) ? $_POST['personal-password'] : null; | |||
$oldPassword = isset($_POST['oldpassword']) ? $_POST['oldpassword'] : ''; | |||
$l = new \OC_L10n('settings'); | |||
if (!\OC_User::checkPassword($username, $oldPassword)) { | |||
$l = new \OC_L10n('settings'); | |||
\OC_JSON::error(array("data" => array("message" => $l->t("Wrong password")) )); | |||
exit(); | |||
} | |||
if (!is_null($password) && \OC_User::setPassword($username, $password)) { | |||
\OC::$server->getUserSession()->updateSessionTokenPassword($password); | |||
\OC_JSON::success(); | |||
} else { | |||
\OC_JSON::error(); | |||
try { | |||
if (!is_null($password) && \OC_User::setPassword($username, $password)) { | |||
\OC::$server->getUserSession()->updateSessionTokenPassword($password); | |||
\OC_JSON::success(['data' => ['message' => $l->t('Saved')]]); | |||
} else { | |||
\OC_JSON::error(); | |||
} | |||
} catch (HintException $e) { | |||
\OC_JSON::error(['data' => ['message' => $e->getHint()]]); | |||
} | |||
} | |||
@@ -150,10 +157,14 @@ class Controller { | |||
} | |||
} else { // if encryption is disabled, proceed | |||
if (!is_null($password) && \OC_User::setPassword($username, $password)) { | |||
\OC_JSON::success(array('data' => array('username' => $username))); | |||
} else { | |||
\OC_JSON::error(array('data' => array('message' => $l->t('Unable to change password')))); | |||
try { | |||
if (!is_null($password) && \OC_User::setPassword($username, $password)) { | |||
\OC_JSON::success(array('data' => array('username' => $username))); | |||
} else { | |||
\OC_JSON::error(array('data' => array('message' => $l->t('Unable to change password')))); | |||
} | |||
} catch (HintException $e) { | |||
\OC_JSON::error(array('data' => array('message' => $e->getHint()))); | |||
} | |||
} | |||
} |
@@ -192,6 +192,7 @@ $(document).ready(function () { | |||
$('#pass2').showPassword().keyup(); | |||
} | |||
$("#passwordbutton").click(function () { | |||
OC.msg.startSaving('#password-error-msg'); | |||
var isIE8or9 = $('html').hasClass('lte9'); | |||
// FIXME - TODO - once support for IE8 and IE9 is dropped | |||
// for IE8 and IE9 this will check additionally if the typed in password | |||
@@ -208,25 +209,32 @@ $(document).ready(function () { | |||
if (data.status === "success") { | |||
$('#pass1').val(''); | |||
$('#pass2').val('').change(); | |||
// Hide a possible errormsg and show successmsg | |||
$('#password-changed').removeClass('hidden').addClass('inlineblock'); | |||
$('#password-error').removeClass('inlineblock').addClass('hidden'); | |||
OC.msg.finishedSaving('#password-error-msg', data); | |||
} else { | |||
if (typeof(data.data) !== "undefined") { | |||
$('#password-error').text(data.data.message); | |||
OC.msg.finishedSaving('#password-error-msg', data); | |||
} else { | |||
$('#password-error').text(t('Unable to change password')); | |||
OC.msg.finishedSaving('#password-error-msg', | |||
{ | |||
'status' : 'error', | |||
'data' : { | |||
'message' : t('core', 'Unable to change password') | |||
} | |||
} | |||
); | |||
} | |||
// Hide a possible successmsg and show errormsg | |||
$('#password-changed').removeClass('inlineblock').addClass('hidden'); | |||
$('#password-error').removeClass('hidden').addClass('inlineblock'); | |||
} | |||
}); | |||
return false; | |||
} else { | |||
// Hide a possible successmsg and show errormsg | |||
$('#password-changed').removeClass('inlineblock').addClass('hidden'); | |||
$('#password-error').removeClass('hidden').addClass('inlineblock'); | |||
OC.msg.finishedSaving('#password-error-msg', | |||
{ | |||
'status' : 'error', | |||
'data' : { | |||
'message' : t('core', 'Unable to change password') | |||
} | |||
} | |||
); | |||
return false; | |||
} | |||
@@ -118,8 +118,7 @@ if($_['passwordChangeSupported']) { | |||
?> | |||
<form id="passwordform" class="section"> | |||
<h2 class="inlineblock"><?php p($l->t('Password'));?></h2> | |||
<div class="hidden icon-checkmark" id="password-changed"></div> | |||
<div class="hidden" id="password-error"><?php p($l->t('Unable to change your password'));?></div> | |||
<div id="password-error-msg" class="msg success inlineblock" style="display: none;">Saved</div> | |||
<br> | |||
<label for="pass1" class="hidden-visually"><?php echo $l->t('Current password');?>: </label> | |||
<input type="password" id="pass1" name="oldpassword" |
@@ -21,6 +21,9 @@ | |||
*/ | |||
namespace Test\User; | |||
use OC\HintException; | |||
use Symfony\Component\EventDispatcher\EventDispatcher; | |||
use Symfony\Component\EventDispatcher\GenericEvent; | |||
/** | |||
* Class DatabaseTest | |||
@@ -30,6 +33,8 @@ namespace Test\User; | |||
class DatabaseTest extends Backend { | |||
/** @var array */ | |||
private $users; | |||
/** @var EventDispatcher | \PHPUnit_Framework_MockObject_MockObject */ | |||
private $eventDispatcher; | |||
public function getUser() { | |||
$user = parent::getUser(); | |||
@@ -39,7 +44,10 @@ class DatabaseTest extends Backend { | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->backend=new \OC\User\Database(); | |||
$this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcher'); | |||
$this->backend=new \OC\User\Database($this->eventDispatcher); | |||
} | |||
protected function tearDown() { | |||
@@ -51,4 +59,41 @@ class DatabaseTest extends Backend { | |||
} | |||
parent::tearDown(); | |||
} | |||
public function testVerifyPasswordEvent() { | |||
$user = $this->getUser(); | |||
$this->backend->createUser($user, 'pass1'); | |||
$this->eventDispatcher->expects($this->once())->method('dispatch') | |||
->willReturnCallback( | |||
function ($eventName, GenericEvent $event) { | |||
$this->assertSame('OCP\PasswordPolicy::validate', $eventName); | |||
$this->assertSame('newpass', $event->getSubject()); | |||
} | |||
); | |||
$this->backend->setPassword($user, 'newpass'); | |||
$this->assertSame($user, $this->backend->checkPassword($user, 'newpass')); | |||
} | |||
/** | |||
* @expectedException \OC\HintException | |||
* @expectedExceptionMessage password change failed | |||
*/ | |||
public function testVerifyPasswordEventFail() { | |||
$user = $this->getUser(); | |||
$this->backend->createUser($user, 'pass1'); | |||
$this->eventDispatcher->expects($this->once())->method('dispatch') | |||
->willReturnCallback( | |||
function ($eventName, GenericEvent $event) { | |||
$this->assertSame('OCP\PasswordPolicy::validate', $eventName); | |||
$this->assertSame('newpass', $event->getSubject()); | |||
throw new HintException('password change failed', 'password change failed'); | |||
} | |||
); | |||
$this->backend->setPassword($user, 'newpass'); | |||
$this->assertSame($user, $this->backend->checkPassword($user, 'newpass')); | |||
} | |||
} |