Fix to use one-time Usermin login URLs for switches
ⓘ Replace the legacy Usermin switch cookie/restart flow with a short-lived `session_login.cgi` handoff, while keeping the old API as a compatibility wrapper. https://forum.virtualmin.com/t/usermin-2-550-login-from-the-virtualmin-edit-users-page-stopped-working/137491/37?u=ilia
This commit is contained in:
@@ -474,7 +474,7 @@ else {
|
||||
&foreign_require("usermin", "usermin-lib.pl");
|
||||
local %uminiserv;
|
||||
&usermin::get_usermin_miniserv_config(\%uminiserv);
|
||||
if ($uminiserv{'session'}) {
|
||||
if (&usermin::can_create_usermin_login_url(\%uminiserv)) {
|
||||
push(@buts, [ "switch", $text{'uedit_swit'} ]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,7 +624,7 @@ if ($n ne "") {
|
||||
&foreign_require("usermin", "usermin-lib.pl");
|
||||
local %uminiserv;
|
||||
&usermin::get_usermin_miniserv_config(\%uminiserv);
|
||||
if ($uminiserv{'session'}) {
|
||||
if (&usermin::can_create_usermin_login_url(\%uminiserv)) {
|
||||
push(@buts, [ "switch", $text{'uedit_swit'}, undef, 0,
|
||||
"onClick='form.target=\"_blank\"'" ]);
|
||||
}
|
||||
|
||||
@@ -433,6 +433,8 @@ clone_ecopy=failed to copy config : $1
|
||||
clone_desc=Clone of $1
|
||||
|
||||
sessions_title=Current Login Sessions
|
||||
sessions_ecannot=You are not allowed to manage Usermin login sessions
|
||||
switch_esession=Failed to create a Usermin login session
|
||||
sessions_desc=Current Usermin session logins are listed below. To cancel an existing session and force the user to login again, click on its session ID.
|
||||
sessions_id=Session ID
|
||||
sessions_user=Unix user
|
||||
|
||||
+2
-3
@@ -3,10 +3,9 @@
|
||||
|
||||
require './usermin-lib.pl';
|
||||
&ReadParse();
|
||||
$access{'sessions'} || &error($text{'switch_euser'});
|
||||
$access{'sessions'} || &error($text{'sessions_ecannot'});
|
||||
|
||||
($cookie, $url) = &switch_to_usermin_user($in{'user'});
|
||||
print "Set-Cookie: $cookie\n";
|
||||
$url = &create_usermin_login_url($in{'user'});
|
||||
&redirect($url);
|
||||
&webmin_log("switch", undef, $in{'user'});
|
||||
|
||||
|
||||
+75
-28
@@ -930,47 +930,84 @@ else {
|
||||
return $mode;
|
||||
}
|
||||
|
||||
=head2 switch_to_usermin_user(username)
|
||||
=head2 can_create_usermin_login_url(&miniserv)
|
||||
|
||||
Returns a set-cookie header and redirect URL for auto-logging into Usermin
|
||||
as some user.
|
||||
Returns 1 if Usermin can accept a one-time login URL.
|
||||
|
||||
=cut
|
||||
sub switch_to_usermin_user
|
||||
sub can_create_usermin_login_url
|
||||
{
|
||||
my ($user) = @_;
|
||||
my ($miniserv) = @_;
|
||||
return $miniserv->{'session'} &&
|
||||
defined(&acl::open_session_db) &&
|
||||
defined(&acl::generate_random_session_id) &&
|
||||
defined(&reload_usermin_miniserv);
|
||||
}
|
||||
|
||||
# Stop Usermin first, so that the DBM can be safely written
|
||||
=head2 create_usermin_login_url(username, [lifetime])
|
||||
|
||||
Creates a one-time URL that logs into Usermin as some user.
|
||||
|
||||
=cut
|
||||
sub create_usermin_login_url
|
||||
{
|
||||
my ($user, $lifetime) = @_;
|
||||
my %miniserv;
|
||||
&get_usermin_miniserv_config(\%miniserv);
|
||||
my $stopped;
|
||||
if (&check_pid_file($miniserv{'pidfile'})) {
|
||||
&stop_usermin();
|
||||
$stopped = 1;
|
||||
&can_create_usermin_login_url(\%miniserv) ||
|
||||
&error($text{'switch_esession'});
|
||||
&check_pid_file($miniserv{'pidfile'}) ||
|
||||
&error($text{'switch_esession'});
|
||||
$lifetime ||= 5*60;
|
||||
my $sid = &create_usermin_login_session(\%miniserv, "-".$user,
|
||||
$lifetime);
|
||||
$sid || &error($text{'switch_esession'});
|
||||
|
||||
# Make sure the running Usermin process re-opens the session DBM, without
|
||||
# stopping the service or racing its PID file re-creation.
|
||||
&reload_usermin_miniserv();
|
||||
my $url = &get_usermin_login_base_url(\%miniserv);
|
||||
$url =~ s/\/+$//;
|
||||
return $url."/session_login.cgi?session=".&urlize($sid);
|
||||
}
|
||||
|
||||
# Generate a session ID and set it in the DB
|
||||
&acl::open_session_db(\%miniserv);
|
||||
&seed_random();
|
||||
=head2 create_usermin_login_session(&miniserv, username, lifetime)
|
||||
|
||||
Creates a one-time Usermin session token for the current browser.
|
||||
|
||||
=cut
|
||||
sub create_usermin_login_session
|
||||
{
|
||||
my ($miniserv, $user, $lifetime) = @_;
|
||||
return if (&is_readonly_mode());
|
||||
my $sid = &acl::generate_random_session_id();
|
||||
return if (!$sid);
|
||||
my $ip = $ENV{'REMOTE_ADDR'} || "127.0.0.1";
|
||||
my $now = time();
|
||||
my $sid = int(rand()*$now);
|
||||
$acl::sessiondb{$sid} = "$user $now $ENV{'REMOTE_ADDR'}";
|
||||
&acl::open_session_db($miniserv);
|
||||
$acl::sessiondb{$sid} = "$user $now $ip".($lifetime ? " ".$lifetime : "");
|
||||
dbmclose(%acl::sessiondb);
|
||||
if ($stopped) {
|
||||
&start_usermin();
|
||||
return $sid;
|
||||
}
|
||||
&reload_usermin_miniserv();
|
||||
|
||||
=head2 get_usermin_login_base_url(&miniserv)
|
||||
|
||||
Returns the base URL to use for browser handoff to Usermin.
|
||||
|
||||
=cut
|
||||
sub get_usermin_login_base_url
|
||||
{
|
||||
my ($miniserv) = @_;
|
||||
return $miniserv->{'redirect_url'} if ($miniserv->{'redirect_url'});
|
||||
|
||||
eval "use Net::SSLeay";
|
||||
if ($@) {
|
||||
$miniserv{'ssl'} = 0;
|
||||
$miniserv->{'ssl'} = 0;
|
||||
}
|
||||
my $ssl = $miniserv{'ssl'} || $miniserv{'inetd_ssl'};
|
||||
my $sec = $ssl ? "; secure" : "";
|
||||
my $sidname = $miniserv{'sidname'} || 'sid';
|
||||
my $cookie = "$sidname=$sid; path=/$sec";
|
||||
my $ssl = $miniserv->{'ssl'} || $miniserv->{'inetd_ssl'};
|
||||
|
||||
# Work out redirect host
|
||||
my @sockets = &webmin::get_miniserv_sockets(\%miniserv);
|
||||
my @sockets = &webmin::get_miniserv_sockets($miniserv);
|
||||
my ($host, $port, $url);
|
||||
my %uconfig;
|
||||
&get_usermin_config(\%uconfig);
|
||||
@@ -990,11 +1027,21 @@ else {
|
||||
$host =~ s/:.*//;
|
||||
}
|
||||
}
|
||||
$port ||= $uconfig{'port'} || $miniserv{'port'};
|
||||
$port ||= $uconfig{'port'} || $miniserv->{'port'};
|
||||
$url = ($ssl ? "https://" : "http://").$host.":".$port."/";
|
||||
$url = $miniserv{'redirect_url'}
|
||||
if ($miniserv{'redirect_url'});
|
||||
return ($cookie, $url);
|
||||
return $url;
|
||||
}
|
||||
|
||||
=head2 switch_to_usermin_user(username)
|
||||
|
||||
Returns a redirect URL for auto-logging into Usermin as some user.
|
||||
|
||||
=cut
|
||||
sub switch_to_usermin_user
|
||||
{
|
||||
my ($user) = @_;
|
||||
my $url = &create_usermin_login_url($user);
|
||||
return wantarray ? ("", $url) : $url;
|
||||
}
|
||||
|
||||
=head2 get_usermin_email_url([module], [cgi], [force-default], [force-host])
|
||||
|
||||
Reference in New Issue
Block a user