You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
8.9 KiB
355 lines
8.9 KiB
# Test 2F API
|
|
|
|
use Test::More;
|
|
use strict;
|
|
use JSON;
|
|
use IO::String;
|
|
use Lemonldap::NG::Common::Session;
|
|
|
|
eval { mkdir 't/sessions' };
|
|
`rm -rf t/sessions/*`;
|
|
|
|
require 't/test-lib.pm';
|
|
|
|
our $_json = JSON->new->allow_nonref;
|
|
|
|
sub newSession {
|
|
my ( $uid, $ip, $kind, $sfaDevices ) = splice @_;
|
|
my $tmp;
|
|
ok(
|
|
$tmp = Lemonldap::NG::Common::Session->new( {
|
|
storageModule => 'Apache::Session::File',
|
|
storageModuleOptions => {
|
|
Directory => 't/sessions',
|
|
LockDirectory => 't/sessions',
|
|
backend => 'Apache::Session::File',
|
|
generateModule =>
|
|
'Lemonldap::NG::Common::Apache::Session::Generate::SHA256',
|
|
},
|
|
}
|
|
),
|
|
'Sessions module'
|
|
);
|
|
count(1);
|
|
ok(
|
|
$tmp->update( {
|
|
ipAddr => $ip,
|
|
_whatToTrace => $uid,
|
|
uid => $uid,
|
|
_session_uid => $uid,
|
|
_utime => time,
|
|
_session_kind => $kind,
|
|
_2fDevices => to_json($sfaDevices),
|
|
}
|
|
), "New $kind session for $uid"
|
|
);
|
|
count(1);
|
|
}
|
|
|
|
sub check200 {
|
|
my ( $test, $res ) = splice @_;
|
|
ok( $res->[0] == 200, "$test: Result code is 200" );
|
|
count(1);
|
|
checkJson( $test, $res );
|
|
}
|
|
|
|
sub check405 {
|
|
my ( $test, $res ) = splice @_;
|
|
ok( $res->[0] == 405, "$test: Result code is 405" );
|
|
count(1);
|
|
checkJson( $test, $res );
|
|
}
|
|
|
|
sub check404 {
|
|
my ( $test, $res ) = splice @_;
|
|
ok( $res->[0] == 404, "$test: Result code is 404" );
|
|
count(1);
|
|
checkJson( $test, $res );
|
|
}
|
|
|
|
sub checkJson {
|
|
my ( $test, $res ) = splice @_;
|
|
my $key;
|
|
|
|
#diag Dumper($res->[2]->[0]);
|
|
ok( $key = from_json( $res->[2]->[0] ), "$test: Response is JSON" );
|
|
count(1);
|
|
}
|
|
|
|
sub get {
|
|
my ( $test, $uid, $type, $id ) = splice @_;
|
|
my ($res);
|
|
ok(
|
|
$res = &client->_get(
|
|
"/api/v1/secondFactor/$uid"
|
|
. (
|
|
defined $type ? "/type/$type" : ( defined $id ? "/id/$id" : "" )
|
|
)
|
|
),
|
|
"$test: Request succeed"
|
|
);
|
|
count(1);
|
|
return $res;
|
|
}
|
|
|
|
sub checkGet {
|
|
my ( $uid, $id ) = splice @_;
|
|
my ( $test, $res, $ret );
|
|
$test = "$uid should have one 2F with id \"$id\"";
|
|
$res = get( $test, $uid, undef, $id );
|
|
check200( $test, $res );
|
|
|
|
#diag Dumper($res);
|
|
$ret = from_json( $res->[2]->[0] );
|
|
ok( ref $ret eq 'HASH' && $ret->{id} eq $id,
|
|
"$test: check returned type is HASH and that ids match" );
|
|
count(1);
|
|
}
|
|
|
|
sub checkGet404 {
|
|
my ( $uid, $id ) = splice @_;
|
|
my ( $test, $res, $ret );
|
|
$test = "$uid should not have any 2F with id \"$id\"";
|
|
$res = get( $test, $uid, undef, $id );
|
|
check404( $test, $res );
|
|
}
|
|
|
|
sub checkGetList {
|
|
my ( $expect, $uid, $type ) = splice @_;
|
|
my ( $test, $res, $ret );
|
|
$test = "$uid should have $expect 2F"
|
|
. ( defined $type ? " of type \"$type\"" : "" );
|
|
$res = get( $test, $uid, $type );
|
|
check200( $test, $res );
|
|
|
|
#diag Dumper($res);
|
|
$ret = from_json( $res->[2]->[0] );
|
|
ok(
|
|
scalar @$ret eq $expect,
|
|
"$test: check if nb of 2F found ("
|
|
. scalar @$ret
|
|
. ") equals expectation ($expect)"
|
|
);
|
|
count(1);
|
|
return $ret;
|
|
}
|
|
|
|
sub checkGetBadType {
|
|
my ( $uid, $type ) = splice @_;
|
|
my ( $test, $res );
|
|
$test = "Get for uid $uid and type \"$type\" should get rejected.";
|
|
$res = get( $test, $uid, $type );
|
|
check405( $test, $res );
|
|
}
|
|
|
|
sub checkGetOnIds {
|
|
my ( $uid, $ret ) = splice @_;
|
|
foreach (@$ret) {
|
|
checkGet( $uid, $_->{id} );
|
|
}
|
|
}
|
|
|
|
sub checkGetOnIdsNotFound {
|
|
my ( $uid, $ret ) = splice @_;
|
|
foreach (@$ret) {
|
|
checkGet404( $uid, $_->{id} );
|
|
}
|
|
}
|
|
|
|
sub del {
|
|
my ( $test, $uid, $type, $id ) = splice @_;
|
|
my ($res);
|
|
ok(
|
|
$res = &client->_del(
|
|
"/api/v1/secondFactor/$uid"
|
|
. (
|
|
defined $type ? "/type/$type" : ( defined $id ? "/id/$id" : "" )
|
|
)
|
|
),
|
|
"$test: Request succeed"
|
|
);
|
|
count(1);
|
|
return $res;
|
|
}
|
|
|
|
sub checkDelete {
|
|
my ( $uid, $id ) = splice @_;
|
|
my ( $test, $res );
|
|
$test = "$uid should have a 2F with id \"$id\" to be deleted.";
|
|
$res = del( $test, $uid, undef, $id );
|
|
check200( $test, $res );
|
|
}
|
|
|
|
sub checkDelete404 {
|
|
my ( $uid, $id ) = splice @_;
|
|
my ( $test, $res );
|
|
$test = "$uid should not have a 2F with id \"$id\" to be deleted.";
|
|
$res = del( $test, $uid, undef, $id );
|
|
check404( $test, $res );
|
|
}
|
|
|
|
sub checkDeleteList {
|
|
my ( $expect, $uid, $type ) = splice @_;
|
|
my ( $test, $res, $ret, $countDel );
|
|
$test =
|
|
"Delete all 2F from $uid" . ( defined $type ? " of type \"$type\"" : "" );
|
|
$res = del( $test, $uid, $type );
|
|
check200( $test, $res );
|
|
$ret = from_json( $res->[2]->[0] );
|
|
($countDel) = $ret->{message} =~ m/^Successful operation: ([\d]+) /i;
|
|
$countDel = 0 unless ( defined $countDel );
|
|
ok(
|
|
$countDel eq $expect,
|
|
"$test: check nb of 2FA deleted ($countDel) matches expectation ($expect)"
|
|
);
|
|
count(1);
|
|
}
|
|
|
|
sub checkDeleteBadType {
|
|
my ( $uid, $type ) = splice @_;
|
|
my ( $test, $res );
|
|
$test = "Delete for uid $uid and type \"$type\" should get rejected.";
|
|
$res = del( $test, $uid, $type );
|
|
check405( $test, $res );
|
|
}
|
|
|
|
my $sfaDevices = [];
|
|
my $ret;
|
|
|
|
## Sessions creation
|
|
# msmith
|
|
newSession( 'msmith', '127.10.0.1', 'SSO', $sfaDevices );
|
|
newSession( 'msmith', '127.10.0.1', 'Persistent', $sfaDevices );
|
|
|
|
# dwho
|
|
$sfaDevices = [ {
|
|
"name" => "MyU2FKey",
|
|
"type" => "U2F",
|
|
"_userKey" => "123456",
|
|
"_keyHandle" => "654321",
|
|
"epoch" => time
|
|
},
|
|
{
|
|
"name" => "MyTOTP",
|
|
"type" => "TOTP",
|
|
"_secret" => "123456",
|
|
"epoch" => time
|
|
},
|
|
{
|
|
"name" => "MyYubikey",
|
|
"type" => "UBK",
|
|
"_secret" => "123456",
|
|
"epoch" => time
|
|
}
|
|
];
|
|
newSession( 'dwho', '127.10.0.1', 'SSO', $sfaDevices );
|
|
newSession( 'dwho', '127.10.0.1', 'Persistent', $sfaDevices );
|
|
|
|
# rtyler
|
|
$sfaDevices = [ {
|
|
"name" => "MyU2FKey",
|
|
"type" => "U2F",
|
|
"_userKey" => "123456",
|
|
"_keyHandle" => "654321",
|
|
"epoch" => time
|
|
},
|
|
{
|
|
"name" => "MyYubikey",
|
|
"type" => "UBK",
|
|
"_secret" => "123456",
|
|
"epoch" => time
|
|
},
|
|
{
|
|
"name" => "MyYubikey2",
|
|
"type" => "UBK",
|
|
"_secret" => "654321",
|
|
"epoch" => time
|
|
}
|
|
];
|
|
newSession( 'rtyler', '127.10.0.1', 'SSO', $sfaDevices );
|
|
newSession( 'rtyler', '127.10.0.1', 'Persistent', $sfaDevices );
|
|
|
|
# davros
|
|
$sfaDevices = [ {
|
|
"name" => "MyU2FKey",
|
|
"type" => "U2F",
|
|
"_userKey" => "123456",
|
|
"_keyHandle" => "654321",
|
|
"epoch" => time
|
|
},
|
|
{
|
|
"name" => "MyTOTP",
|
|
"type" => "TOTP",
|
|
"_secret" => "123456",
|
|
"epoch" => time
|
|
}
|
|
];
|
|
newSession( 'davros', '127.10.0.1', 'SSO', $sfaDevices );
|
|
newSession( 'davros', '127.10.0.1', 'Persistent', $sfaDevices );
|
|
|
|
# tof
|
|
$sfaDevices = [ {
|
|
"name" => "MyU2FKey",
|
|
"type" => "U2F",
|
|
"_userKey" => "123456",
|
|
"_keyHandle" => "654321",
|
|
"epoch" => time
|
|
}
|
|
];
|
|
newSession( 'tof', '127.10.0.1', 'SSO', $sfaDevices );
|
|
newSession( 'tof', '127.10.0.1', 'Persistent', $sfaDevices );
|
|
|
|
# dwho
|
|
checkGetList( 1, 'dwho', 'U2F' );
|
|
checkGetList( 1, 'dwho', 'TOTP' );
|
|
checkGetList( 1, 'dwho', 'UBK' );
|
|
checkGetBadType( 'dwho', 'UBKIKI' );
|
|
$ret = checkGetList( 3, 'dwho' );
|
|
checkGetOnIds( 'dwho', $ret );
|
|
checkDelete( 'dwho', @$ret[0]->{id} );
|
|
checkDelete404( 'dwho', @$ret[0]->{id} );
|
|
checkGetList( 2, 'dwho' );
|
|
checkDeleteList( 2, 'dwho' );
|
|
checkGetList( 0, 'dwho' );
|
|
checkDeleteList( 0, 'dwho' );
|
|
|
|
# msmith
|
|
checkGetList( 0, 'msmith' );
|
|
|
|
# rtyler
|
|
checkGetList( 1, 'rtyler', 'U2F' );
|
|
checkGetList( 0, 'rtyler', 'TOTP' );
|
|
checkGetList( 2, 'rtyler', 'UBK' );
|
|
$ret = checkGetList( 3, 'rtyler' );
|
|
checkGetOnIds( 'rtyler', $ret );
|
|
checkDeleteList( 2, 'rtyler', 'UBK' );
|
|
$ret = checkGetList( 1, 'rtyler' );
|
|
checkDelete( 'rtyler', @$ret[0]->{id} );
|
|
checkDelete404( 'rtyler', @$ret[0]->{id} );
|
|
checkDeleteList( 0, 'rtyler' );
|
|
|
|
# davros
|
|
checkGetList( 1, 'davros', 'U2F' );
|
|
checkGetList( 1, 'davros', 'TOTP' );
|
|
checkGetList( 0, 'davros', 'UBK' );
|
|
$ret = checkGetList( 2, 'davros' );
|
|
checkGetOnIds( 'davros', $ret );
|
|
checkDelete( 'davros', @$ret[0]->{id} );
|
|
checkDelete404( 'davros', @$ret[0]->{id} );
|
|
checkGetList( 1, 'davros' );
|
|
checkDeleteList( 1, 'davros', @$ret[1]->{type} );
|
|
checkGetList( 0, 'davros' );
|
|
checkDeleteList( 0, 'davros' );
|
|
|
|
# tof
|
|
checkGetList( 1, 'tof', 'U2F' );
|
|
checkGetList( 0, 'tof', 'TOTP' );
|
|
checkGetList( 0, 'tof', 'UBK' );
|
|
$ret = checkGetList( 1, 'tof' );
|
|
checkGetOnIds( 'tof', $ret );
|
|
checkDelete( 'tof', @$ret[0]->{id} );
|
|
checkDelete404( 'tof', @$ret[0]->{id} );
|
|
checkGetList( 0, 'tof' );
|
|
checkDeleteList( 0, 'tof' );
|
|
|
|
done_testing();
|
|
|