Completed google authenticator support

This commit is contained in:
Jamie Cameron
2013-09-29 22:03:40 -07:00
parent 53011ba46d
commit a7d026f2fc
7 changed files with 97 additions and 20 deletions

View File

@@ -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");

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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";
}
}

View File

@@ -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

View File

@@ -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;