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

Require current password when user changes own pwd #6971

Merged
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
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 @@ -714,6 +714,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
Loading