diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 0b49e9e8c..dc2b757c3 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -457,6 +457,7 @@ t/73-2F-UTOTP-TOTP-and-U2F-with-HISTORY.t t/73-2F-UTOTP-TOTP-and-U2F.t t/73-2F-UTOTP-TOTP-only-with-HISTORY.t t/73-2F-UTOTP-TOTP-only.t +t/74-2F-Required.t t/90-Translations.t t/99-pod.t t/lmConf-1.json diff --git a/lemonldap-ng-portal/t/74-2F-Required.t b/lemonldap-ng-portal/t/74-2F-Required.t new file mode 100644 index 000000000..e34128396 --- /dev/null +++ b/lemonldap-ng-portal/t/74-2F-Required.t @@ -0,0 +1,121 @@ +use Test::More; +use strict; +use IO::String; + +require 't/test-lib.pm'; +my $maintests = 17; + +SKIP: { + eval { require Convert::Base32 }; + if ($@) { + skip 'Convert::Base32 is missing', $maintests; + } + require Lemonldap::NG::Common::TOTP; + + my $client = LLNG::Manager::Test->new( + { + ini => { + logLevel => 'error', + totp2fSelfRegistration => 1, + totp2fActivation => 1, + sfRequired => 1, + } + } + ); + my $res; + + # Try to authenticate + # ------------------- + ok( + $res = $client->_post( + '/', + IO::String->new('user=dwho&password=dwho'), + length => 23 + ), + 'Auth query' + ); + expectRedirection( $res, qr'http://auth.example.com/+2fregisters/?' ); + my $pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' ); + ok( $res = $client->_get( '/2fregisters', cookie => $pdata ), + 'Follow redirection to /2fregisters' ); + ok( $res->[2]->[0] =~ m#/2fregisters/totp#, 'Found TOTP link' ); + + # TOTP form + ok( + $res = $client->_get( + '/2fregisters/totp', + cookie => $pdata, + accept => 'text/html', + ), + 'Form registration' + ); + ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' ); + + # JS query + ok( + $res = $client->_post( + '/2fregisters/totp/getkey', IO::String->new(''), + cookie => $pdata, + length => 0, + ), + 'Get new key' + ); + eval { $res = JSON::from_json( $res->[2]->[0] ) }; + ok( not($@), 'Content is JSON' ) + or explain( $res->[2]->[0], 'JSON content' ); + my ( $key, $token ); + ok( $key = $res->{secret}, 'Found secret' ); + ok( $token = $res->{token}, 'Found token' ); + $key = Convert::Base32::decode_base32($key); + + # Post code + my $code; + ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ), + 'Code' ); + ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' ); + my $s = "code=$code&token=$token"; + ok( + $res = $client->_post( + '/2fregisters/totp/verify', + IO::String->new($s), + length => length($s), + cookie => $pdata, + ), + 'Post code' + ); + eval { $res = JSON::from_json( $res->[2]->[0] ) }; + ok( not($@), 'Content is JSON' ) + or explain( $res->[2]->[0], 'JSON content' ); + ok( $res->{result} == 1, 'Key is registered' ); + + # Try to sign-in + ok( + $res = $client->_post( + '/', + IO::String->new('user=dwho&password=dwho'), + length => 23, + accept => 'text/html', + ), + 'Auth query' + ); + my ( $host, $url, $query ) = + expectForm( $res, undef, '/totp2fcheck', 'token' ); + ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ), + 'Code' ); + $query =~ s/code=/code=$code/; + ok( + $res = $client->_post( + '/totp2fcheck', IO::String->new($query), + length => length($query), + ), + 'Post code' + ); + my $id = expectCookie($res); + $client->logout($id); +} +count($maintests); + +clean_sessions(); + +done_testing( count() ); +