Skip to content

Commit

Permalink
Merge pull request #6971 from getkirby/enhancement/change-password-co…
Browse files Browse the repository at this point in the history
…nfirm-current

Require current password when user changes own pwd
  • Loading branch information
bastianallgeier authored Feb 7, 2025
2 parents 5879249 + 82e48ad commit 8d471ee
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 21 deletions.
25 changes: 21 additions & 4 deletions config/areas/users/dialogs.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Kirby\Cms\App;
use Kirby\Cms\Find;
use Kirby\Cms\UserRules;
use Kirby\Exception\Exception;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Panel\Field;
use Kirby\Panel\Panel;
Expand Down Expand Up @@ -180,12 +181,15 @@
'user.changePassword' => [
'pattern' => 'users/(:any)/changePassword',
'load' => function (string $id) {
$user = Find::user($id);
Find::user($id);

return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'fields' => [
'currentPassword' => Field::password([
'label' => I18n::translate('user.changePassword.current'),
]),
'password' => Field::password([
'label' => I18n::translate('user.changePassword.new'),
]),
Expand All @@ -198,13 +202,26 @@
];
},
'submit' => function (string $id) {
$request = App::instance()->request();
$kirby = App::instance();
$request = $kirby->request();

$user = Find::user($id);
$currentPassword = $request->get('currentPassword');
$password = $request->get('password');
$passwordConfirmation = $request->get('passwordConfirmation');

// validate the password
// validate the current password of the acting user
try {
$kirby->user()->validatePassword($currentPassword);
} catch (Exception) {
// catching and re-throwing exception to avoid automatic
// sign-out of current user from the Panel
throw new InvalidArgumentException([
'key' => 'user.password.wrong'
]);
}

// validate the new password
UserRules::validPassword($user, $password ?? '');

// compare passwords
Expand Down
1 change: 1 addition & 0 deletions i18n/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@
"user.changeLanguage": "Change language",
"user.changeName": "Rename this user",
"user.changePassword": "Change password",
"user.changePassword.current": "Your current password",
"user.changePassword.new": "New password",
"user.changePassword.new.confirm": "Confirm the new password…",
"user.changeRole": "Change role",
Expand Down
3 changes: 3 additions & 0 deletions src/Cms/UserActions.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public function changeName(string $name): static

/**
* Changes the user password
*
* If this method is used with user input, it is recommended to also
* confirm the current password by the user via `::validatePassword()`
*/
public function changePassword(
#[SensitiveParameter]
Expand Down
32 changes: 25 additions & 7 deletions tests/Panel/Areas/AccountDialogsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public function testChangePassword(): void

$this->assertFormDialog($dialog);

$this->assertSame('Your current password', $props['fields']['currentPassword']['label']);
$this->assertSame('New password', $props['fields']['password']['label']);
$this->assertSame('Confirm the new password…', $props['fields']['passwordConfirmation']['label']);
$this->assertSame('Change', $props['submitButton']);
Expand All @@ -105,23 +106,39 @@ public function testChangePassword(): void
public function testChangePasswordOnSubmit(): void
{
$this->submit([
'password' => '12345678',
'passwordConfirmation' => '12345678'
'currentPassword' => '12345678',
'password' => 'abcdefgh',
'passwordConfirmation' => 'abcdefgh'
]);

$dialog = $this->dialog('account/changePassword');

$this->assertSame('user.changePassword', $dialog['event']);
$this->assertSame(200, $dialog['code']);

$this->assertTrue($this->app->user('test')->validatePassword(12345678));
$this->assertTrue($this->app->user('test')->validatePassword('abcdefgh'));
}

public function testChangePasswordOnSubmitWithInvalidCurrentPassword(): void
{
$this->submit([
'currentPassword' => '123456',
'password' => 'abcdefgh',
'passwordConfirmation' => 'abcdefgh'
]);

$dialog = $this->dialog('account/changePassword');

$this->assertSame(400, $dialog['code']);
$this->assertSame('Wrong password', $dialog['error']);
}

public function testChangePasswordOnSubmitWithInvalidPassword(): void
{
$this->submit([
'password' => '1234567',
'passwordConfirmation' => '1234567'
'currentPassword' => '12345678',
'password' => 'abcdef',
'passwordConfirmation' => 'abcdef'
]);

$dialog = $this->dialog('account/changePassword');
Expand All @@ -133,8 +150,9 @@ public function testChangePasswordOnSubmitWithInvalidPassword(): void
public function testChangePasswordOnSubmitWithInvalidConfirmation(): void
{
$this->submit([
'password' => '12345678',
'passwordConfirmation' => '1234567'
'currentPassword' => '12345678',
'password' => 'abcdefgh',
'passwordConfirmation' => 'abcdefg'
]);

$dialog = $this->dialog('account/changePassword');
Expand Down
8 changes: 5 additions & 3 deletions tests/Panel/Areas/AreaTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Kirby\Cms\App;
use Kirby\Cms\Blueprint;
use Kirby\Cms\User;
use Kirby\Filesystem\Dir;
use Kirby\Http\Response;
use Kirby\Panel\Panel;
Expand Down Expand Up @@ -82,9 +83,10 @@ public function install(): void
$this->app([
'users' => [
[
'id' => 'test',
'email' => 'test@getkirby.com',
'role' => 'admin',
'id' => 'test',
'email' => 'test@getkirby.com',
'role' => 'admin',
'password' => User::hashPassword('12345678')
]
]
]);
Expand Down
32 changes: 25 additions & 7 deletions tests/Panel/Areas/UsersDialogsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public function testChangePassword(): void

$this->assertFormDialog($dialog);

$this->assertSame('Your current password', $props['fields']['currentPassword']['label']);
$this->assertSame('New password', $props['fields']['password']['label']);
$this->assertSame('Confirm the new password…', $props['fields']['passwordConfirmation']['label']);
$this->assertSame('Change', $props['submitButton']);
Expand All @@ -168,23 +169,39 @@ public function testChangePassword(): void
public function testChangePasswordOnSubmit(): void
{
$this->submit([
'password' => '12345678',
'passwordConfirmation' => '12345678'
'currentPassword' => '12345678',
'password' => 'abcdefgh',
'passwordConfirmation' => 'abcdefgh'
]);

$dialog = $this->dialog('users/test/changePassword');

$this->assertSame('user.changePassword', $dialog['event']);
$this->assertSame(200, $dialog['code']);

$this->assertTrue($this->app->user('test')->validatePassword(12345678));
$this->assertTrue($this->app->user('test')->validatePassword('abcdefgh'));
}

public function testChangePasswordOnSubmitWithInvalidCurrentPassword(): void
{
$this->submit([
'currentPassword' => '123456',
'password' => 'abcdefgh',
'passwordConfirmation' => 'abcdefgh'
]);

$dialog = $this->dialog('users/test/changePassword');

$this->assertSame(400, $dialog['code']);
$this->assertSame('Wrong password', $dialog['error']);
}

public function testChangePasswordOnSubmitWithInvalidPassword(): void
{
$this->submit([
'password' => '1234567',
'passwordConfirmation' => '1234567'
'currentPassword' => '12345678',
'password' => 'abcdef',
'passwordConfirmation' => 'abcdef'
]);

$dialog = $this->dialog('users/test/changePassword');
Expand All @@ -196,8 +213,9 @@ public function testChangePasswordOnSubmitWithInvalidPassword(): void
public function testChangePasswordOnSubmitWithInvalidConfirmation(): void
{
$this->submit([
'password' => '12345678',
'passwordConfirmation' => '1234567'
'currentPassword' => '12345678',
'password' => 'abcdefgh',
'passwordConfirmation' => 'abcdefg'
]);

$dialog = $this->dialog('users/test/changePassword');
Expand Down

0 comments on commit 8d471ee

Please sign in to comment.