diff --git a/acl/lang/en b/acl/lang/en index a0194c54a..a983c7e24 100644 --- a/acl/lang/en +++ b/acl/lang/en @@ -230,6 +230,8 @@ log_pass=Changed password restrictions log_unix=Changed unix user authentication log_sync=Changed unix user synchronization log_sql=Changed user and group database +log_twofactor=Enrolled user $1 with two-factor provider $2 +log_onefactor=Dis-enrolled user $1 for two-factor authentication gedit_ecannot=You are not allowed to edit groups gedit_title=Edit Webmin Group @@ -461,5 +463,8 @@ twofactor_already=Your Webmin login already has two-factor authentication enable twofactor_desc=This page allows you to enable two-factor authentication for your Webmin login using $1. Once active, an additional authentication token will be required when logging into Webmin. twofactor_enable=Enroll For Two-Factor Authentication twofactor_header=Two-factor authentication enrollment details +twofactor_enrolling=Enrolling for two-factor authentication with provider $1 .. +twofactor_failed=.. enrollment failed : $1 +twofactor_done=.. complete. Your ID with this provider is $1. __norefs=1 diff --git a/acl/log_parser.pl b/acl/log_parser.pl index ae2870e81..c34d335b8 100755 --- a/acl/log_parser.pl +++ b/acl/log_parser.pl @@ -51,6 +51,9 @@ elsif ($action eq 'cert') { elsif ($action eq 'switch') { return &text('log_switch', "".&html_escape($object).""); } +elsif ($action eq 'twofactor') { + return &text('log_twofactor', $object, $p->{'provider'}, $p->{'id'}); + } else { return $text{'log_'.$action}; } diff --git a/acl/save_twofactor.cgi b/acl/save_twofactor.cgi new file mode 100644 index 000000000..c8ddefe10 --- /dev/null +++ b/acl/save_twofactor.cgi @@ -0,0 +1,57 @@ +#!/usr/local/bin/perl +# Activate or de-activate twofactor + +require './acl-lib.pl'; +&foreign_require("webmin"); +&error_setup($text{'twofactor_err'}); +&get_miniserv_config(\%miniserv); +&ReadParse(); + +# Get the user +($user) = grep { $_->{'name'} eq $base_remote_user } &list_users(); +$user || &error($twxt{'twofactor_euser'}); + +if ($in{'enable'}) { + # Validate enrollment inputs + $vfunc = "webmin::parse_twofactor_form_".$miniserv{'twofactor_provider'}; + $details = &$vfunc(\%in, $user); + &error($details) if (!ref($details)); + + &ui_print_header(undef, $text{'twofactor_title'}, ""); + ($prov) = grep { $_->[0] eq $miniserv{'twofactor_provider'} } + &webmin::list_twofactor_providers(); + + # Register user + print &text('twofactor_enrolling', $prov->[1]),"
\n"; + $efunc = "webmin::enroll_twofactor_".$miniserv{'twofactor_provider'}; + $err = &$efunc($details, $user); + if ($err) { + # Failed! + print &text('twofactor_failed', $err),"

\n"; + } + else { + print &text('twofactor_done', $user->{'twofactor_id'}),"

\n"; + + # Save user + $user->{'twofactor_provider'} = $miniserv{'twofactor_provider'}; + &modify_user($user->{'name'}, $user); + &reload_miniserv(); + &webmin_log("twofactor", "user", $user->{'name'}, + { 'provider' => $user->{'twofactor_provider'}, + 'id' => $user->{'twofactor_id'} }); + } + + &ui_print_footer("", $text{'index_return'}); + } +elsif ($in{'disable'}) { + # Turn off for this user + $user->{'twofactor_provider'} = undef; + $user->{'twofactor_id'} = undef; + &modify_user($user->{'name'}, $user); + &reload_miniserv(); + &webmin_log("onefactor", "user", $user->{'name'}); + &redirect(""); + } +else { + &error($text{'twofactor_ebutton'}); + } diff --git a/webmin/change_twofactor.cgi b/webmin/change_twofactor.cgi index 55af8df45..2e1115937 100644 --- a/webmin/change_twofactor.cgi +++ b/webmin/change_twofactor.cgi @@ -22,6 +22,7 @@ if ($in{'twofactor_provider'}) { &get_miniserv_config(\%miniserv); $miniserv{'twofactor_provider'} = $in{'twofactor_provider'}; $miniserv{'twofactor_apikey'} = $in{'twofactor_apikey'}; +$miniserv{'twofactor_test'} = $in{'twofactor_test'}; &put_miniserv_config(\%miniserv); &unlock_file($ENV{'MINISERV_CONFIG'}); diff --git a/webmin/edit_twofactor.cgi b/webmin/edit_twofactor.cgi index 27f605bd5..bbe0ffd6f 100644 --- a/webmin/edit_twofactor.cgi +++ b/webmin/edit_twofactor.cgi @@ -21,6 +21,10 @@ print ui_table_row($text{'twofactor_provider'}, print ui_table_row($text{'twofactor_apikey'}, ui_textbox("twofactor_apikey", $miniserv{'twofactor_apikey'}, 40)); +# Test mode? +print ui_table_row($text{'twofactor_test'}, + ui_yesno_radio("twofactor_test", $miniserv{'twofactor_test'})); + print ui_table_end(); print ui_form_end([ [ "save", $text{'save'} ] ]); diff --git a/webmin/lang/en b/webmin/lang/en index 9544cb2b9..8381749b6 100644 --- a/webmin/lang/en +++ b/webmin/lang/en @@ -1026,6 +1026,7 @@ twofactor_header=Two-factor authentication sessions twofactor_provider=Authentication provider twofactor_none=None twofactor_apikey=Provider API key +twofactor_test=Use provider's test mode? twofactor_desc=Two-factor authentication allows Webmin users to enable use of an additional authentication device when logging in, such as a one-time passcode generator. Users must individually enroll with the selected authentication provider after it is enabled on this page. twofactor_err=Failed to save two-factor authentication twofactor_eprovider=Invalid provider! diff --git a/webmin/webmin-lib.pl b/webmin/webmin-lib.pl index d15cccba7..dfd1a6f45 100755 --- a/webmin/webmin-lib.pl +++ b/webmin/webmin-lib.pl @@ -2188,8 +2188,8 @@ return $rv; } # parse_twofactor_form_authy(&in, &user) -# Parses inputs from show_twofactor_form_authy, and returns a hash ref with enrollment -# details on success, or an error message on failure. +# Parses inputs from show_twofactor_form_authy, and returns a hash ref with +# enrollment details on success, or an error message on failure. sub parse_twofactor_form_authy { my ($in, $user) = @_; @@ -2203,11 +2203,26 @@ return { 'email' => $in->{'email'}, } # enroll_twofactor_authy(&details, &user) -# Attempts to enroll a user for Authy two-factor. Returns undef on success and sets -# twofactor_id in &user, or an error message on failure. +# Attempts to enroll a user for Authy two-factor. Returns undef on success and +# sets twofactor_id in &user, or an error message on failure. sub enroll_twofactor_authy { my ($details, $user) = @_; +my %miniserv; +&get_miniserv_config(\%miniserv); +my $host = $miniserv{'twofactor_test'} ? "sandbox-api.authy.com" : "api.authy.com"; +my $port = $miniserv{'twofactor_test'} ? 80 : 443; +my $page = "/protected/xml/users/new?api_key=".$miniserv{'twofactor_apikey'}; +my $ssl = $miniserv{'twofactor_test'} ? 0 : 1; +my $content = "user[email]=".&urlize($details->{'email'})."&". + "user[country_code]=".&urlize($details->{'country'})."&". + "user[cellphone]=".&urlize($details->{'phone'}); +my ($out, $err); +&http_post($host, $port, $page, $content, \$out, \$err, undef, $ssl, undef, + undef, 60, 0, 1); +return $err if ($err); +print STDERR $out; +return undef; } 1;