lemonldap-ng/lemonldap-ng-common/t/60-U2F-Migrate.t

229 lines
8.5 KiB
Perl

# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl Lemonldap-NG-Manager.t'
#########################
# change 'tests => 1' to 'tests => last_test_to_print';
use Test::More;
use Test::Output;
use File::Path;
use JSON;
BEGIN {
use_ok('Lemonldap::NG::Common::Session');
use_ok('Lemonldap::NG::Common::CliSessions');
}
#########################
SKIP: {
eval "use Authen::WebAuthn::Test; use Authen::WebAuthn;";
if ($@) {
skip 'Authen::WebAuthn not found';
}
my $dir;
my $cli;
sub setup_sessions {
use File::Temp;
$dir = File::Temp::tempdir();
my $sessionsdir = "$dir/sessions";
my $psessionsdir = "$dir/psessions";
mkdir $sessionsdir;
mkdir $psessionsdir;
$cli = Lemonldap::NG::Common::CliSessions->new(
conf => {
globalStorage => "Apache::Session::File",
globalStorageOptions => {
Directory => $sessionsdir,
LockDirectory => $sessionsdir,
},
persistentStorage => "Apache::Session::File",
persistentStorageOptions => {
Directory => $psessionsdir,
LockDirectory => $psessionsdir,
},
}
);
# Provision test sessions
my @psessionsOpts = (
storageModule => "Apache::Session::File",
storageModuleOptions => {
Directory => $psessionsdir,
LockDirectory => $psessionsdir,
},
kind => 'Persistent',
force => 1,
);
#dwho
Lemonldap::NG::Common::Session->new( {
@psessionsOpts,
id => "5efe8af397fc3577e05b483aca964f1b",
force => 1,
info => {
"_2fDevices" => to_json( [ {
'type' => 'UBK',
'epoch' => 1588691690,
'_yubikey' => 'cccccceijfnf',
'name' => 'Imported automatically'
},
{
'name' => 'U2F-1',
'type' => 'U2F',
'epoch' => 1588691728,
'_keyHandle' =>
'4aS6vXlFQpG5XZSoad6auM9fFu7Q1wazQYwfPtPKN_Hll6Up_ceeWkOgqxm49swWq4Vvcg5UlX0sQQhuRe8heA',
'_userKey' =>
'BMgMqKPL2PhsjCNW78UEQyNF8zlJtrAAPtWMUDBp9VfDRF5oL2xkwFuyXRMPtRZ7lNfGijDrMc06bDNfp478sQQ',
},
{
'name' => 'U2F-2',
'type' => 'U2F',
'epoch' => 1588691730,
'_keyHandle' =>
'F1Kk9V_O7KDPIx-mqp6CIjbz7ljA-ihWVWyoP1xYBe_HPLHR74aTLanmn0b4vI8DumiBWO1DAle3k6N55cXreg',
'_userKey' =>
'BAE_svIcxLfm2Knart7DI1ScfBnCt-OFKDWugp3YMO14tamwuc_wN0vSh1D_0DV4Ao3S5GNQZXxtjtUADHTwXHA',
},
{
_credentialId => 'noconflict',
'name' => 'Existing WebAuthn',
'type' => 'WebAuthn',
'epoch' => 1588691798
}
]
),
"_oidcConsents" => to_json( [ {
'scope' => 'openid email',
'rp' => 'rp-example',
'epoch' => 1589288341
},
{
'scope' => 'openid email',
'epoch' => 1589291482,
'rp' => 'rp-example2'
}
]
),
"_session_uid" => "dwho",
}
}
);
# rtyler
Lemonldap::NG::Common::Session->new( {
@psessionsOpts,
id => "8d3bc3b0e14ea2a155f275aa7c07ebee",
force => 1,
info => {
"_session_uid" => "rtyler",
"_2fDevices" => to_json( [ {
'type' => 'UBK',
'epoch' => 1588691690,
'_yubikey' => 'cccccceijfnf',
'name' => 'Imported automatically'
},
{
'name' => 'U2F-3',
'type' => 'U2F',
'epoch' => 1588691734,
'_keyHandle' =>
'4suXv5Cf10vbJEP72mVkLpBjhSqy5niOgfc0X_MjdxZ_g2e-V8biC6WyCTpF_kGV1FCa06YlcryPCtWUuUST_g',
'_userKey' =>
'BIXrgc12iGGOYIGyWKd8WeOGCKyTkFA7jXkjlLS0i1MA3vy8gDocfqYCngXMzBAmtGI7FfMlbkG6DJeSubdxAVc',
},
]
),
}
}
);
}
sub getJson {
my @args = @_;
my ($str) = Test::Output::output_from( sub { $cli->run(@args); } );
return from_json($str);
}
sub getLines {
my @args = @_;
my ($str) = Test::Output::output_from( sub { $cli->run(@args); } );
return [ split /\n/, $str ];
}
setup_sessions();
my $res;
# Migrate U2F
$cli->run( "secondfactors", {}, "migrateu2f", "dwho" );
$res = getJson( "secondfactors", {}, "get", "rtyler" );
is( values %{$res}, 2, "Still 2 devices" );
is( ( grep { $_->{type} eq "WebAuthn" } values %{$res} ),
0, "No WebAuthn sessions created" );
$res = getJson( "secondfactors", {}, "get", "dwho" );
is( values %{$res}, 6, "Expect 6 devices after migration" );
is( ( grep { $_->{type} eq "U2F" } values %{$res} ),
2, "U2F still present" );
is( ( grep { $_->{type} eq "UBK" } values %{$res} ),
1, "UBK still in place" );
is( ( grep { $_->{type} eq "WebAuthn" } values %{$res} ),
3, "New WebAuthn device" );
my $migratedid = "MTU4ODY5MTcyODo6V2ViQXV0aG46OlUyRi0x";
is( $res->{$migratedid}->{_signCount}, 0, "migrated signcount" );
is(
$res->{$migratedid}->{_credentialId},
'4aS6vXlFQpG5XZSoad6auM9fFu7Q1wazQYwfPtPKN_Hll6Up_ceeWkOgqxm49swWq4Vvcg5UlX0sQQhuRe8heA',
"migrated credential ID"
);
is(
$res->{$migratedid}->{_credentialPublicKey},
'pQECAyYgASFYIMgMqKPL2PhsjCNW78UEQyNF8zlJtrAAPtWMUDBp9VfDIlggRF5oL2xkwFuyXRMPtRZ7lNfGijDrMc06bDNfp478sQQ',
"migrated credential key"
);
is( $res->{$migratedid}->{epoch}, '1588691728', "migrated epoch" );
is( $res->{$migratedid}->{name}, "U2F-1", "migrated name" );
# Check idempotence
$cli->run( "secondfactors", {}, "migrateu2f", "dwho" );
$res = getJson( "secondfactors", {}, "get", "dwho" );
is( values %{$res}, 6, "Expect still 6 devices after rerunning migration" );
is( ( grep { $_->{type} eq "U2F" } values %{$res} ),
2, "U2F still in place" );
is( ( grep { $_->{type} eq "UBK" } values %{$res} ),
1, "UBK still in place" );
is( ( grep { $_->{type} eq "WebAuthn" } values %{$res} ),
3, "Same WebAuthn devices" );
rmtree $dir;
setup_sessions();
# Migrate all
$cli->run( "secondfactors", { all => 1 }, "migrateu2f" );
$res = getJson( "secondfactors", {}, "get", "dwho" );
is( values %{$res}, 6, "Expect 6 devices after migration" );
is( ( grep { $_->{type} eq "U2F" } values %{$res} ),
2, "U2F still in place" );
is( ( grep { $_->{type} eq "UBK" } values %{$res} ),
1, "UBK still in place" );
is( ( grep { $_->{type} eq "WebAuthn" } values %{$res} ),
3, "New WebAuthn device" );
$res = getJson( "secondfactors", {}, "get", "rtyler" );
is( values %{$res}, 3, "Expect 3 devices after migration" );
is( ( grep { $_->{type} eq "U2F" } values %{$res} ),
1, "U2F still in place" );
is( ( grep { $_->{type} eq "UBK" } values %{$res} ),
1, "UBK still in place" );
is( ( grep { $_->{type} eq "WebAuthn" } values %{$res} ),
1, "New WebAuthn device" );
rmtree $dir;
}
done_testing();