mirror of
https://github.com/webmin/webmin.git
synced 2026-02-18 04:22:38 +00:00
Completed google authenticator support
This commit is contained in:
@@ -188,11 +188,9 @@ if (uc($ENV{'HTTPS'}) eq "ON" && $miniserv{'ca'}) {
|
||||
push(@links, "cert_form.cgi");
|
||||
push(@titles, $text{'index_cert'});
|
||||
}
|
||||
if ($miniserv{'twofactor_provider'}) {
|
||||
push(@icons, "images/twofactor.gif");
|
||||
push(@links, "twofactor_form.cgi");
|
||||
push(@titles, $text{'index_twofactor'});
|
||||
}
|
||||
push(@icons, "images/twofactor.gif");
|
||||
push(@links, "twofactor_form.cgi");
|
||||
push(@titles, $text{'index_twofactor'});
|
||||
if ($access{'rbacenable'}) {
|
||||
push(@icons, "images/rbac.gif");
|
||||
push(@links, "edit_rbac.cgi");
|
||||
|
||||
@@ -466,6 +466,7 @@ 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.
|
||||
twofactor_done=.. complete. Your ID with this provider is <tt>$1</tt>.
|
||||
twofactor_setup=Two-factor authentication has not been enabled on this system yet, but can be turned on using the <a href='$1'>Webmin Configuration</a> module.
|
||||
|
||||
__norefs=1
|
||||
|
||||
@@ -13,9 +13,12 @@ $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));
|
||||
$vfunc = "webmin::parse_twofactor_form_".
|
||||
$miniserv{'twofactor_provider'};
|
||||
if (defined(&$vfunc)) {
|
||||
$details = &$vfunc(\%in, $user);
|
||||
&error($details) if (!ref($details));
|
||||
}
|
||||
|
||||
&ui_print_header(undef, $text{'twofactor_title'}, "");
|
||||
($prov) = grep { $_->[0] eq $miniserv{'twofactor_provider'} }
|
||||
@@ -32,6 +35,12 @@ if ($in{'enable'}) {
|
||||
else {
|
||||
print &text('twofactor_done', $user->{'twofactor_id'}),"<p>\n";
|
||||
|
||||
# Print provider-specific message
|
||||
$mfunc = "webmin::message_twofactor_".$miniserv{'twofactor_provider'};
|
||||
if (defined(&$mfunc)) {
|
||||
print &$mfunc($user);
|
||||
}
|
||||
|
||||
# Save user
|
||||
$user->{'twofactor_provider'} = $miniserv{'twofactor_provider'};
|
||||
&modify_user($user->{'name'}, $user);
|
||||
|
||||
@@ -6,6 +6,12 @@ require './acl-lib.pl';
|
||||
&error_setup($text{'twofactor_err'});
|
||||
&get_miniserv_config(\%miniserv);
|
||||
|
||||
if (!$miniserv{'twofactor_provider'}) {
|
||||
&ui_print_endpage(&text('twofactor_setup',
|
||||
'../webmin/edit_twofactor.cgi'));
|
||||
return;
|
||||
}
|
||||
|
||||
# Get the user
|
||||
($user) = grep { $_->{'name'} eq $base_remote_user } &list_users();
|
||||
$user || &error($twxt{'twofactor_euser'});
|
||||
@@ -24,10 +30,12 @@ else {
|
||||
($prov) = grep { $_->[0] eq $miniserv{'twofactor_provider'} }
|
||||
&webmin::list_twofactor_providers();
|
||||
print &text('twofactor_desc', $prov->[1], $prov->[2]),"<p>\n";
|
||||
print &ui_table_start($text{'twofactor_header'}, undef, 2);
|
||||
$ffunc = "webmin::show_twofactor_form_".$miniserv{'twofactor_provider'};
|
||||
print &$ffunc($user);
|
||||
print &ui_table_end();
|
||||
if (defined(&$ffunc)) {
|
||||
print &ui_table_start($text{'twofactor_header'}, undef, 2);
|
||||
print &$ffunc($user);
|
||||
print &ui_table_end();
|
||||
}
|
||||
@buts = ( [ "enable", $text{'twofactor_enable'} ] );
|
||||
}
|
||||
print &ui_form_end(\@buts);
|
||||
|
||||
@@ -26,7 +26,11 @@ $msg = $text{'restart_done'}."<p>\n";
|
||||
if ($in{'twofactor_provider'}) {
|
||||
$msg .= &text('twofactor_enrolllink',
|
||||
"../acl/twofactor_form.cgi")."<p>\n";
|
||||
if ($prov->[2]) {
|
||||
$mfunc = "message_twofactor_apikey_".$in{'twofactor_provider'};
|
||||
if (defined(&$mfunc)) {
|
||||
$msg .= &$mfunc(\%miniserv)."<p>\n";
|
||||
}
|
||||
elsif ($prov->[2]) {
|
||||
$msg .= &text('twofactor_url', $prov->[1], $prov->[2])."<p>\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,5 +1047,11 @@ twofactor_eauthytoken=Authy token must be a number
|
||||
twofactor_eauthyotp=Authy token is invalid
|
||||
twofactor_enrolllink=You can now enroll for two-factor authentication in the <a href='$1'>Webmin Users</a> module.
|
||||
twofactor_url=To learn more about $1, see it's website at <a href='$2' target=_blank>$2</a>.
|
||||
twofactor_etoptmodule=The Perl module <tt>$1</tt> needed for two-factor authentication is not installed. Use the <a href='$2'>Perl Modules</a> page in Webmin to install it.
|
||||
twofactor_qrcode=Enter the secret code $1 in the Google Authenticator app, or scan the QR code below.
|
||||
twofactor_etoptid=Invalid TOPT base32-encoded secret
|
||||
twofactor_etotptoken=Google Authenticator token must be a number
|
||||
twofactor_etoptmodule2=Missing Perl module $1
|
||||
twofactor_etoptmatch=Incorrect OTP code
|
||||
|
||||
__norefs=1
|
||||
|
||||
@@ -2186,8 +2186,8 @@ return $rv;
|
||||
}
|
||||
|
||||
# validate_twofactor_apikey_authy(&in, &miniserv)
|
||||
# Validates inputs from show_twofactor_apikey_authy, and stores them. Returns undef
|
||||
# if OK, or an error message on failure
|
||||
# Validates inputs from show_twofactor_apikey_authy, and stores them. Returns
|
||||
# undef if OK, or an error message on failure
|
||||
sub validate_twofactor_apikey_authy
|
||||
{
|
||||
my ($in, $miniserv) = @_;
|
||||
@@ -2320,16 +2320,67 @@ else {
|
||||
}
|
||||
|
||||
# validate_twofactor_apikey_topt()
|
||||
# Checks that the needed Perl module for TOPT is installed
|
||||
# Checks that the needed Perl module for TOPT is installed.
|
||||
sub validate_twofactor_apikey_topt
|
||||
{
|
||||
# XXX
|
||||
my ($miniserv, $in) = @_;
|
||||
eval "use Authen::OATH";
|
||||
if ($@) {
|
||||
return &text('twofactor_etoptmodule', 'Authen::OATH',
|
||||
"../cpan/download.cgi?source=3&cpan=Authen::OATH&mode=2&".
|
||||
"return=/$module_name/&returndesc=".&urlize($text{'index_return'}))
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
# show_twofactor_form_topt()
|
||||
# XXX is this even needed?
|
||||
sub show_twofactor_form_topt
|
||||
# enroll_twofactor_topt(&in, &user)
|
||||
# Generate a secret for this user, based-32 encoded
|
||||
sub enroll_twofactor_topt
|
||||
{
|
||||
my ($in, $user) = @_;
|
||||
&seed_random();
|
||||
my $secret = "";
|
||||
while(length($secret) < 10) {
|
||||
$secret .= chr(rand()*256);
|
||||
}
|
||||
$user->{'twofactor_id'} = &encode_base32($secret);
|
||||
return undef;
|
||||
}
|
||||
|
||||
# message_twofactor_topt(&user)
|
||||
# Returns HTML to display after a user enrolls
|
||||
sub message_twofactor_topt
|
||||
{
|
||||
my ($user) = @_;
|
||||
my $url = "https://chart.googleapis.com/chart".
|
||||
"?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/".
|
||||
$user->{'name'}."%3Fsecret%3D".$user->{'twofactor_id'};
|
||||
my $rv;
|
||||
$rv .= &text('twofactor_qrcode', "<tt>$user->{'twofactor_id'}</tt>")."<p>\n";
|
||||
$rv .= "<img src='$url' border=0><p>\n";
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# validate_twofactor_totp(id, token, apikey)
|
||||
# Checks the validity of some token with google authenticator
|
||||
sub validate_twofactor_totp
|
||||
{
|
||||
my ($id, $token, $apikey) = @_;
|
||||
$id =~ /^[A-Z0-9=]+$/ || return $text{'twofactor_etoptid'};
|
||||
$token =~ /^\d+$/ || return $text{'twofactor_etotptoken'};
|
||||
eval "use Authen::OATH";
|
||||
if ($@) {
|
||||
return &text('twofactor_etoptmodule2', 'Authen::OATH');
|
||||
}
|
||||
my $secret = &decode_base32($id);
|
||||
my $oauth = Authen::OATH->new();
|
||||
my $now = time();
|
||||
foreach my $t ($now - 30, $now, $now + 30) {
|
||||
my $expected = $oauth->totp($secret, $t);
|
||||
return undef if ($expected eq $token);
|
||||
}
|
||||
return $text{'twofactor_etoptmatch'};
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
Reference in New Issue
Block a user