Skip to content

Commit

Permalink
Merge pull request #6 from movabletype/fix-new-password
Browse files Browse the repository at this point in the history
fix new password MTC-28857
  • Loading branch information
usualoma authored Apr 12, 2023
2 parents 14237fd + c0de5b0 commit b7c41a7
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 15 deletions.
17 changes: 5 additions & 12 deletions mt-static/plugins/MFA/src/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,36 +52,29 @@ function renderMFAForm() {

rendered = true;

const fieldSelector = [
"#username-field, #password-field, #remember-me, #remember-me + div", // login
"#page-title, #name-field, #name-field + div", // new_password
].join(",");
const fieldSelector =
"#username-field, #password-field, #remember-me, #remember-me + div";
document
.querySelectorAll(fieldSelector)
.forEach((el) => el.classList.add("d-none"));

const wrap = document.createElement("div");
wrap.innerHTML = html;
wrap.innerHTML = html || "";
wrap.querySelector("#mfa-cancel")?.addEventListener("click", () => {
wrap.remove();
rendered = false;
document
.querySelectorAll(fieldSelector)
.forEach((el) => el.classList.remove("d-none"));
});
const placeholder = document.querySelector(
[
"#password-field", // login
"#name-field", // new_password
].join(",")
);
const placeholder = document.querySelector("#password-field");
placeholder?.parentElement?.insertBefore(wrap, placeholder.nextSibling);
const firstInputElement = wrap.querySelector("input");
if (firstInputElement) {
firstInputElement.focus();
}

scripts.forEach((src) => {
(scripts || []).forEach((src) => {
if (document.querySelector(`script[src="${src}"]`)) {
return;
}
Expand Down
8 changes: 6 additions & 2 deletions plugins/MFA/config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
id: MFA
name: MFA
version: 1.0.3
version: 1.0.4

description: <__trans phrase="This plugin provides multi factor authentication feature for the Movable Type.">
author_link: http://www.movabletype.org/
Expand All @@ -14,13 +14,14 @@ l10n_lexicon:
Reset MFA settings: "多要素認証のリセット"
You have successfully Reset the MFA settings of selected user(s).: "選択したユーザーの多要素認証の設定をリセットしました。"
Failed to reset MFA settings of selected user(s).: "選択したユーザーの多要素認証の設定のリセットに失敗しました。"
Your password has been updated. Please sign in again.: "パスワードを更新しました。再度サインインしてください。"

callbacks:
MT::App::CMS::init_app: $MFA::MT::Plugin::MFA::init_app
MT::App::CMS::template_param.login: $MFA::MT::Plugin::MFA::template_param_login
MT::App::CMS::template_param.new_password: $MFA::MT::Plugin::MFA::template_param_login
MT::App::CMS::template_param.author_list_header: $MFA::MT::Plugin::MFA::template_param_author_list_header
MT::App::CMS::template_param.edit_author: $MFA::MT::Plugin::MFA::template_param_edit_author
MT::App::CMS::template_source.new_password: $MFA::MT::Plugin::MFA::template_source_new_password

applications:
cms:
Expand All @@ -33,6 +34,9 @@ applications:
handler: $MFA::MT::Plugin::MFA::page_actions
app_mode: JSON
mfa_reset: $MFA::MT::Plugin::MFA::reset_settings
mfa_new_password:
handler: $MFA::MT::Plugin::MFA::new_password
requires_login: 0
list_actions:
author:
mfa_reset:
Expand Down
27 changes: 26 additions & 1 deletion plugins/MFA/lib/MT/Plugin/MFA.pm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ sub template_param_login {
my ($cb, $app, $param, $tmpl) = @_;
$param->{plugin_mfa_version} = _plugin()->version;
_insert_after_by_name($tmpl, 'layout/chromeless.tmpl', 'login_footer.tmpl');
_insert_after_by_name($tmpl, 'logged_out', 'login_status_message.tmpl');
}

sub template_param_author_list_header {
Expand All @@ -38,6 +39,11 @@ sub template_param_edit_author {
_insert_after_by_name($tmpl, 'related_content', 'edit_author.tmpl');
}

sub template_source_new_password {
my ($cb, $app, $tmpl) = @_;
$$tmpl =~ s{\bvalue="new_pw"}{value="mfa_new_password"};
}

our $pre_check_credentials = 0;
sub login_form {
my $app = shift;
Expand Down Expand Up @@ -93,6 +99,22 @@ sub login_form {
});
}

our $disable_login = 0;
sub new_password {
my $app = shift;
require MT::CMS::Tools;
local $disable_login = 1;
my $res = MT::CMS::Tools::new_password($app);

if (ref $app eq 'MT::App::CMS' && $app->{redirect}) {
# password has been updated
$app->redirect($app->mt_uri(args => { mfa_password_updated => 1 }));
return;
}

return $res;
}

my $app_initialized = 0;
sub init_app {
return if $app_initialized;
Expand Down Expand Up @@ -130,6 +152,8 @@ sub init_app {
my $orig = shift;
my $self = shift;

return if $disable_login;

my @res = $self->$orig(@_);

return @res unless $self->isa('MT::App::CMS');
Expand Down Expand Up @@ -184,7 +208,8 @@ sub page_actions {
}) or return;

# TODO: Allow super users to also perform actions on other users.
if ($app->param('id') != $app->user->id) {
my $page_user_id = $app->param('id');
if ($page_user_id && $page_user_id != $app->user->id) {
return $app->json_result({ page_actions => [] });
}

Expand Down
101 changes: 101 additions & 0 deletions plugins/MFA/t/01-new-password.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use strict;
use warnings;

use FindBin;
use lib "$FindBin::Bin/../../../t/lib";

use Test::More;
use MT::Test::Env;

our $test_env;
BEGIN {
$test_env = MT::Test::Env->new;
$ENV{MT_CONFIG} = $test_env->config_file;
}

use MT::Test;
use MT::Test::Permission;
use MT::Test::App;
use MT::Util;
use MT::Util::Captcha;
use MT::Util::UniqueID;

$test_env->prepare_fixture('db');

my $password = 'password';
my $user = MT::Author->load(1);
$user->set_password($password);
$user->save or die $user->errstr;

my $app = MT::Test::App->new('MT::App::CMS');

sub _start_recover {
my $user = shift;
require MT::Util::Captcha;
my $salt = MT::Util::Captcha->_generate_code(8);
my $expires = time + (60 * 60);
my $token = MT::Util::perl_sha1_digest_hex($salt . $expires . MT->config->SecretToken);

$user->password_reset($salt);
$user->password_reset_expires($expires);
$user->save;
$token;
}

subtest '__mode=new_pw' => sub {
subtest '__mode should be replaced' => sub {
my $token = _start_recover($user);
$app->get_ok({
__mode => 'new_pw',
token => $token,
email => $user->email,
});
$app->content_like(qr/value="mfa_new_password"/);
};

subtest 'should not be replaced if token is invalid' => sub {
my $token = _start_recover($user);
$app->get_ok({
__mode => 'new_pw',
token => $token . '-invalid',
email => $user->email,
});
$app->content_unlike(qr/value="mfa_new_password"/);
};
};

subtest '__mode=mfa_new_password' => sub {
subtest 'redirect target should be replaced' => sub {
local $app->{no_redirect} = 1;
my $new_password = MT::Util::UniqueID->create_md5_id();
my $token = _start_recover($user);
$app->post_ok({
__mode => 'mfa_new_password',
token => $token,
email => $user->email,
username => $user->name,
password => $new_password,
password_again => $new_password,
});
my $location = $app->last_location;
ok $location->query_param('mfa_password_updated');
ok !$location->query_param('__mode');
};

subtest 'the result is the same as the original new_password if not redirected' => sub {
local $app->{no_redirect} = 1;
my $new_password = MT::Util::UniqueID->create_md5_id();
my $token = _start_recover($user);
$app->post_ok({
__mode => 'mfa_new_password',
token => $token,
email => $user->email,
username => $user->name,
password => $new_password,
password_again => $new_password . '-typo',
});
$app->content_like(qr/value="mfa_new_password"/);
};
};

done_testing();
15 changes: 15 additions & 0 deletions plugins/MFA/t/01-sign-in.t
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@ sub insert_failedlogin {
$failedlogin->save or die $failedlogin->errstr;
}

subtest 'sign in page' => sub {
my $message_re = qr/Your password has been updated. Please sign in again./;
subtest 'with mfa_password_updated=1' => sub {
$app->get_ok({
mfa_password_updated => 1,
});
$app->content_like($message_re);
};

subtest 'without parameters' => sub {
$app->get_ok();
$app->content_unlike($message_re);
};
};

subtest 'sign in' => sub {
subtest 'Should not affect to "sign in" function for users who have not configured MFA' => sub {
subtest 'valid password' => sub {
Expand Down
8 changes: 8 additions & 0 deletions plugins/MFA/tmpl/login_status_message.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<mt:If name="request.mfa_password_updated">
<mtapp:statusmsg
id="mfa_password_updated"
class="info"
can_close="0">
<__trans phrase="Your password has been updated. Please sign in again.">
</mtapp:statusmsg>
</mt:If>

0 comments on commit b7c41a7

Please sign in to comment.