View | Details | Raw Unified | Return to bug 27342
Collapse All | Expand All

(-)a/C4/Auth.pm (-12 / +12 lines)
Lines 398-404 sub get_template_and_user { Link Here
398
                # we add them to the logged-in search history
398
                # we add them to the logged-in search history
399
                my @recentSearches = C4::Search::History::get_from_session( { cgi => $in->{'query'} } );
399
                my @recentSearches = C4::Search::History::get_from_session( { cgi => $in->{'query'} } );
400
                if (@recentSearches) {
400
                if (@recentSearches) {
401
                    my $dbh   = C4::Context->dbh;
402
                    my $query = q{
401
                    my $query = q{
403
                        INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, type,  total, time )
402
                        INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, type,  total, time )
404
                        VALUES (?, ?, ?, ?, ?, ?, ?)
403
                        VALUES (?, ?, ?, ?, ?, ?, ?)
Lines 835-841 sub checkauth { Link Here
835
          @allowed_scripts_for_private_opac;
834
          @allowed_scripts_for_private_opac;
836
    }
835
    }
837
836
838
    my $dbh     = C4::Context->dbh;
839
    my $timeout = _timeout_syspref();
837
    my $timeout = _timeout_syspref();
840
838
841
    _version_check( $type, $query );
839
    _version_check( $type, $query );
Lines 994-1000 sub checkauth { Link Here
994
                my $retuserid;
992
                my $retuserid;
995
993
996
                # Do not pass password here, else shib will not be checked in checkpw.
994
                # Do not pass password here, else shib will not be checked in checkpw.
997
                ( $return, $cardnumber, $retuserid ) = checkpw( $dbh, $q_userid, undef, $query );
995
                ( $return, $cardnumber, $retuserid ) = checkpw( $q_userid, undef, $query );
998
                $userid      = $retuserid;
996
                $userid      = $retuserid;
999
                $shibSuccess = $return;
997
                $shibSuccess = $return;
1000
                $info{'invalidShibLogin'} = 1 unless ($return);
998
                $info{'invalidShibLogin'} = 1 unless ($return);
Lines 1005-1011 sub checkauth { Link Here
1005
                if ( $cas && $query->param('ticket') ) {
1003
                if ( $cas && $query->param('ticket') ) {
1006
                    my $retuserid;
1004
                    my $retuserid;
1007
                    ( $return, $cardnumber, $retuserid, $cas_ticket ) =
1005
                    ( $return, $cardnumber, $retuserid, $cas_ticket ) =
1008
                      checkpw( $dbh, $userid, $password, $query, $type );
1006
                      checkpw( $userid, $password, $query, $type );
1009
                    $userid = $retuserid;
1007
                    $userid = $retuserid;
1010
                    $info{'invalidCasLogin'} = 1 unless ($return);
1008
                    $info{'invalidCasLogin'} = 1 unless ($return);
1011
                }
1009
                }
Lines 1074-1080 sub checkauth { Link Here
1074
                    {
1072
                    {
1075
1073
1076
                        ( $return, $cardnumber, $retuserid, $cas_ticket ) =
1074
                        ( $return, $cardnumber, $retuserid, $cas_ticket ) =
1077
                          checkpw( $dbh, $q_userid, $password, $query, $type );
1075
                          checkpw( $q_userid, $password, $query, $type );
1078
                        $userid = $retuserid if ($retuserid);
1076
                        $userid = $retuserid if ($retuserid);
1079
                        $info{'invalid_username_or_password'} = 1 unless ($return);
1077
                        $info{'invalid_username_or_password'} = 1 unless ($return);
1080
                    }
1078
                    }
Lines 1119-1124 sub checkauth { Link Here
1119
                    FROM borrowers
1117
                    FROM borrowers
1120
                    LEFT JOIN branches on borrowers.branchcode=branches.branchcode
1118
                    LEFT JOIN branches on borrowers.branchcode=branches.branchcode
1121
                    ";
1119
                    ";
1120
                    my $dbh = C4::Context->dbh;
1122
                    my $sth = $dbh->prepare("$select where userid=?");
1121
                    my $sth = $dbh->prepare("$select where userid=?");
1123
                    $sth->execute($userid);
1122
                    $sth->execute($userid);
1124
                    unless ( $sth->rows ) {
1123
                    unless ( $sth->rows ) {
Lines 1460-1466 sub check_api_auth { Link Here
1460
1459
1461
    my $query         = shift;
1460
    my $query         = shift;
1462
    my $flagsrequired = shift;
1461
    my $flagsrequired = shift;
1463
    my $dbh     = C4::Context->dbh;
1464
    my $timeout = _timeout_syspref();
1462
    my $timeout = _timeout_syspref();
1465
1463
1466
    unless ( C4::Context->preference('Version') ) {
1464
    unless ( C4::Context->preference('Version') ) {
Lines 1512-1518 sub check_api_auth { Link Here
1512
1510
1513
            # In case of a CAS authentication, we use the ticket instead of the password
1511
            # In case of a CAS authentication, we use the ticket instead of the password
1514
            my $PT = $query->param('PT');
1512
            my $PT = $query->param('PT');
1515
            ( $return, $cardnumber, $userid, $cas_ticket ) = check_api_auth_cas( $dbh, $PT, $query );    # EXTERNAL AUTH
1513
            ( $return, $cardnumber, $userid, $cas_ticket ) = check_api_auth_cas( $PT, $query );    # EXTERNAL AUTH
1516
        } else {
1514
        } else {
1517
1515
1518
            # User / password auth
1516
            # User / password auth
Lines 1522-1528 sub check_api_auth { Link Here
1522
                return ( "failed", undef, undef );
1520
                return ( "failed", undef, undef );
1523
            }
1521
            }
1524
            my $newuserid;
1522
            my $newuserid;
1525
            ( $return, $cardnumber, $newuserid, $cas_ticket ) = checkpw( $dbh, $userid, $password, $query );
1523
            ( $return, $cardnumber, $newuserid, $cas_ticket ) = checkpw( $userid, $password, $query );
1526
        }
1524
        }
1527
1525
1528
        if ( $return and haspermission( $userid, $flagsrequired ) ) {
1526
        if ( $return and haspermission( $userid, $flagsrequired ) ) {
Lines 1543-1548 sub check_api_auth { Link Here
1543
                    $userflags,      $branchcode, $branchname,
1541
                    $userflags,      $branchcode, $branchname,
1544
                    $emailaddress
1542
                    $emailaddress
1545
                );
1543
                );
1544
                my $dbh = C4::Context->dbh;
1546
                my $sth =
1545
                my $sth =
1547
                  $dbh->prepare(
1546
                  $dbh->prepare(
1548
"select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where userid=?"
1547
"select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where userid=?"
Lines 1798-1804 sub get_session { Link Here
1798
# Currently it's only passed from C4::SIP::ILS::Patron::check_password, but
1797
# Currently it's only passed from C4::SIP::ILS::Patron::check_password, but
1799
# not having a userenv defined could cause a crash.
1798
# not having a userenv defined could cause a crash.
1800
sub checkpw {
1799
sub checkpw {
1801
    my ( $dbh, $userid, $password, $query, $type, $no_set_userenv ) = @_;
1800
    my ( $userid, $password, $query, $type, $no_set_userenv ) = @_;
1802
    $type = 'opac' unless $type;
1801
    $type = 'opac' unless $type;
1803
1802
1804
    # Get shibboleth login attribute
1803
    # Get shibboleth login attribute
Lines 1833-1839 sub checkpw { Link Here
1833
        # In case of a CAS authentication, we use the ticket instead of the password
1832
        # In case of a CAS authentication, we use the ticket instead of the password
1834
        my $ticket = $query->param('ticket');
1833
        my $ticket = $query->param('ticket');
1835
        $query->delete('ticket');                                   # remove ticket to come back to original URL
1834
        $query->delete('ticket');                                   # remove ticket to come back to original URL
1836
        my ( $retval, $retcard, $retuserid, $cas_ticket ) = checkpw_cas( $dbh, $ticket, $query, $type );    # EXTERNAL AUTH
1835
        my ( $retval, $retcard, $retuserid, $cas_ticket ) = checkpw_cas( $ticket, $query, $type );    # EXTERNAL AUTH
1837
        if ( $retval ) {
1836
        if ( $retval ) {
1838
            @return = ( $retval, $retcard, $retuserid, $cas_ticket );
1837
            @return = ( $retval, $retcard, $retuserid, $cas_ticket );
1839
        } else {
1838
        } else {
Lines 1865-1871 sub checkpw { Link Here
1865
1864
1866
    # INTERNAL AUTH
1865
    # INTERNAL AUTH
1867
    if ( $check_internal_as_fallback ) {
1866
    if ( $check_internal_as_fallback ) {
1868
        @return = checkpw_internal( $dbh, $userid, $password, $no_set_userenv);
1867
        @return = checkpw_internal( $userid, $password, $no_set_userenv);
1869
        $passwd_ok = 1 if $return[0] > 0; # 1 or 2
1868
        $passwd_ok = 1 if $return[0] > 0; # 1 or 2
1870
    }
1869
    }
1871
1870
Lines 1888-1898 sub checkpw { Link Here
1888
}
1887
}
1889
1888
1890
sub checkpw_internal {
1889
sub checkpw_internal {
1891
    my ( $dbh, $userid, $password, $no_set_userenv ) = @_;
1890
    my ( $userid, $password, $no_set_userenv ) = @_;
1892
1891
1893
    $password = Encode::encode( 'UTF-8', $password )
1892
    $password = Encode::encode( 'UTF-8', $password )
1894
      if Encode::is_utf8($password);
1893
      if Encode::is_utf8($password);
1895
1894
1895
    my $dbh = C4::Context->dbh;
1896
    my $sth =
1896
    my $sth =
1897
      $dbh->prepare(
1897
      $dbh->prepare(
1898
        "select password,cardnumber,borrowernumber,userid,firstname,surname,borrowers.branchcode,branches.branchname,flags from borrowers join branches on borrowers.branchcode=branches.branchcode where userid=?"
1898
        "select password,cardnumber,borrowernumber,userid,firstname,surname,borrowers.branchcode,branches.branchname,flags from borrowers join branches on borrowers.branchcode=branches.branchcode where userid=?"
(-)a/C4/Auth_with_cas.pm (-2 / +4 lines)
Lines 99-105 sub login_cas_url { Link Here
99
# Checks for password correctness
99
# Checks for password correctness
100
# In our case : is there a ticket, is it valid and does it match one of our users ?
100
# In our case : is there a ticket, is it valid and does it match one of our users ?
101
sub checkpw_cas {
101
sub checkpw_cas {
102
    my ($dbh, $ticket, $query, $type) = @_;
102
    my ($ticket, $query, $type) = @_;
103
    my $retnumber;
103
    my $retnumber;
104
    my ( $cas, $uri ) = _get_cas_and_service($query, undef, $type);
104
    my ( $cas, $uri ) = _get_cas_and_service($query, undef, $type);
105
105
Lines 117-122 sub checkpw_cas { Link Here
117
            # we should store the CAS ticekt too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout
117
            # we should store the CAS ticekt too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout
118
118
119
            # Does it match one of our users ?
119
            # Does it match one of our users ?
120
            my $dbh = C4::Context->dbh;
120
            my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
121
            my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
121
            $sth->execute($userid);
122
            $sth->execute($userid);
122
            if ( $sth->rows ) {
123
            if ( $sth->rows ) {
Lines 147-153 sub checkpw_cas { Link Here
147
148
148
# Proxy CAS auth
149
# Proxy CAS auth
149
sub check_api_auth_cas {
150
sub check_api_auth_cas {
150
    my ($dbh, $PT, $query, $type) = @_;
151
    my ($PT, $query, $type) = @_;
151
    my $retnumber;
152
    my $retnumber;
152
    my ( $cas, $uri ) = _get_cas_and_service($query, undef, $type);
153
    my ( $cas, $uri ) = _get_cas_and_service($query, undef, $type);
153
154
Lines 164-169 sub check_api_auth_cas { Link Here
164
            # we should store the CAS ticket too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout
165
            # we should store the CAS ticket too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout
165
166
166
            # Does it match one of our users ?
167
            # Does it match one of our users ?
168
            my $dbh = C4::Context->dbh;
167
            my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
169
            my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
168
            $sth->execute($userid);
170
            $sth->execute($userid);
169
            if ( $sth->rows ) {
171
            if ( $sth->rows ) {
(-)a/C4/Auth_with_ldap.pm (-2 / +2 lines)
Lines 109-115 sub search_method { Link Here
109
}
109
}
110
110
111
sub checkpw_ldap {
111
sub checkpw_ldap {
112
    my ($dbh, $userid, $password) = @_;
112
    my ($userid, $password) = @_;
113
    my @hosts = split(',', $prefhost);
113
    my @hosts = split(',', $prefhost);
114
    my $db = Net::LDAP->new(\@hosts);
114
    my $db = Net::LDAP->new(\@hosts);
115
    unless ( $db ) {
115
    unless ( $db ) {
Lines 355-361 sub _do_changepassword { Link Here
355
    #warn "changing local password for borrowernumber=$borrowerid to '$digest'\n";
355
    #warn "changing local password for borrowernumber=$borrowerid to '$digest'\n";
356
    Koha::Patrons->find($borrowerid)->set_password({ password => $password, skip_validation => 1 });
356
    Koha::Patrons->find($borrowerid)->set_password({ password => $password, skip_validation => 1 });
357
357
358
    my ($ok, $cardnum) = checkpw_internal(C4::Context->dbh, $userid, $password);
358
    my ($ok, $cardnum) = checkpw_internal($userid, $password);
359
    return $cardnum if $ok;
359
    return $cardnum if $ok;
360
360
361
    warn "Password mismatch after update to borrowernumber=$borrowerid";
361
    warn "Password mismatch after update to borrowernumber=$borrowerid";
(-)a/C4/SIP/ILS/Patron.pm (-2 / +1 lines)
Lines 268-276 sub check_password { Link Here
268
    # If the record has a NULL password, accept '' as match
268
    # If the record has a NULL password, accept '' as match
269
    return $pwd eq q{} unless $self->{password};
269
    return $pwd eq q{} unless $self->{password};
270
270
271
    my $dbh = C4::Context->dbh;
272
    my $ret = 0;
271
    my $ret = 0;
273
    ($ret) = checkpw( $dbh, $self->{userid}, $pwd, undef, undef, 1 ); # dbh, userid, query, type, no_set_userenv
272
    ($ret) = checkpw( $self->{userid}, $pwd, undef, undef, 1 ); # userid, query, type, no_set_userenv
274
    return $ret;
273
    return $ret;
275
}
274
}
276
275
(-)a/Koha/REST/V1/Auth.pm (-2 / +1 lines)
Lines 486-493 sub _basic_auth { Link Here
486
    my $decoded_credentials = decode_base64( $credentials );
486
    my $decoded_credentials = decode_base64( $credentials );
487
    my ( $user_id, $password ) = split( /:/, $decoded_credentials, 2 );
487
    my ( $user_id, $password ) = split( /:/, $decoded_credentials, 2 );
488
488
489
    my $dbh = C4::Context->dbh;
489
    unless ( checkpw_internal($user_id, $password ) ) {
490
    unless ( checkpw_internal($dbh, $user_id, $password ) ) {
491
        Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Invalid password' );
490
        Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Invalid password' );
492
    }
491
    }
493
492
(-)a/Koha/REST/V1/Patrons/Password.pm (-2 / +1 lines)
Lines 119-126 sub set_public { Link Here
119
    }
119
    }
120
120
121
    return try {
121
    return try {
122
        my $dbh = C4::Context->dbh;
122
        unless ( checkpw_internal($user->userid, $old_password ) ) {
123
        unless ( checkpw_internal($dbh, $user->userid, $old_password ) ) {
124
            return $c->render(
123
            return $c->render(
125
                status  => 400,
124
                status  => 400,
126
                openapi => { error => "Invalid password" }
125
                openapi => { error => "Invalid password" }
(-)a/opac/sco/sco-main.pl (-2 / +1 lines)
Lines 118-125 my $issuer = Koha::Patrons->find( $issuerid )->unblessed; Link Here
118
my $patronid = $jwt ? Koha::Token->new->decode_jwt({ token => $jwt }) : undef;
118
my $patronid = $jwt ? Koha::Token->new->decode_jwt({ token => $jwt }) : undef;
119
unless ( $patronid ) {
119
unless ( $patronid ) {
120
    if ( C4::Context->preference('SelfCheckoutByLogin') ) {
120
    if ( C4::Context->preference('SelfCheckoutByLogin') ) {
121
        my $dbh = C4::Context->dbh;
121
        ( undef, $patronid ) = checkpw( $patronlogin, $patronpw );
122
        ( undef, $patronid ) = checkpw( $dbh, $patronlogin, $patronpw );
123
    }
122
    }
124
    else {    # People should not do that unless they know what they are doing!
123
    else {    # People should not do that unless they know what they are doing!
125
              # SelfCheckAllowByIPRanges MUST be configured
124
              # SelfCheckAllowByIPRanges MUST be configured
(-)a/t/db_dependent/Auth.t (-12 / +11 lines)
Lines 26-32 BEGIN { Link Here
26
26
27
my $schema  = Koha::Database->schema;
27
my $schema  = Koha::Database->schema;
28
my $builder = t::lib::TestBuilder->new;
28
my $builder = t::lib::TestBuilder->new;
29
my $dbh     = C4::Context->dbh;
30
29
31
# FIXME: SessionStorage defaults to mysql, but it seems to break transaction
30
# FIXME: SessionStorage defaults to mysql, but it seems to break transaction
32
# handling
31
# handling
Lines 164-177 subtest 'no_set_userenv parameter tests' => sub { Link Here
164
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
163
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
165
    $patron->set_password({ password => $password });
164
    $patron->set_password({ password => $password });
166
165
167
    ok( checkpw( $dbh, $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' );
166
    ok( checkpw( $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' );
168
    is( C4::Context->userenv, undef, 'Userenv should be undef as required' );
167
    is( C4::Context->userenv, undef, 'Userenv should be undef as required' );
169
    C4::Context->_new_userenv('DUMMY SESSION');
168
    C4::Context->_new_userenv('DUMMY SESSION');
170
    C4::Context->set_userenv(0,0,0,'firstname','surname', $library->branchcode, 'Library 1', 0, '', '');
169
    C4::Context->set_userenv(0,0,0,'firstname','surname', $library->branchcode, 'Library 1', 0, '', '');
171
    is( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv gives correct branch' );
170
    is( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv gives correct branch' );
172
    ok( checkpw( $dbh, $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' );
171
    ok( checkpw( $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' );
173
    is( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv branch is preserved if no_set_userenv is true' );
172
    is( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv branch is preserved if no_set_userenv is true' );
174
    ok( checkpw( $dbh, $patron->userid, $password, undef, undef, 0 ), 'checkpw still returns true' );
173
    ok( checkpw( $patron->userid, $password, undef, undef, 0 ), 'checkpw still returns true' );
175
    isnt( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv branch is overwritten if no_set_userenv is false' );
174
    isnt( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv branch is overwritten if no_set_userenv is false' );
176
};
175
};
177
176
Lines 186-200 subtest 'checkpw lockout tests' => sub { Link Here
186
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 1 );
185
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 1 );
187
    $patron->set_password({ password => $password });
186
    $patron->set_password({ password => $password });
188
187
189
    my ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->cardnumber, $password, undef, undef, 1 );
188
    my ( $checkpw, undef, undef ) = checkpw( $patron->cardnumber, $password, undef, undef, 1 );
190
    ok( $checkpw, 'checkpw returns true with right password when logging in via cardnumber' );
189
    ok( $checkpw, 'checkpw returns true with right password when logging in via cardnumber' );
191
    ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->userid, "wrong_password", undef, undef, 1 );
190
    ( $checkpw, undef, undef ) = checkpw( $patron->userid, "wrong_password", undef, undef, 1 );
192
    is( $checkpw, 0, 'checkpw returns false when given wrong password' );
191
    is( $checkpw, 0, 'checkpw returns false when given wrong password' );
193
    $patron = $patron->get_from_storage;
192
    $patron = $patron->get_from_storage;
194
    is( $patron->account_locked, 1, "Account is locked from failed login");
193
    is( $patron->account_locked, 1, "Account is locked from failed login");
195
    ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->userid, $password, undef, undef, 1 );
194
    ( $checkpw, undef, undef ) = checkpw( $patron->userid, $password, undef, undef, 1 );
196
    is( $checkpw, undef, 'checkpw returns undef with right password when account locked' );
195
    is( $checkpw, undef, 'checkpw returns undef with right password when account locked' );
197
    ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->cardnumber, $password, undef, undef, 1 );
196
    ( $checkpw, undef, undef ) = checkpw( $patron->cardnumber, $password, undef, undef, 1 );
198
    is( $checkpw, undef, 'checkpw returns undefwith right password when logging in via cardnumber if account locked' );
197
    is( $checkpw, undef, 'checkpw returns undefwith right password when logging in via cardnumber if account locked' );
199
198
200
};
199
};
Lines 392-398 subtest 'Check value of login_attempts in checkpw' => sub { Link Here
392
    $patron->password('123')->store; # yes, deliberately not hashed
391
    $patron->password('123')->store; # yes, deliberately not hashed
393
392
394
    is( $patron->account_locked, 0, 'Patron not locked' );
393
    is( $patron->account_locked, 0, 'Patron not locked' );
395
    my @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 );
394
    my @test = checkpw( $patron->userid, '123', undef, 'opac', 1 );
396
        # Note: 123 will not be hashed to 123 !
395
        # Note: 123 will not be hashed to 123 !
397
    is( $test[0], 0, 'checkpw should have failed' );
396
    is( $test[0], 0, 'checkpw should have failed' );
398
    $patron->discard_changes; # refresh
397
    $patron->discard_changes; # refresh
Lines 400-406 subtest 'Check value of login_attempts in checkpw' => sub { Link Here
400
    is( $patron->account_locked, 1, 'Check locked status' );
399
    is( $patron->account_locked, 1, 'Check locked status' );
401
400
402
    # And another try to go over the limit: different return value!
401
    # And another try to go over the limit: different return value!
403
    @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 );
402
    @test = checkpw( $patron->userid, '123', undef, 'opac', 1 );
404
    is( @test, 0, 'checkpw failed again and returns nothing now' );
403
    is( @test, 0, 'checkpw failed again and returns nothing now' );
405
    $patron->discard_changes; # refresh
404
    $patron->discard_changes; # refresh
406
    is( $patron->login_attempts, 3, 'Login attempts not increased anymore' );
405
    is( $patron->login_attempts, 3, 'Login attempts not increased anymore' );
Lines 410-420 subtest 'Check value of login_attempts in checkpw' => sub { Link Here
410
    my $auth = Test::MockModule->new( 'C4::Auth' );
409
    my $auth = Test::MockModule->new( 'C4::Auth' );
411
    $auth->mock( 'checkpw_hash', sub { return 1; } ); # not for production :)
410
    $auth->mock( 'checkpw_hash', sub { return 1; } ); # not for production :)
412
    $patron->login_attempts(0)->store;
411
    $patron->login_attempts(0)->store;
413
    @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 );
412
    @test = checkpw( $patron->userid, '123', undef, 'opac', 1 );
414
    is( $test[0], 1, 'Build confidence in the mock' );
413
    is( $test[0], 1, 'Build confidence in the mock' );
415
    $patron->login_attempts(-1)->store;
414
    $patron->login_attempts(-1)->store;
416
    is( $patron->account_locked, 1, 'Check administrative lockout' );
415
    is( $patron->account_locked, 1, 'Check administrative lockout' );
417
    @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 );
416
    @test = checkpw( $patron->userid, '123', undef, 'opac', 1 );
418
    is( @test, 0, 'checkpw gave red' );
417
    is( @test, 0, 'checkpw gave red' );
419
    $patron->discard_changes; # refresh
418
    $patron->discard_changes; # refresh
420
    is( $patron->login_attempts, -1, 'Still locked out' );
419
    is( $patron->login_attempts, -1, 'Still locked out' );
(-)a/t/db_dependent/Auth_with_ldap.t (-14 / +11 lines)
Lines 28-35 use C4::Context; Link Here
28
28
29
use Koha::Patrons;
29
use Koha::Patrons;
30
30
31
my $dbh = '';
32
33
# Start transaction
31
# Start transaction
34
my $schema = Koha::Database->new->schema;
32
my $schema = Koha::Database->new->schema;
35
$schema->storage->txn_begin();
33
$schema->storage->txn_begin();
Lines 131-142 subtest 'checkpw_ldap tests' => sub { Link Here
131
129
132
    plan tests => 4;
130
    plan tests => 4;
133
131
134
    my $dbh = C4::Context->dbh;
135
    ## Connection fail tests
132
    ## Connection fail tests
136
    $desired_connection_result = 'error';
133
    $desired_connection_result = 'error';
137
    warning_is {
134
    warning_is {
138
        $ret =
135
        $ret =
139
          C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' );
136
          C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' );
140
    }
137
    }
141
    'LDAP connexion failed',
138
    'LDAP connexion failed',
142
      'checkpw_ldap prints correct warning if LDAP conexion fails';
139
      'checkpw_ldap prints correct warning if LDAP conexion fails';
Lines 158-164 subtest 'checkpw_ldap tests' => sub { Link Here
158
        reload_ldap_module();
155
        reload_ldap_module();
159
156
160
        warning_like {
157
        warning_like {
161
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
158
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
162
                password => 'hey' );
159
                password => 'hey' );
163
        }
160
        }
164
        qr/Anonymous LDAP bind failed: LDAP error #1: error_name/,
161
        qr/Anonymous LDAP bind failed: LDAP error #1: error_name/,
Lines 171-177 subtest 'checkpw_ldap tests' => sub { Link Here
171
        reload_ldap_module();
168
        reload_ldap_module();
172
169
173
        warning_like {
170
        warning_like {
174
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
171
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
175
                password => 'hey' );
172
                password => 'hey' );
176
        }
173
        }
177
        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
174
        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
Lines 204-210 subtest 'checkpw_ldap tests' => sub { Link Here
204
            }
201
            }
205
        );
202
        );
206
203
207
        C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' );
204
        C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' );
208
        ok(
205
        ok(
209
            Koha::Patrons->find($borrower->{borrowernumber})->extended_attributes->count,
206
            Koha::Patrons->find($borrower->{borrowernumber})->extended_attributes->count,
210
            'Extended attributes are not deleted'
207
            'Extended attributes are not deleted'
Lines 219-225 subtest 'checkpw_ldap tests' => sub { Link Here
219
        $patron->delete;
216
        $patron->delete;
220
        reload_ldap_module();
217
        reload_ldap_module();
221
        is(
218
        is(
222
            C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' ),
219
            C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ),
223
            0,
220
            0,
224
            'checkpw_ldap returns 0 if user lookup returns 0'
221
            'checkpw_ldap returns 0 if user lookup returns 0'
225
        );
222
        );
Lines 228-234 subtest 'checkpw_ldap tests' => sub { Link Here
228
        reload_ldap_module();
225
        reload_ldap_module();
229
226
230
        warning_like {
227
        warning_like {
231
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
228
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
232
                password => 'hey' );
229
                password => 'hey' );
233
        }
230
        }
234
        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
231
        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
Lines 246-252 subtest 'checkpw_ldap tests' => sub { Link Here
246
        reload_ldap_module();
243
        reload_ldap_module();
247
244
248
        warning_like {
245
        warning_like {
249
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
246
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
250
                password => 'hey' );
247
                password => 'hey' );
251
        }
248
        }
252
        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
249
        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
Lines 271-277 subtest 'checkpw_ldap tests' => sub { Link Here
271
        reload_ldap_module();
268
        reload_ldap_module();
272
269
273
        warning_like {
270
        warning_like {
274
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
271
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
275
                password => 'hey' );
272
                password => 'hey' );
276
        }
273
        }
277
qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
274
qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
Lines 286-292 qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: er Link Here
286
        reload_ldap_module();
283
        reload_ldap_module();
287
284
288
        warning_like {
285
        warning_like {
289
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
286
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
290
                password => 'hey' );
287
                password => 'hey' );
291
        }
288
        }
292
qr/LDAP Auth rejected : invalid password for user 'hola'./,
289
qr/LDAP Auth rejected : invalid password for user 'hola'./,
Lines 300-306 qr/LDAP Auth rejected : invalid password for user 'hola'./, Link Here
300
        reload_ldap_module();
297
        reload_ldap_module();
301
298
302
        warning_like {
299
        warning_like {
303
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
300
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
304
                password => 'hey' );
301
                password => 'hey' );
305
        }
302
        }
306
qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
303
qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
Lines 313-319 qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: er Link Here
313
        reload_ldap_module();
310
        reload_ldap_module();
314
311
315
        warning_like {
312
        warning_like {
316
            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
313
            $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola',
317
                password => 'hey' );
314
                password => 'hey' );
318
        }
315
        }
319
qr/LDAP Auth rejected : invalid password for user 'hola'./,
316
qr/LDAP Auth rejected : invalid password for user 'hola'./,
(-)a/t/db_dependent/Log.t (-14 / +10 lines)
Lines 30-36 use t::lib::TestBuilder; Link Here
30
# Make sure we can rollback.
30
# Make sure we can rollback.
31
our $schema  = Koha::Database->new->schema;
31
our $schema  = Koha::Database->new->schema;
32
$schema->storage->txn_begin;
32
$schema->storage->txn_begin;
33
our $dbh = C4::Context->dbh;
34
33
35
subtest 'Existing tests' => sub {
34
subtest 'Existing tests' => sub {
36
    plan tests => 3;
35
    plan tests => 3;
Lines 47-63 subtest 'Existing tests' => sub { Link Here
47
    ok($success, "logaction seemed to work");
46
    ok($success, "logaction seemed to work");
48
47
49
    # We want numbers to be the same between runs.
48
    # We want numbers to be the same between runs.
50
    $dbh->do("DELETE FROM action_logs;");
49
    Koha::ActionLogs->search->delete;
51
50
52
    t::lib::Mocks::mock_preference('CronjobLog',0);
51
    t::lib::Mocks::mock_preference('CronjobLog',0);
53
    cronlogaction();
52
    cronlogaction();
54
    my $cronJobCount = $dbh->selectrow_array("SELECT COUNT(*) FROM action_logs WHERE module='CRONJOBS';",{});
53
    is(Koha::ActionLogs->search({ module => 'CRONJOBS' })->count,0,"Cronjob not logged as expected.");
55
    is($cronJobCount,0,"Cronjob not logged as expected.");
56
54
57
    t::lib::Mocks::mock_preference('CronjobLog',1);
55
    t::lib::Mocks::mock_preference('CronjobLog',1);
58
    cronlogaction();
56
    cronlogaction();
59
    $cronJobCount = $dbh->selectrow_array("SELECT COUNT(*) FROM action_logs WHERE module='CRONJOBS';",{});
57
    is(Koha::ActionLogs->search({ module => 'CRONJOBS' })->count,0,"Cronjob logged as expected.");
60
    is($cronJobCount,1,"Cronjob logged as expected.");
61
};
58
};
62
59
63
subtest 'logaction(): interface is correctly logged' => sub {
60
subtest 'logaction(): interface is correctly logged' => sub {
Lines 65-92 subtest 'logaction(): interface is correctly logged' => sub { Link Here
65
    plan tests => 4;
62
    plan tests => 4;
66
63
67
    # No interface passed, using C4::Context->interface
64
    # No interface passed, using C4::Context->interface
68
    $dbh->do("DELETE FROM action_logs;");
65
    Koha::ActionLogs->search->delete;
69
    C4::Context->interface( 'commandline' );
66
    C4::Context->interface( 'commandline' );
70
    logaction( "MEMBERS", "MODIFY", 1, "test operation");
67
    logaction( "MEMBERS", "MODIFY", 1, "test operation");
71
    my $log = Koha::ActionLogs->search->next;
68
    my $log = Koha::ActionLogs->search->next;
72
    is( $log->interface, 'commandline', 'Interface correctly deduced (commandline)');
69
    is( $log->interface, 'commandline', 'Interface correctly deduced (commandline)');
73
70
74
    # No interface passed, using C4::Context->interface
71
    # No interface passed, using C4::Context->interface
75
    $dbh->do("DELETE FROM action_logs;");
72
    Koha::ActionLogs->search->delete;
76
    C4::Context->interface( 'opac' );
73
    C4::Context->interface( 'opac' );
77
    logaction( "MEMBERS", "MODIFY", 1, "test operation");
74
    logaction( "MEMBERS", "MODIFY", 1, "test operation");
78
    $log = Koha::ActionLogs->search->next;
75
    $log = Koha::ActionLogs->search->next;
79
    is( $log->interface, 'opac', 'Interface correctly deduced (opac)');
76
    is( $log->interface, 'opac', 'Interface correctly deduced (opac)');
80
77
81
    # Explicit interfaces
78
    # Explicit interfaces
82
    $dbh->do("DELETE FROM action_logs;");
79
    Koha::ActionLogs->search->delete;
83
    C4::Context->interface( 'intranet' );
80
    C4::Context->interface( 'intranet' );
84
    logaction( "MEMBERS", "MODIFY", 1, 'test info', 'intranet');
81
    logaction( "MEMBERS", "MODIFY", 1, 'test info', 'intranet');
85
    $log = Koha::ActionLogs->search->next;
82
    $log = Koha::ActionLogs->search->next;
86
    is( $log->interface, 'intranet', 'Passed interface is respected (intranet)');
83
    is( $log->interface, 'intranet', 'Passed interface is respected (intranet)');
87
84
88
    # Explicit interfaces
85
    # Explicit interfaces
89
    $dbh->do("DELETE FROM action_logs;");
86
    Koha::ActionLogs->search->delete;
90
    C4::Context->interface( 'sip' );
87
    C4::Context->interface( 'sip' );
91
    logaction( "MEMBERS", "MODIFY", 1, 'test info', 'sip');
88
    logaction( "MEMBERS", "MODIFY", 1, 'test info', 'sip');
92
    $log = Koha::ActionLogs->search->next;
89
    $log = Koha::ActionLogs->search->next;
Lines 114-120 subtest 'GDPR logging' => sub { Link Here
114
    t::lib::Mocks::mock_preference('AuthFailureLog', 1);
111
    t::lib::Mocks::mock_preference('AuthFailureLog', 1);
115
    my $strong_password = 'N0tStr0ngAnyM0reN0w:)';
112
    my $strong_password = 'N0tStr0ngAnyM0reN0w:)';
116
    $patron->set_password({ password => $strong_password });
113
    $patron->set_password({ password => $strong_password });
117
    my @ret = checkpw( $dbh, $patron->userid, 'WrongPassword', undef, undef, 1);
114
    my @ret = checkpw( $patron->userid, 'WrongPassword', undef, undef, 1);
118
    is( $ret[0], 0, 'Authentication failed' );
115
    is( $ret[0], 0, 'Authentication failed' );
119
    # Look for auth failure but NOT on patron id, pass userid in info parameter
116
    # Look for auth failure but NOT on patron id, pass userid in info parameter
120
    $logs = Koha::ActionLogs->search(
117
    $logs = Koha::ActionLogs->search(
Lines 126-132 subtest 'GDPR logging' => sub { Link Here
126
    );
123
    );
127
    is( $logs->count, 1, 'We should find one auth failure with this userid' );
124
    is( $logs->count, 1, 'We should find one auth failure with this userid' );
128
    t::lib::Mocks::mock_preference('AuthFailureLog', 0);
125
    t::lib::Mocks::mock_preference('AuthFailureLog', 0);
129
    @ret = checkpw( $dbh, $patron->userid, 'WrongPassword', undef, undef, 1);
126
    @ret = checkpw( $patron->userid, 'WrongPassword', undef, undef, 1);
130
    $logs = Koha::ActionLogs->search(
127
    $logs = Koha::ActionLogs->search(
131
        {
128
        {
132
            module => 'AUTH',
129
            module => 'AUTH',
Lines 136-142 subtest 'GDPR logging' => sub { Link Here
136
    );
133
    );
137
    is( $logs->count, 1, 'Still only one failure with this userid' );
134
    is( $logs->count, 1, 'Still only one failure with this userid' );
138
    t::lib::Mocks::mock_preference('AuthSuccessLog', 1);
135
    t::lib::Mocks::mock_preference('AuthSuccessLog', 1);
139
    @ret = checkpw( $dbh, $patron->userid, $strong_password, undef, undef, 1);
136
    @ret = checkpw( $patron->userid, $strong_password, undef, undef, 1);
140
    is( $ret[0], 1, 'Authentication succeeded' );
137
    is( $ret[0], 1, 'Authentication succeeded' );
141
    # Now we can look for patron id
138
    # Now we can look for patron id
142
    $logs = Koha::ActionLogs->search(
139
    $logs = Koha::ActionLogs->search(
143
- 

Return to bug 27342