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

(-)a/t/db_dependent/Koha/Patron.t (+195 lines)
Lines 1807-1812 subtest 'force_password_reset_when_set_by_staff tests' => sub { Link Here
1807
    $schema->storage->txn_rollback;
1807
    $schema->storage->txn_rollback;
1808
};
1808
};
1809
1809
1810
subtest 'password history integration tests' => sub {
1811
    plan tests => 7;
1812
1813
    $schema->storage->txn_begin;
1814
1815
    my $category = $builder->build_object(
1816
        {
1817
            class => 'Koha::Patron::Categories',
1818
            value => {
1819
                password_history_count  => 3,
1820
                require_strong_password => 0,
1821
            }
1822
        }
1823
    );
1824
1825
    my $patron = $builder->build_object(
1826
        {
1827
            class => 'Koha::Patrons',
1828
            value => {
1829
                categorycode => $category->categorycode,
1830
                password     => Koha::AuthUtils::hash_password('initial_password')
1831
            }
1832
        }
1833
    );
1834
1835
    # Test that password history is created when changing password
1836
    my $initial_history_count =
1837
        Koha::PatronPasswordHistories->search( { borrowernumber => $patron->borrowernumber } )->count;
1838
1839
    $patron->set_password( { password => 'new_password_1', skip_validation => 1 } );
1840
1841
    my $new_history_count =
1842
        Koha::PatronPasswordHistories->search( { borrowernumber => $patron->borrowernumber } )->count;
1843
1844
    is( $new_history_count, $initial_history_count + 1, 'Password history entry created when password changed' );
1845
1846
    # Test that UsedBefore exception is thrown for reused password
1847
    throws_ok {
1848
        $patron->set_password( { password => 'initial_password' } );
1849
    }
1850
    'Koha::Exceptions::Password::UsedBefore', 'UsedBefore exception thrown for reused password';
1851
1852
    # Test that category-specific history count is respected
1853
    $patron->set_password( { password => 'new_password_2', skip_validation => 1 } );
1854
    $patron->set_password( { password => 'new_password_3', skip_validation => 1 } );
1855
    $patron->set_password( { password => 'new_password_4', skip_validation => 1 } );
1856
1857
    my $final_history_count =
1858
        Koha::PatronPasswordHistories->search( { borrowernumber => $patron->borrowernumber } )->count;
1859
1860
    # With password_history_count=3, we should have 2 history entries (3-1 for current)
1861
    is( $final_history_count, 2, 'Password history cleanup respects category setting' );
1862
1863
    # Test that changing category password_history_count affects validation
1864
    $category->password_history_count(1)->store;
1865
1866
    lives_ok {
1867
        $patron->set_password( { password => 'initial_password', skip_validation => 1 } );
1868
    }
1869
    'With history_count=1, old passwords from history are not checked';
1870
1871
    throws_ok {
1872
        $patron->set_password( { password => 'initial_password' } );
1873
    }
1874
    'Koha::Exceptions::Password::UsedBefore', 'Current password still checked with history_count=1';
1875
1876
    # Test with history_count=0 (no checking)
1877
    $category->password_history_count(0)->store;
1878
1879
    lives_ok {
1880
        $patron->set_password( { password => 'initial_password', skip_validation => 1 } );
1881
    }
1882
    'With history_count=0, no password history checking performed';
1883
1884
    # Test fallback to system preference
1885
    $category->password_history_count(undef)->store;
1886
    t::lib::Mocks::mock_preference( 'PasswordHistoryCount', 2 );
1887
1888
    throws_ok {
1889
        $patron->set_password( { password => 'initial_password' } );
1890
    }
1891
    'Koha::Exceptions::Password::UsedBefore', 'Falls back to system preference when category setting is null';
1892
1893
    $schema->storage->txn_rollback;
1894
};
1895
1896
subtest 'password history edge cases and overrides' => sub {
1897
    plan tests => 4;
1898
1899
    $schema->storage->txn_begin;
1900
1901
    # Test both category and system preference = 0 (should allow password reuse)
1902
    t::lib::Mocks::mock_preference( 'PasswordHistoryCount', 0 );
1903
1904
    my $category_zero = $builder->build_object(
1905
        {
1906
            class => 'Koha::Patron::Categories',
1907
            value => {
1908
                password_history_count  => 0,
1909
                require_strong_password => 0,
1910
            }
1911
        }
1912
    );
1913
1914
    my $patron_zero = $builder->build_object(
1915
        {
1916
            class => 'Koha::Patrons',
1917
            value => {
1918
                categorycode => $category_zero->categorycode,
1919
                password     => Koha::AuthUtils::hash_password('reusable_password')
1920
            }
1921
        }
1922
    );
1923
1924
    # Should allow password reuse when both are 0
1925
    lives_ok {
1926
        $patron_zero->set_password( { password => 'reusable_password' } );
1927
    }
1928
    'Password reuse allowed when both category and system preference are 0';
1929
1930
    # Test category overrides system preference (category higher than system)
1931
    t::lib::Mocks::mock_preference( 'PasswordHistoryCount', 1 );
1932
1933
    my $category_high = $builder->build_object(
1934
        {
1935
            class => 'Koha::Patron::Categories',
1936
            value => {
1937
                password_history_count  => 3,
1938
                require_strong_password => 0,
1939
            }
1940
        }
1941
    );
1942
1943
    my $patron_high = $builder->build_object(
1944
        {
1945
            class => 'Koha::Patrons',
1946
            value => {
1947
                categorycode => $category_high->categorycode,
1948
                password     => Koha::AuthUtils::hash_password('test_password')
1949
            }
1950
        }
1951
    );
1952
1953
    # Add some password history
1954
    $patron_high->set_password( { password => 'password1', skip_validation => 1 } );
1955
    $patron_high->set_password( { password => 'password2', skip_validation => 1 } );
1956
1957
    # Should prevent reuse of old password because category=3 overrides system=1
1958
    throws_ok {
1959
        $patron_high->set_password( { password => 'test_password' } );
1960
    }
1961
    'Koha::Exceptions::Password::UsedBefore', 'Category setting (3) overrides lower system setting (1)';
1962
1963
    # Test category overrides system preference (category lower than system)
1964
    t::lib::Mocks::mock_preference( 'PasswordHistoryCount', 5 );
1965
1966
    my $category_low = $builder->build_object(
1967
        {
1968
            class => 'Koha::Patron::Categories',
1969
            value => {
1970
                password_history_count  => 1,
1971
                require_strong_password => 0,
1972
            }
1973
        }
1974
    );
1975
1976
    my $patron_low = $builder->build_object(
1977
        {
1978
            class => 'Koha::Patrons',
1979
            value => {
1980
                categorycode => $category_low->categorycode,
1981
                password     => Koha::AuthUtils::hash_password('another_password')
1982
            }
1983
        }
1984
    );
1985
1986
    # Add password history that would be caught by system=5 but not category=1
1987
    $patron_low->set_password( { password => 'old_password1', skip_validation => 1 } );
1988
    $patron_low->set_password( { password => 'old_password2', skip_validation => 1 } );
1989
1990
    # Should allow reuse of original password because category=1 overrides system=5
1991
    lives_ok {
1992
        $patron_low->set_password( { password => 'another_password', skip_validation => 1 } );
1993
    }
1994
    'Category setting (1) overrides higher system setting (5) - old password allowed';
1995
1996
    # But current password should still be blocked
1997
    throws_ok {
1998
        $patron_low->set_password( { password => 'another_password' } );
1999
    }
2000
    'Koha::Exceptions::Password::UsedBefore', 'Current password still blocked with category=1';
2001
2002
    $schema->storage->txn_rollback;
2003
};
2004
1810
subtest 'safe_to_delete() tests' => sub {
2005
subtest 'safe_to_delete() tests' => sub {
1811
2006
1812
    plan tests => 17;
2007
    plan tests => 17;
(-)a/t/db_dependent/Koha/Patron/Category.t (-2 / +51 lines)
Lines 20-26 Link Here
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::NoWarnings;
22
use Test::NoWarnings;
23
use Test::More tests => 9;
23
use Test::More tests => 10;
24
24
25
use t::lib::TestBuilder;
25
use t::lib::TestBuilder;
26
use t::lib::Mocks;
26
use t::lib::Mocks;
Lines 310-315 subtest 'get_password_expiry_date() tests' => sub { Link Here
310
310
311
};
311
};
312
312
313
subtest 'effective_password_history_count' => sub {
314
    plan tests => 5;
315
316
    $schema->storage->txn_begin;
317
318
    t::lib::Mocks::mock_preference( 'PasswordHistoryCount', 3 );
319
320
    my $category =
321
        $builder->build_object( { class => 'Koha::Patron::Categories', value => { password_history_count => undef } } );
322
323
    is(
324
        $category->effective_password_history_count, 3,
325
        'Category should use password history count from system preference'
326
    );
327
328
    $category->password_history_count(5)->store;
329
330
    is(
331
        $category->effective_password_history_count, 5,
332
        'Category should use password history count from category setting'
333
    );
334
335
    # Test explicit 0 in category (should not fall back to system preference)
336
    $category->password_history_count(0)->store;
337
338
    is(
339
        $category->effective_password_history_count, 0,
340
        'Category setting of 0 should return 0, not fall back to system preference'
341
    );
342
343
    # Test system preference = 0, category = undef (should return 0)
344
    t::lib::Mocks::mock_preference( 'PasswordHistoryCount', 0 );
345
    $category->password_history_count(undef)->store;
346
347
    is(
348
        $category->effective_password_history_count, 0,
349
        'Should return 0 when system preference is 0 and category is undef'
350
    );
351
352
    # Test both are 0
353
    $category->password_history_count(0)->store;
354
355
    is(
356
        $category->effective_password_history_count, 0,
357
        'Should return 0 when both category and system preference are 0'
358
    );
359
360
    $schema->storage->txn_rollback;
361
};
362
313
subtest 'can_make_suggestions' => sub {
363
subtest 'can_make_suggestions' => sub {
314
364
315
    plan tests => 6;
365
    plan tests => 6;
316
- 

Return to bug 40824