diff options
author | Matthew Somerville <matthew@mysociety.org> | 2019-10-30 15:16:33 +0000 |
---|---|---|
committer | Matthew Somerville <matthew@mysociety.org> | 2019-10-30 15:17:16 +0000 |
commit | 3d593bc68d65015a50f8f4b1a6d9f818d8678226 (patch) | |
tree | 1c8b035b8279dcf3c0fbeaddd5cd9a8ad14df12f | |
parent | 03390054664ca11ce1db178dff5065ce8f545925 (diff) |
If 2FA enforced, do it for an email login as well.
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Auth.pm | 31 | ||||
-rw-r--r-- | t/app/controller/auth.t | 34 | ||||
-rw-r--r-- | templates/web/base/auth/2fa/intro.html | 2 |
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> |