| Lines 19-24
          use C4::Members;
      
      
        Link Here | 
        
          | 19 | use Koha::AuthUtils qw/hash_password/; | 19 | use Koha::AuthUtils qw/hash_password/; | 
        
          | 20 | use Koha::Database; | 20 | use Koha::Database; | 
        
          | 21 | use Koha::Patrons; | 21 | use Koha::Patrons; | 
            
              |  |  | 22 | use Koha::Auth::TwoFactorAuth; | 
        
          | 22 |  | 23 |  | 
        
          | 23 | BEGIN { | 24 | BEGIN { | 
        
          | 24 |     use_ok('C4::Auth', qw( checkauth haspermission track_login_daily checkpw get_template_and_user checkpw_hash )); | 25 |     use_ok('C4::Auth', qw( checkauth haspermission track_login_daily checkpw get_template_and_user checkpw_hash )); | 
  
    | Lines 37-43
          $schema->storage->txn_begin;
      
      
        Link Here | 
        
          | 37 |  | 38 |  | 
        
          | 38 | subtest 'checkauth() tests' => sub { | 39 | subtest 'checkauth() tests' => sub { | 
        
          | 39 |  | 40 |  | 
          
            
              | 40 |     plan tests => 4; | 41 |     plan tests => 5; | 
        
          | 41 |  | 42 |  | 
        
          | 42 |     my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => undef } }); | 43 |     my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => undef } }); | 
        
          | 43 |  | 44 |  | 
  
    | Lines 107-112
          subtest 'checkauth() tests' => sub {
      
      
        Link Here | 
        
          | 107 |         is( $userid, undef, 'If librarian user is used and password with GET, they should not be logged in' ); | 108 |         is( $userid, undef, 'If librarian user is used and password with GET, they should not be logged in' ); | 
        
          | 108 |     }; | 109 |     }; | 
        
          | 109 |  | 110 |  | 
            
              |  |  | 111 |     subtest 'Two-factor authentication' => sub { | 
            
              | 112 |  | 
            
              | 113 |         my $patron = $builder->build_object( | 
            
              | 114 |             { class => 'Koha::Patrons', value => { flags => 1 } } ); | 
            
              | 115 |         my $password = 'password'; | 
            
              | 116 |         $patron->set_password( { password => $password } ); | 
            
              | 117 |         $cgi = Test::MockObject->new(); | 
            
              | 118 |  | 
            
              | 119 |         my $otp_token; | 
            
              | 120 |         our ( $logout, $sessionID, $verified ); | 
            
              | 121 |         $cgi->mock( | 
            
              | 122 |             'param', | 
            
              | 123 |             sub { | 
            
              | 124 |                 my ( $self, $param ) = @_; | 
            
              | 125 |                 if    ( $param eq 'userid' )    { return $patron->userid; } | 
            
              | 126 |                 elsif ( $param eq 'password' )  { return $password; } | 
            
              | 127 |                 elsif ( $param eq 'otp_token' ) { return $otp_token; } | 
            
              | 128 |                 elsif ( $param eq 'logout.x' )  { return $logout; } | 
            
              | 129 |                 else                            { return; } | 
            
              | 130 |             } | 
            
              | 131 |         ); | 
            
              | 132 |         $cgi->mock( 'request_method', sub { return 'POST' } ); | 
            
              | 133 |         $cgi->mock( 'cookie', sub { return $sessionID } ); | 
            
              | 134 |  | 
            
              | 135 |         my $two_factor_auth = Test::MockModule->new( 'Koha::Auth::TwoFactorAuth' ); | 
            
              | 136 |         $two_factor_auth->mock( 'verify', sub {$verified} ); | 
            
              | 137 |  | 
            
              | 138 |         my ( $userid, $cookie, $flags ); | 
            
              | 139 |         ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 140 |  | 
            
              | 141 |         sub logout { | 
            
              | 142 |             my $cgi = shift; | 
            
              | 143 |             $logout = 1; | 
            
              | 144 |             undef $sessionID; | 
            
              | 145 |             C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 146 |             $logout = 0; | 
            
              | 147 |         } | 
            
              | 148 |  | 
            
              | 149 |         t::lib::Mocks::mock_preference( 'TwoFactorAuthentication', 0 ); | 
            
              | 150 |         $patron->auth_method('password')->store; | 
            
              | 151 |         ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 152 |         is( $userid, $patron->userid, 'Succesful login' ); | 
            
              | 153 |         is( C4::Auth::get_session($sessionID)->param('waiting-for-2FA'), undef, 'Second auth not required' ); | 
            
              | 154 |         logout($cgi); | 
            
              | 155 |  | 
            
              | 156 |         $patron->auth_method('two-factor')->store; | 
            
              | 157 |         ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 158 |         is( $userid, $patron->userid, 'Succesful login' ); | 
            
              | 159 |         is( C4::Auth::get_session($sessionID)->param('waiting-for-2FA'), undef, 'Second auth not required' ); | 
            
              | 160 |         logout($cgi); | 
            
              | 161 |  | 
            
              | 162 |         t::lib::Mocks::mock_preference( 'TwoFactorAuthentication', 1 ); | 
            
              | 163 |         $patron->auth_method('password')->store; | 
            
              | 164 |         ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 165 |         is( $userid, $patron->userid, 'Succesful login' ); | 
            
              | 166 |         is( C4::Auth::get_session($sessionID)->param('waiting-for-2FA'), undef, 'Second auth not required' ); | 
            
              | 167 |         logout($cgi); | 
            
              | 168 |  | 
            
              | 169 |         $patron->auth_method('two-factor')->store; | 
            
              | 170 |         ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 171 |         is( $userid, $patron->userid, 'Succesful login' ); | 
            
              | 172 |         my $session = C4::Auth::get_session($sessionID); | 
            
              | 173 |         is( C4::Auth::get_session($sessionID)->param('waiting-for-2FA'), 1, 'Second auth required' ); | 
            
              | 174 |  | 
            
              | 175 |         # Wrong OTP token | 
            
              | 176 |         $otp_token = "wrong"; | 
            
              | 177 |         $verified = 0; | 
            
              | 178 |         $patron->auth_method('two-factor')->store; | 
            
              | 179 |         ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 180 |         is( $userid, $patron->userid, 'Succesful login' ); | 
            
              | 181 |         is( C4::Auth::get_session($sessionID)->param('waiting-for-2FA'), 1, 'Second auth still required after wrong OTP token' ); | 
            
              | 182 |  | 
            
              | 183 |         $otp_token = "good"; | 
            
              | 184 |         $verified = 1; | 
            
              | 185 |         ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth( $cgi, 'authrequired', undef, 'intranet' ); | 
            
              | 186 |         is( $userid, $patron->userid, 'Succesful login' ); | 
            
              | 187 |         is( C4::Auth::get_session($sessionID)->param('waiting-for-2FA'), 0, 'Second auth no longer required if OTP token has been verified' ); | 
            
              | 188 |  | 
            
              | 189 |     }; | 
            
              | 190 |  | 
        
          | 110 |     C4::Context->_new_userenv; # For next tests | 191 |     C4::Context->_new_userenv; # For next tests | 
        
          | 111 |  | 192 |  | 
        
          | 112 | }; | 193 | }; | 
            
              | 113 | -  |  |  |