|
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; |