aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2019-10-30 15:16:33 +0000
committerMatthew Somerville <matthew@mysociety.org>2019-10-30 15:17:16 +0000
commit3d593bc68d65015a50f8f4b1a6d9f818d8678226 (patch)
tree1c8b035b8279dcf3c0fbeaddd5cd9a8ad14df12f
parent03390054664ca11ce1db178dff5065ce8f545925 (diff)
If 2FA enforced, do it for an email login as well.
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm31
-rw-r--r--t/app/controller/auth.t34
-rw-r--r--templates/web/base/auth/2fa/intro.html2
3 files changed, 66 insertions, 1 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm
index ecca92bd3..041a8b76e 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -259,6 +259,7 @@ sub process_login : Private {
# People using 2FA need to supply a code
$c->forward( 'token_2fa', [ $user, $url_token ] ) if $user->has_2fa;
+ $c->forward( 'signup_2fa', [ $user ] ) if $c->cobrand->call_hook('must_have_2fa', $user);
if ($data->{old_user_id}) {
# Were logged in as old_user_id, want to switch to $user
@@ -320,6 +321,36 @@ sub token_2fa : Private {
$c->detach;
}
+sub signup_2fa : Private {
+ my ($self, $c, $user) = @_;
+
+ $c->stash->{form_action} = $c->req->path;
+ $c->stash->{template} = 'auth/2fa/intro.html';
+ my $action = $c->get_param('2fa_action') || '';
+
+ my $secret;
+ if ($action eq 'confirm') {
+ $secret = $c->get_param('secret32');
+ if ($c->check_2fa($secret)) {
+ $user->set_extra_metadata('2fa_secret' => $secret);
+ $user->update;
+ $c->stash->{stage} = 'success';
+ return;
+ } else {
+ $action = 'activate'; # Incorrect code, reshow
+ }
+ }
+
+ if ($action eq 'activate') {
+ my $auth = Auth::GoogleAuth->new;
+ $c->stash->{qr_code} = $auth->qr_code($secret, $user->email, 'FixMyStreet');
+ $c->stash->{secret32} = $auth->secret32;
+ $c->stash->{stage} = 'activate';
+ }
+
+ $c->detach;
+}
+
=head2 redirect_on_signin
Used after signing in to take the person back to where they were.
diff --git a/t/app/controller/auth.t b/t/app/controller/auth.t
index 652a4b293..cd72ab550 100644
--- a/t/app/controller/auth.t
+++ b/t/app/controller/auth.t
@@ -343,6 +343,40 @@ subtest "Test enforced two-factor authentication" => sub {
};
};
+subtest "Test enforced two-factor authentication, no password yet set" => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => 'dummy',
+ }, sub {
+ my $user = FixMyStreet::App->model('DB::User')->find( { email => $test_email } );
+ $user->unset_extra_metadata('2fa_secret');
+ $user->update;
+
+ $mech->clear_emails_ok;
+ $mech->get_ok('/auth');
+ $mech->submit_form_ok({
+ fields => { username => $test_email, password_register => $test_password },
+ button => 'sign_in_by_code',
+ }, "log in by email");
+
+ my $link = $mech->get_link_from_email;
+ $mech->get_ok($link);
+
+ $mech->content_contains('requires two-factor');
+ $mech->submit_form_ok({ with_fields => { '2fa_action' => 'activate' } }, "submit 2fa activation");
+ my ($token) = $mech->content =~ /name="secret32" value="([^"]*)">/;
+
+ my $auth = Auth::GoogleAuth->new({ secret32 => $token });
+ my $code = $auth->code;
+ $mech->submit_form_ok({ with_fields => { '2fa_code' => $code } }, "provide correct 2fa code" );
+
+ $user->discard_changes();
+ my $user_token = $user->get_extra_metadata('2fa_secret');
+ is $token, $user_token, '2FA secret set';
+
+ $mech->logged_in_ok;
+ };
+};
+
subtest "Check two-factor log in by email works" => sub {
use Auth::GoogleAuth;
my $auth = Auth::GoogleAuth->new;
diff --git a/templates/web/base/auth/2fa/intro.html b/templates/web/base/auth/2fa/intro.html
index 85e623e7f..7813507a3 100644
--- a/templates/web/base/auth/2fa/intro.html
+++ b/templates/web/base/auth/2fa/intro.html
@@ -5,7 +5,7 @@ INCLUDE 'header.html', title = loc('Two-factor authentication'), bodyclass = 'fu
<div class="confirmation-header confirmation-header--phone">
<h1>[% loc('Two-factor authentication') %]</h1>
- <form action="/auth" method="post">
+ <form action="/[% form_action OR 'auth' %]" method="post">
[% IF stage == 'success' %]
<p>[% loc('Thanks, you have successfully enabled two-factor authentication on your account.') %]</p>