aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/Catalyst/Authentication/Credential/2FA.pm
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2019-10-24 10:40:49 +0100
committerMatthew Somerville <matthew@mysociety.org>2019-10-30 15:16:02 +0000
commit5a3e4c05be9e8eb931fccbcf6499abcc1da8d903 (patch)
tree3d6f4538275c5c9b0fa6b5c77dad870eeb3311bf /perllib/Catalyst/Authentication/Credential/2FA.pm
parente8adf97e7f01efdaab2f0ab3181268d07640c3f4 (diff)
Allow enforcement of 2FA for staff users.
Diffstat (limited to 'perllib/Catalyst/Authentication/Credential/2FA.pm')
-rw-r--r--perllib/Catalyst/Authentication/Credential/2FA.pm47
1 files changed, 45 insertions, 2 deletions
diff --git a/perllib/Catalyst/Authentication/Credential/2FA.pm b/perllib/Catalyst/Authentication/Credential/2FA.pm
index 9f22fed11..8b6771037 100644
--- a/perllib/Catalyst/Authentication/Credential/2FA.pm
+++ b/perllib/Catalyst/Authentication/Credential/2FA.pm
@@ -21,11 +21,54 @@ sub authenticate {
my $user_obj = $realm->find_user($userfindauthinfo, $c);
if (ref($user_obj)) {
- # We don't care unless user has a 2FA secret
- return $user_obj unless $user_obj->get_extra_metadata('2fa_secret');
+
+ # We don't care unless user has a 2FA secret, or the cobrand mandates it
+ return $user_obj unless $user_obj->has_2fa || $c->cobrand->call_hook('must_have_2fa', $user_obj);
$c->stash->{token} = $c->get_param('token');
+ if (!$user_obj->has_2fa) {
+ $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_obj->set_extra_metadata('2fa_secret' => $secret);
+ $user_obj->update;
+ if ($c->stash->{token}) {
+ my $token = $c->forward('/tokens/load_auth_token', [ $c->stash->{token}, '2fa' ]);
+ # Will contain a detach_to and report/update data
+ $c->stash($token->data);
+ } else {
+ $c->stash->{stage} = 'success';
+ $c->stash->{detach_to} = '/auth/two_factor_setup_success';
+ }
+ return $user_obj;
+ } else {
+ $action = 'activate'; # Incorrect code, reshow
+ }
+ }
+
+ if ($action eq 'activate') {
+ my $auth = Auth::GoogleAuth->new;
+ $c->stash->{qr_code} = $auth->qr_code($secret, $user_obj->email, 'FixMyStreet');
+ $c->stash->{secret32} = $auth->secret32;
+ $c->stash->{stage} = 'activate';
+ }
+
+ if ($c->stash->{tfa_data}) {
+ my $token = $c->model("DB::Token")->create( {
+ scope => '2fa',
+ data => $c->stash->{tfa_data},
+ });
+ $c->stash->{token} = $token->token;
+ }
+
+ $c->detach;
+ }
+
if ($c->check_2fa($user_obj->has_2fa)) {
if ($c->stash->{token}) {
my $token = $c->forward('/tokens/load_auth_token', [ $c->stash->{token}, '2fa' ]);