feat: groupModify: add --idle-lock-timeout and --idle-kill-timeout for group-specific timeouts

This commit is contained in:
Stéphane Lesimple 2022-04-05 12:25:17 +00:00 committed by Stéphane Lesimple
parent 6fb528ccf1
commit 46a01a546a
8 changed files with 345 additions and 45 deletions

View file

@ -41,7 +41,8 @@ if echo "$DISTRO_LIKE" | grep -q -w debian; then
if [ "$(uname -m)" = armv7l ]; then
wanted_list="$wanted_list wget"
fi
[ "$opt_dev" = 1 ] && wanted_list="$wanted_list libperl-critic-perl perltidy shellcheck openssl"
[ "$opt_dev" = 1 ] && wanted_list="$wanted_list libperl-critic-perl libtest-deep-perl perltidy shellcheck openssl wget"
if { [ "$LINUX_DISTRO" = debian ] && [ "$DISTRO_VERSION_MAJOR" -lt 9 ]; } ||
{ [ "$LINUX_DISTRO" = ubuntu ] && [ "$DISTRO_VERSION_MAJOR" -le 16 ]; }; then
wanted_list="$wanted_list openssh-blacklist openssh-blacklist-extra"
@ -70,7 +71,7 @@ elif echo "$DISTRO_LIKE" | grep -q -w rhel; then
expect openssh-server netcat bash perl-CGI perl-Test-Simple passwd \
cracklib-dicts perl-Time-Piece perl-Time-HiRes diffutils \
perl-Sys-Syslog pamtester google-authenticator qrencode-libs \
perl-LWP-Protocol-https findutils tar"
perl-LWP-Protocol-https perl-Test-Deep findutils tar"
if [ "$DISTRO_VERSION_MAJOR" = 7 ]; then
wanted_list="$wanted_list fortune-mod coreutils util-linux"
else
@ -78,6 +79,7 @@ elif echo "$DISTRO_LIKE" | grep -q -w rhel; then
fi
[ "$opt_syslogng" = 1 ] && wanted_list="$wanted_list syslog-ng"
if [ "$opt_install" = 1 ]; then
if [ "$DISTRO_VERSION_MAJOR" = 8 ]; then
# in December 2020, they added "-Linux" to their repo name, so trying both combinations
@ -115,7 +117,7 @@ elif echo "$DISTRO_LIKE" | grep -q -w suse; then
perl-Net-Server cryptsetup mosh expect openssh \
coreutils netcat-openbsd bash perl-CGI iputils \
perl-Time-HiRes perl-Unix-Syslog hostname perl-LWP-Protocol-https \
google-authenticator-libpam tar"
google-authenticator-libpam tar perl-Test-Deep"
[ "$opt_syslogng" = 1 ] && wanted_list="$wanted_list syslog-ng"
if [ "$opt_install" = 1 ]; then
@ -129,7 +131,8 @@ elif echo "$DISTRO_LIKE" | grep -q -w suse; then
elif [ "$OS_FAMILY" = FreeBSD ]; then
wanted_list="base64 coreutils rsync bash sudo pamtester p5-JSON p5-JSON-XS gnupg \
p5-common-sense p5-DateTime p5-Net-IP p5-DBD-SQLite p5-Net-Netmask lsof \
p5-Term-ReadKey expect fping p5-Net-Server p5-CGI p5-LWP-Protocol-https"
p5-Term-ReadKey expect fping p5-Net-Server p5-CGI p5-LWP-Protocol-https \
p5-Test-Deep"
install_cmd="pkg add"
installed=""
for i in $wanted_list

View file

@ -18,13 +18,15 @@ use OVH::Result;
# Fetch command options
my $fnret;
my ($result, @optwarns);
my ($group, $mfaRequired, $ttl);
my ($group, $mfaRequired, $ttl, $idleLockTimeout, $idleKillTimeout);
eval {
local $SIG{__WARN__} = sub { push @optwarns, shift };
$result = GetOptions(
"group=s" => sub { $group //= $_[1] },
"mfa-required=s" => \$mfaRequired,
"guest-ttl-limit=i" => \$ttl,
"group=s" => sub { $group //= $_[1] },
"mfa-required=s" => \$mfaRequired,
"guest-ttl-limit=i" => \$ttl,
"idle-lock-timeout=i" => \$idleLockTimeout,
"idle-kill-timeout=i" => \$idleKillTimeout,
);
};
if ($@) { die $@ }
@ -40,8 +42,9 @@ if (!$group) {
HEXIT('ERR_MISSING_PARAMETER', msg => "Missing argument 'group'");
}
if (!$mfaRequired && !defined $ttl) {
HEXIT('ERR_MISSING_PARAMETER', msg => "Missing argument 'mfa-required' or 'guest-ttl-limit'");
if (!$mfaRequired && !defined $ttl && !defined $idleLockTimeout && !defined $idleKillTimeout) {
HEXIT('ERR_MISSING_PARAMETER',
msg => "Missing argument 'mfa-required', 'guest-ttl-limit', 'idle-lock-timeout' or 'idle-kill-timeout'");
}
#<HEADER
@ -88,6 +91,69 @@ if (defined $mfaRequired) {
}
}
my %idleTimeout = (
lock => {
name => "idle lock timeout",
key => \%{OVH::Bastion::OPT_GROUP_IDLE_LOCK_TIMEOUT()},
value => $idleLockTimeout,
},
kill => {
name => "idle kill timeout",
key => \%{OVH::Bastion::OPT_GROUP_IDLE_KILL_TIMEOUT()},
value => $idleKillTimeout,
},
);
foreach my $item (keys %idleTimeout) {
next if !defined $idleTimeout{$item}{'value'};
osh_info "Modifying " . $idleTimeout{$item}{'name'} . " policy of group...";
if ($idleTimeout{$item}{'value'} >= 0) {
$fnret = OVH::Bastion::group_config(
group => $group,
%{$idleTimeout{$item}{'key'}}, value => $idleTimeout{$item}{'value'}
);
if ($fnret) {
if ($idleTimeout{$item}{'value'} == 0) {
osh_info "... done, this group's " . $idleTimeout{$item}{'name'} . " policy is now set to: disabled";
}
else {
osh_info "... done, this group is now configured to use a "
. $idleTimeout{$item}{'name'}
. " policy of "
. OVH::Bastion::duration2human(seconds => $idleTimeout{$item}{'value'})->value->{'human'};
}
}
else {
osh_warn "... error while setting the group-specific "
. $idleTimeout{$item}{'name'}
. " policy ("
. $fnret->msg . ")";
warn_syslog "Error setting the group-specific "
. $idleTimeout{$item}{'name'}
. " policy of $group ("
. $fnret->msg . ")";
}
}
else {
$fnret = OVH::Bastion::group_config(group => $group, %{$idleTimeout{$item}{'key'}}, delete => 1);
if ($fnret) {
osh_info "... done, this group will now use the global " . $idleTimeout{$item}{'name'} . " policy";
}
else {
osh_warn "... error while removing the group-specific "
. $idleTimeout{$item}{'name'}
. " policy ("
. $fnret->msg . ")";
warn_syslog "Error removing the group-specific "
. $idleTimeout{$item}{'name'}
. " policy of $group ("
. $fnret->msg . ")";
}
}
$result{$idleTimeout{$item}{'key'}} = $fnret;
}
if (defined $ttl) {
osh_info "Modifying guest TTL limit policy of group...";
if ($ttl > 0) {

View file

@ -12,19 +12,33 @@ my $remainingOptions = OVH::Bastion::Plugin::begin(
argv => \@ARGV,
header => "modify the configuration of a group",
options => {
"group=s" => \my $group,
"mfa-required=s" => \my $mfaRequired,
"guest-ttl-limit=s" => \my $ttl,
"group=s" => \my $group,
"mfa-required=s" => \my $mfaRequired,
"idle-lock-timeout=s" => \my $idleLockTimeout,
"idle-kill-timeout=s" => \my $idleKillTimeout,
"guest-ttl-limit=s" => \my $ttl,
},
helptext => <<'EOF',
Modify the configuration of a group
Usage: --osh SCRIPT_NAME --group GROUP [--mfa-required password|totp|any|none] [--guest-ttl-limit DURATION]
--group GROUP Name of the group to modify
--mfa-required password|totp|any|none Enforce UNIX password requirement, or TOTP requirement, or any MFA requirement, when connecting to a server of the group
--guest-ttl-limit DURATION This group will enforce TTL setting, on guest access creation, to be set, and not to a higher value than DURATION,
set to zero to allow guest accesses creation without any TTL set (default)
--group GROUP Name of the group to modify
--mfa-required password|totp|any|none Enforce UNIX password requirement, or TOTP requirement, or any MFA requirement, when connecting to a server of the group
--idle-lock-timeout DURATION|0|-1 Overrides the global setting (`idleLockTimeout`), to the specified duration. If set to 0, disables `idleLockTimeout` for
this group. If set to -1, remove this group override and use the global setting instead.
--idle-kill-timeout DURATION|0|-1 Overrides the global setting (`idleKillTimeout`), to the specified duration. If set to 0, disables `idleKillTimeout` for
this group. If set to -1, remove this group override and use the global setting instead.
--guest-ttl-limit DURATION This group will enforce TTL setting, on guest access creation, to be set, and not to a higher value than DURATION,
set to zero to allow guest accesses creation without any TTL set (default)
Note that `--idle-lock-timeout` and `--idle-kill-timeout` will NOT be applied for catch-all groups (having 0.0.0.0/0 in their server list).
If a server is in exactly one group an account is a member of, then its values of `--idle-lock-timeout` and `--idle-kill-timeout`, if set,
will prevail over the global setting. The global setting can be seen with `--osh info`.
Otherwise, the most restrictive setting (i.e. the one with the lower strictly positive duration) between
all the considered groups and the global setting, will be used.
EOF
);
@ -34,14 +48,22 @@ if (!$group) {
help();
osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'group'";
}
if (!$mfaRequired && !defined $ttl) {
if (!$mfaRequired && !defined $ttl && !defined $idleLockTimeout && !defined $idleKillTimeout) {
help();
osh_exit 'ERR_MISSING_PARAMETER', "Nothing to modify";
}
if (defined $ttl) {
$fnret = OVH::Bastion::is_valid_ttl(ttl => $ttl);
$fnret or osh_exit $fnret;
$ttl = $fnret->value->{'seconds'};
foreach my $item (\$ttl, \$idleLockTimeout, \$idleKillTimeout) {
if (defined $$item && $$item != -1) {
$fnret = OVH::Bastion::is_valid_ttl(ttl => $$item);
$fnret or osh_exit $fnret;
$$item = $fnret->value->{'seconds'};
}
}
# ttl doesn't allow -1 as a valid value, check that
if ($ttl == -1) {
osh_exit 'ERR_INVALID_PARAMETER',
"Invalid TTL (-1), expected an amount of seconds, or a duration string such as '2d8h15m'";
}
$fnret = OVH::Bastion::is_valid_group_and_existing(group => $group, groupType => 'key');
@ -66,5 +88,7 @@ push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-groupModify';
push @command, '--group', $group;
push @command, '--mfa-required', $mfaRequired if $mfaRequired;
push @command, '--guest-ttl-limit', $ttl if defined $ttl;
push @command, '--idle-lock-timeout', $idleLockTimeout if defined $idleLockTimeout;
push @command, '--idle-kill-timeout', $idleKillTimeout if defined $idleKillTimeout;
osh_exit OVH::Bastion::helper(cmd => \@command);

View file

@ -176,11 +176,25 @@ if ( OVH::Bastion::is_group_owner(group => $shortGroup, account => $self, supe
}
$fnret = OVH::Bastion::group_config(group => $group, key => 'guest_ttl_limit');
if ($fnret) {
if ($fnret && defined $fnret->value && $fnret->value =~ /^\d+$/) {
osh_warn "Guest TTL enforced: guest accesses must have a TTL with a maximum duration of "
. OVH::Bastion::duration2human(seconds => $fnret->value)->value->{'duration'};
$result_hash->{'guest_ttl_limit'} = $fnret->value;
}
$fnret = OVH::Bastion::group_config(group => $group, %{OVH::Bastion::OPT_GROUP_IDLE_KILL_TIMEOUT()});
if ($fnret && defined $fnret->value && $fnret->value =~ /^-?\d+$/) {
osh_warn "Specific idle kill timeout: idle sessions on servers of this group will be cut after "
. OVH::Bastion::duration2human(seconds => $fnret->value)->value->{'duration'};
$result_hash->{'idle_kill_timeout'} = $fnret->value;
}
$fnret = OVH::Bastion::group_config(group => $group, => %{OVH::Bastion::OPT_GROUP_IDLE_LOCK_TIMEOUT()});
if ($fnret && defined $fnret->value && $fnret->value =~ /^-?\d+$/) {
osh_warn "Specific idle lock timeout: idle sessions on servers of this group will be locked after "
. OVH::Bastion::duration2human(seconds => $fnret->value)->value->{'duration'};
$result_hash->{'idle_lock_timeout'} = $fnret->value;
}
}
else {
osh_info "You should ask him/her/them if you think you need access for your work tasks.";

View file

@ -1172,7 +1172,7 @@ if ($osh_debug) {
}
# build ttyrec command that'll prefix the real command
my $ttyrec_fnret = OVH::Bastion::build_ttyrec_cmdline(
my $ttyrec_fnret = OVH::Bastion::build_ttyrec_cmdline_part1of2(
ip => $ip,
port => $port,
user => $user,
@ -1310,6 +1310,60 @@ else {
push @command, '/usr/bin/ssh', $ip, '-l', $user, '-p', $port;
# before listing the accesses and the keys they use, first compute the correct
# idle-kill-timeout and idle-lock-timeout value, as these can be overriden for group accesses,
# see the help of groupModify command for details on the algorithm's logic, it is also commented below
# First, we init the vars with the global setting.
my %idleTimeout = (
kill => OVH::Bastion::config("idleKillTimeout")->value,
lock => OVH::Bastion::config("idleLockTimeout")->value,
);
# Then, gather all the timeouts overrides that may be defined for the matching groups
my %idleTimeoutsOverride = (kill => [], lock => []);
foreach my $access (@accessList) {
next if ($access->{'type'} !~ /^group/);
push @{$idleTimeoutsOverride{'kill'}}, $access->{'idleKillTimeout'}
if (defined $access->{'idleKillTimeout'} && $access->{'size'} != 2**32);
push @{$idleTimeoutsOverride{'lock'}}, $access->{'idleLockTimeout'}
if (defined $access->{'idleLockTimeout'} && $access->{'size'} != 2**32);
}
# Now, decide what to apply for each timeout setting
foreach my $timeout (qw{ kill lock }) {
if (@{$idleTimeoutsOverride{$timeout}} == 0) {
# zero override, we'll use the global setting,
# $idleTimeout{$timeout} is already inited to the global setting
osh_debug("idle_timeout: no override for $timeout, using global setting");
}
elsif (@{$idleTimeoutsOverride{$timeout}} == 1) {
# exactly one match, use it
$idleTimeout{$timeout} = $idleTimeoutsOverride{$timeout}[0];
osh_debug("idle_timeout: exactly one override for $timeout, using it");
}
else {
osh_debug("idle_timeout: more than one override for $timeout, using the most restrictive one");
# more than one match, so we add the global setting to the pile
push @{$idleTimeoutsOverride{$timeout}}, $idleTimeout{$timeout};
# and choose the most restrictive one (lowest positive integer)
$idleTimeout{$timeout} = (sort { $a <=> $b } grep { $_ > 0 } @{$idleTimeoutsOverride{$timeout}})[0];
}
osh_debug("idle_timeout: finally using " . $idleTimeout{$timeout} . " for $timeout");
}
# adjust the ttyrec cmdline with these parameters
$ttyrec_fnret = OVH::Bastion::build_ttyrec_cmdline_part2of2(
input => $ttyrec_fnret->value,
idleLockTimeout => $idleTimeout{'lock'},
idleKillTimeout => $idleTimeout{'kill'}
);
main_exit(OVH::Bastion::EXIT_TTYREC_CMDLINE_FAILED, "ttyrec_failed", $ttyrec_fnret->msg) if !$ttyrec_fnret;
@ttyrec = @{$ttyrec_fnret->value->{'cmd'}};
my @keysToTry;
print " will try the following accesses you have: \n" unless $quiet;
foreach my $access (@accessList) {

View file

@ -119,6 +119,9 @@ use constant {
OPT_ACCOUNT_OSH_ONLY => 'osh_only',
OPT_ACCOUNT_MAX_INACTIVE_DAYS => {key => 'max_inactive_days', public => 1},
OPT_GROUP_IDLE_LOCK_TIMEOUT => {key => 'idle_lock_timeout'},
OPT_GROUP_IDLE_KILL_TIMEOUT => {key => 'idle_kill_timeout'},
};
###########
@ -991,6 +994,19 @@ sub get_passfile {
sub build_ttyrec_cmdline {
my %params = @_;
my $fnret = build_ttyrec_cmdline_part1of2(%params);
$fnret or return $fnret;
# for this simple version, use global timeout values
return build_ttyrec_cmdline_part2of2(
input => $fnret->value,
idleLockTimeout => OVH::Bastion::config("idleLockTimeout")->value,
idleKillTimeout => OVH::Bastion::config("idleKillTimeout")->value
);
}
sub build_ttyrec_cmdline_part1of2 {
my %params = @_;
if (!$params{'home'}) {
return R('ERR_MISSING_PARAMETER', msg => "Missing home parameter");
@ -1041,11 +1057,6 @@ sub build_ttyrec_cmdline {
}
# forge ttyrec command
my $idleKillTimeout = OVH::Bastion::config('idleKillTimeout')->value;
my $idleLockTimeout = OVH::Bastion::config('idleLockTimeout')->value;
my $warnBeforeLockSeconds = OVH::Bastion::config('warnBeforeLockSeconds')->value;
my $warnBeforeKillSeconds = OVH::Bastion::config('warnBeforeKillSeconds')->value;
my @ttyrec = ('ttyrec', '-f', $saveFile, '-F', $saveFileFormat);
push @ttyrec, '-v' if $params{'debug'};
push @ttyrec, '-T', 'always' if $params{'tty'};
@ -1060,19 +1071,45 @@ sub build_ttyrec_cmdline {
osh_debug("Account is immune to idle, not adding ttyrec commandline parameters");
}
else {
push @ttyrec, '-k', $idleKillTimeout if $idleKillTimeout;
push @ttyrec, '-t', $idleLockTimeout if $idleLockTimeout;
push @ttyrec, '-s', "To unlock, use '--osh unlock' from another console" if $idleLockTimeout;
my $warnBeforeLockSeconds = OVH::Bastion::config('warnBeforeLockSeconds')->value;
my $warnBeforeKillSeconds = OVH::Bastion::config('warnBeforeKillSeconds')->value;
push @ttyrec, '--warn-before-lock', $warnBeforeLockSeconds if $warnBeforeLockSeconds;
push @ttyrec, '--warn-before-kill', $warnBeforeKillSeconds if $warnBeforeKillSeconds;
}
my $ttyrecAdditionalParameters = OVH::Bastion::config('ttyrecAdditionalParameters')->value;
push @ttyrec, @$ttyrecAdditionalParameters if @$ttyrecAdditionalParameters;
return R('OK', value => {saveFile => $saveFile, cmd => \@ttyrec});
}
# call this after build_ttyrec_cmdline_part1of2, don't forget to
# pass part1of2's value output to part2of2's 'input' parameter
sub build_ttyrec_cmdline_part2of2 {
my %params = @_;
my $input = $params{'input'};
if (!$input) {
return R('ERR_MISSING_PARAMETER', msg => "Missing 'input' parameter in build_ttyrec_cmdline_part2of2");
}
if (!$input->{'cmd'}) {
return R('ERR_MISSING_PARAMETER', msg => "Missing 'input->cmd' parameter in build_ttyrec_cmdline_part2of2");
}
my @cmd = @{$input->{'cmd'}};
my $idleLockTimeout = $params{'idleLockTimeout'};
my $idleKillTimeout = $params{'idleKillTimeout'};
push @cmd, '-k', $idleKillTimeout if $idleKillTimeout;
push @cmd, '-t', $idleLockTimeout if $idleLockTimeout;
push @cmd, '-s', "To unlock, use '--osh unlock' from another console" if $idleLockTimeout;
my $ttyrecAdditionalParameters = OVH::Bastion::config('ttyrecAdditionalParameters')->value;
push @cmd, @$ttyrecAdditionalParameters if @$ttyrecAdditionalParameters;
$input->{'cmd'} = \@cmd;
return R('OK', value => $input);
}
sub do_pamtester {
my %params = @_;
my $sysself = $params{'sysself'};

View file

@ -842,36 +842,42 @@ sub is_access_granted {
# 3/3 fill up keys and other metadata info (mfa, idle lock/kill timeout) if asked to
if ($details) {
foreach my $access (@grants) {
undef $fnret;
my $mfaFnret;
my %data;
if ($access->{'type'} =~ /^group/ and $access->{'group'}) {
$fnret = OVH::Bastion::get_group_keys(
$data{'keys'} = OVH::Bastion::get_group_keys(
group => $access->{'group'},
listOnly => $listOnly,
noexec => $noexec,
forceKey => $access->{'forceKey'}
);
$mfaFnret = OVH::Bastion::group_config(key => "mfa_required", group => $access->{'group'});
$data{'mfa'} = OVH::Bastion::group_config(key => "mfa_required", group => $access->{'group'});
$data{'idle_lock_timeout'} = OVH::Bastion::group_config(%{OVH::Bastion::OPT_GROUP_IDLE_LOCK_TIMEOUT()},
group => $access->{'group'});
$data{'idle_kill_timeout'} = OVH::Bastion::group_config(%{OVH::Bastion::OPT_GROUP_IDLE_KILL_TIMEOUT()},
group => $access->{'group'});
}
elsif ($access->{'type'} =~ /^personal/) {
$fnret = OVH::Bastion::get_personal_account_keys(
$data{'keys'} = OVH::Bastion::get_personal_account_keys(
account => $sysaccount,
listOnly => $listOnly,
noexec => $noexec,
forceKey => $access->{'forceKey'}
);
$mfaFnret = OVH::Bastion::account_config(key => "personal_egress_mfa_required", account => $sysaccount);
$data{'mfa'} =
OVH::Bastion::account_config(key => "personal_egress_mfa_required", account => $sysaccount);
}
else {
# unknown access type? no key!
warn_syslog("Unknown access type '" . $access->{'type'} . "' found, ignoring");
}
if ($fnret) {
if ($data{'keys'}) {
# TODO implement $access->{forceKey} check to include only the proper key
$access->{'keys'} = $fnret->value->{'keys'};
$access->{'sortedKeys'} = $fnret->value->{'sortedKeys'};
$access->{'mfaRequired'} = $mfaFnret->value if $mfaFnret;
$access->{'keys'} = $data{'keys'}->value->{'keys'};
$access->{'sortedKeys'} = $data{'keys'}->value->{'sortedKeys'};
$access->{'mfaRequired'} = $data{'mfa'}->value if $data{'mfa'};
$access->{'idleLockTimeout'} = $data{'idle_lock_timeout'}->value if $data{'idle_lock_timeout'};
$access->{'idleKillTimeout'} = $data{'idle_kill_timeout'}->value if $data{'idle_kill_timeout'};
}
}
}

View file

@ -2,6 +2,7 @@
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
use common::sense;
use Test::More;
use Test::Deep;
use File::Basename;
use lib dirname(__FILE__) . '/../../lib/perl';
@ -46,6 +47,9 @@ OVH::Bastion::load_configuration(
],
bastionName => "mock",
idleLockTimeout => 17,
idleKillTimeout => 29,
# all options below are bool, we'll test for their normalization
enableSyslog => 1,
enableGlobalAccessLog => JSON::true,
@ -60,6 +64,98 @@ OVH::Bastion::load_configuration(
);
# TESTS
my $fnret;
$fnret = OVH::Bastion::build_ttyrec_cmdline(
ip => "127.0.0.1",
port => 7979,
user => "randomuser",
account => "bastionuser",
uniqid => 'cafed00dcafe',
home => "/home/randomuser",
);
cmp_deeply(
$fnret->value->{'saveFile'},
re(
qr{^\Q/home/randomuser/ttyrec/127.0.0.1/20\E\d\d-\d\d-\d\d.\d\d\-\d\d\-\d\d\.\d{6}\Q.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec\E$}
),
"build_ttyrec_cmdline saveFile"
);
cmp_deeply(
$fnret->value->{'cmd'},
[
'ttyrec',
'-f',
$fnret->value->{'saveFile'},
'-F',
'/home/randomuser/ttyrec/127.0.0.1/%Y-%m-%d.%H-%M-%S.#usec#.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec',
'-k',
29,
'-t',
17,
'-s',
"To unlock, use '--osh unlock' from another console",
'-k',
29,
],
"build_ttyrec_cmdline cmd"
);
$fnret = OVH::Bastion::build_ttyrec_cmdline_part1of2(
ip => "127.0.0.1",
port => 7979,
user => "randomuser",
account => "bastionuser",
uniqid => 'cafed00dcafe',
home => "/home/randomuser",
);
cmp_deeply(
$fnret->value->{'saveFile'},
re(
qr{^\Q/home/randomuser/ttyrec/127.0.0.1/20\E\d\d-\d\d-\d\d.\d\d\-\d\d\-\d\d\.\d{6}\Q.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec\E$}
),
"build_ttyrec_cmdline_part1of2 saveFile"
);
cmp_deeply(
$fnret->value->{'cmd'},
[
'ttyrec',
'-f',
$fnret->value->{'saveFile'},
'-F',
'/home/randomuser/ttyrec/127.0.0.1/%Y-%m-%d.%H-%M-%S.#usec#.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec'
],
"build_ttyrec_cmdline_part1of2 cmd"
);
$fnret = OVH::Bastion::build_ttyrec_cmdline_part2of2(
input => $fnret->value,
idleKillTimeout => 88,
idleLockTimeout => 99,
);
cmp_deeply(
$fnret->value->{'saveFile'},
re(
qr{^\Q/home/randomuser/ttyrec/127.0.0.1/20\E\d\d-\d\d-\d\d.\d\d\-\d\d\-\d\d\.\d{6}\Q.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec\E$}
),
"build_ttyrec_cmdline_part2of2 saveFile"
);
cmp_deeply(
$fnret->value->{'cmd'},
[
'ttyrec',
'-f',
$fnret->value->{'saveFile'},
'-F',
'/home/randomuser/ttyrec/127.0.0.1/%Y-%m-%d.%H-%M-%S.#usec#.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec',
'-k',
88,
'-t',
99,
'-s',
"To unlock, use '--osh unlock' from another console"
],
"build_ttyrec_cmdline_part2of2 cmd"
);
is(OVH::Bastion::config("bastionName")->value, "mock", "bastion name is mocked");