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

(-)a/C4/Auth.pm (-1 / +1 lines)
Lines 455-461 sub get_template_and_user { Link Here
455
    my $using_https = ( defined $https and $https ne 'OFF' ) ? 1 : 0;
455
    my $using_https = ( defined $https and $https ne 'OFF' ) ? 1 : 0;
456
456
457
    my $minPasswordLength = C4::Context->preference('minPasswordLength');
457
    my $minPasswordLength = C4::Context->preference('minPasswordLength');
458
    $minPasswordLength = 3 if not $minPasswordLength or $minPasswordLength < 3;
458
    $minPasswordLength = 8 if not $minPasswordLength or $minPasswordLength < 8;
459
    $template->param(
459
    $template->param(
460
        "BiblioDefaultView" . C4::Context->preference("BiblioDefaultView") => 1,
460
        "BiblioDefaultView" . C4::Context->preference("BiblioDefaultView") => 1,
461
        EnhancedMessagingPreferences                                       => C4::Context->preference('EnhancedMessagingPreferences'),
461
        EnhancedMessagingPreferences                                       => C4::Context->preference('EnhancedMessagingPreferences'),
(-)a/C4/InstallAuth.pm (-1 / +1 lines)
Lines 151-157 sub get_template_and_user { Link Here
151
        }
151
        }
152
152
153
        my $minPasswordLength = C4::Context->preference('minPasswordLength');
153
        my $minPasswordLength = C4::Context->preference('minPasswordLength');
154
        $minPasswordLength = 3 if not $minPasswordLength or $minPasswordLength < 3;
154
        $minPasswordLength = 8 if not $minPasswordLength or $minPasswordLength < 8;
155
        $template->param(minPasswordLength => $minPasswordLength,);
155
        $template->param(minPasswordLength => $minPasswordLength,);
156
    }
156
    }
157
    return ( $template, $borrowernumber, $cookie );
157
    return ( $template, $borrowernumber, $cookie );
(-)a/Koha/AuthUtils.pm (-1 / +1 lines)
Lines 149-155 otherwise return $is_valid == 0 and $error will contain the error ('too_short' o Link Here
149
sub is_password_valid {
149
sub is_password_valid {
150
    my ($password) = @_;
150
    my ($password) = @_;
151
    my $minPasswordLength = C4::Context->preference('minPasswordLength');
151
    my $minPasswordLength = C4::Context->preference('minPasswordLength');
152
    $minPasswordLength = 3 if not $minPasswordLength or $minPasswordLength < 3;
152
    $minPasswordLength = 8 if not $minPasswordLength or $minPasswordLength < 8;
153
    if ( length($password) < $minPasswordLength ) {
153
    if ( length($password) < $minPasswordLength ) {
154
        return ( 0, 'too_short' );
154
        return ( 0, 'too_short' );
155
    }
155
    }
(-)a/Koha/Patron.pm (-1 / +1 lines)
Lines 736-742 sub set_password { Link Here
736
        if ( !$is_valid ) {
736
        if ( !$is_valid ) {
737
            if ( $error eq 'too_short' ) {
737
            if ( $error eq 'too_short' ) {
738
                my $min_length = C4::Context->preference('minPasswordLength');
738
                my $min_length = C4::Context->preference('minPasswordLength');
739
                $min_length = 3 if not $min_length or $min_length < 3;
739
                $min_length = 8 if not $min_length or $min_length < 8;
740
740
741
                my $password_length = length($password);
741
                my $password_length = length($password);
742
                Koha::Exceptions::Password::TooShort->throw(
742
                Koha::Exceptions::Password::TooShort->throw(
(-)a/installer/data/mysql/sysprefs.sql (-1 / +1 lines)
Lines 326-332 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
326
('MaxTotalSuggestions','',NULL,'Number of total suggestions used for time limit with NumberOfSuggestionDays','Free'),
326
('MaxTotalSuggestions','',NULL,'Number of total suggestions used for time limit with NumberOfSuggestionDays','Free'),
327
('MembershipExpiryDaysNotice','',NULL,'Send an account expiration notice that a patron\'s card is about to expire after','Integer'),
327
('MembershipExpiryDaysNotice','',NULL,'Send an account expiration notice that a patron\'s card is about to expire after','Integer'),
328
('MergeReportFields','',NULL,'Displayed fields for deleted MARC records after merge','Free'),
328
('MergeReportFields','',NULL,'Displayed fields for deleted MARC records after merge','Free'),
329
('minPasswordLength','3',NULL,'Specify the minimum length of a patron/staff password','free'),
329
('minPasswordLength','8',NULL,'Specify the minimum length of a patron/staff password','free'),
330
('NewItemsDefaultLocation','','','If set, all new items will have a location of the given Location Code ( Authorized Value type LOC )',''),
330
('NewItemsDefaultLocation','','','If set, all new items will have a location of the given Location Code ( Authorized Value type LOC )',''),
331
('NewsAuthorDisplay','none','none|opac|staff|both','Display the author name for news items.','Choice'),
331
('NewsAuthorDisplay','none','none|opac|staff|both','Display the author name for news items.','Choice'),
332
('noissuescharge','5','','Define maximum amount withstanding before check outs are blocked','Integer'),
332
('noissuescharge','5','','Define maximum amount withstanding before check outs are blocked','Integer'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt (+6 lines)
Lines 105-110 legend:hover { Link Here
105
                            </div>
105
                            </div>
106
                        [% END %]
106
                        [% END %]
107
107
108
                        [% IF Koha.Preference('minPasswordLength') < 8 %]
109
                            <div class="dialog alert">
110
                                <p><strong>Warning: </strong>The <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=minPasswordLength">minPasswordLength system preference</a> is less than 8 characters. This means library patrons can set unsecure passwords. Please set the <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=minPasswordLength">minPasswordLength system preference</a> to 8 or higher.</p>
111
                            </div>
112
                        [% END %]
113
108
                        [% IF ( nok ) %]
114
                        [% IF ( nok ) %]
109
                            <div class="dialog alert">
115
                            <div class="dialog alert">
110
                                <p>The following fields are wrong. Please fix them.</p>
116
                                <p>The following fields are wrong. Please fix them.</p>
(-)a/t/AuthUtils.t (-11 / +11 lines)
Lines 35-68 subtest 'is_password_valid' => sub { Link Here
35
    t::lib::Mocks::mock_preference('RequireStrongPassword', 0);
35
    t::lib::Mocks::mock_preference('RequireStrongPassword', 0);
36
    t::lib::Mocks::mock_preference('minPasswordLength', 0);
36
    t::lib::Mocks::mock_preference('minPasswordLength', 0);
37
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '12' );
37
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '12' );
38
    is( $is_valid, 0, 'min password size should be 3' );
38
    is( $is_valid, 0, 'min password size should be 8' );
39
    is( $error, 'too_short', 'min password size should be 3' );
39
    is( $error, 'too_short', 'min password size should be 8' );
40
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( ' 123' );
40
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( ' 12345678' );
41
    is( $is_valid, 0, 'password should not contain leading spaces' );
41
    is( $is_valid, 0, 'password should not contain leading spaces' );
42
    is( $error, 'has_whitespaces', 'password should not contain leading spaces' );
42
    is( $error, 'has_whitespaces', 'password should not contain leading spaces' );
43
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '123 ' );
43
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '12345678 ' );
44
    is( $is_valid, 0, 'password should not contain trailing spaces' );
44
    is( $is_valid, 0, 'password should not contain trailing spaces' );
45
    is( $error, 'has_whitespaces', 'password should not contain trailing spaces' );
45
    is( $error, 'has_whitespaces', 'password should not contain trailing spaces' );
46
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '123' );
46
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '12345678' );
47
    is( $is_valid, 1, 'min password size should be 3' );
47
    is( $is_valid, 1, 'min password size should be 8' );
48
48
49
    t::lib::Mocks::mock_preference('RequireStrongPassword', 1);
49
    t::lib::Mocks::mock_preference('RequireStrongPassword', 1);
50
    t::lib::Mocks::mock_preference('minPasswordLength', 8);
50
    t::lib::Mocks::mock_preference('minPasswordLength', 9);
51
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '12345678' );
51
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '123456789' );
52
    is( $is_valid, 0, 'password should be strong' );
52
    is( $is_valid, 0, 'password should be strong' );
53
    is( $error, 'too_weak', 'password should be strong' );
53
    is( $error, 'too_weak', 'password should be strong' );
54
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( 'abcd1234' );
54
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( 'abcd12345' );
55
    is( $is_valid, 0, 'strong password should contain uppercase' );
55
    is( $is_valid, 0, 'strong password should contain uppercase' );
56
    is( $error, 'too_weak', 'strong password should contain uppercase' );
56
    is( $error, 'too_weak', 'strong password should contain uppercase' );
57
57
58
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( 'abcD1234' );
58
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( 'abcD12345' );
59
    is( $is_valid, 1, 'strong password should contain uppercase' );
59
    is( $is_valid, 1, 'strong password should contain uppercase' );
60
};
60
};
61
61
62
subtest 'generate_password' => sub {
62
subtest 'generate_password' => sub {
63
    plan tests => 1;
63
    plan tests => 1;
64
    t::lib::Mocks::mock_preference('RequireStrongPassword', 1);
64
    t::lib::Mocks::mock_preference('RequireStrongPassword', 1);
65
    t::lib::Mocks::mock_preference('minPasswordLength', 8);
65
    t::lib::Mocks::mock_preference('minPasswordLength', 9);
66
    my $all_valid = 1;
66
    my $all_valid = 1;
67
    for ( 1 .. 10 ) {
67
    for ( 1 .. 10 ) {
68
        my $password = Koha::AuthUtils::generate_password;
68
        my $password = Koha::AuthUtils::generate_password;
(-)a/t/db_dependent/Koha/Patrons.t (-12 / +12 lines)
Lines 1788-1817 subtest '->set_password' => sub { Link Here
1788
    t::lib::Mocks::mock_preference( 'minPasswordLength', undef );
1788
    t::lib::Mocks::mock_preference( 'minPasswordLength', undef );
1789
    throws_ok { $patron->set_password({ password => 'ab' }); }
1789
    throws_ok { $patron->set_password({ password => 'ab' }); }
1790
        'Koha::Exceptions::Password::TooShort',
1790
        'Koha::Exceptions::Password::TooShort',
1791
        'minPasswordLength is undef, fall back to 3, fail test';
1791
        'minPasswordLength is undef, fall back to 8, fail test';
1792
    is( "$@",
1792
    is( "$@",
1793
        'Password length (2) is shorter than required (3)',
1793
        'Password length (2) is shorter than required (8)',
1794
        'Exception parameters passed correctly'
1794
        'Exception parameters passed correctly'
1795
    );
1795
    );
1796
1796
1797
    t::lib::Mocks::mock_preference( 'minPasswordLength', 2 );
1797
    t::lib::Mocks::mock_preference( 'minPasswordLength', 2 );
1798
    throws_ok { $patron->set_password({ password => 'ab' }); }
1798
    throws_ok { $patron->set_password({ password => 'ab' }); }
1799
        'Koha::Exceptions::Password::TooShort',
1799
        'Koha::Exceptions::Password::TooShort',
1800
        'minPasswordLength is 2, fall back to 3, fail test';
1800
        'minPasswordLength is 2, fall back to 8, fail test';
1801
1801
1802
    t::lib::Mocks::mock_preference( 'minPasswordLength', 5 );
1802
    t::lib::Mocks::mock_preference( 'minPasswordLength', 10 );
1803
    throws_ok { $patron->set_password({ password => 'abcb' }); }
1803
    throws_ok { $patron->set_password({ password => 'abcdefghi' }); }
1804
        'Koha::Exceptions::Password::TooShort',
1804
        'Koha::Exceptions::Password::TooShort',
1805
        'minPasswordLength is 5, fail test';
1805
        'minPasswordLength is 10, fail test';
1806
1806
1807
    # Trailing spaces tests
1807
    # Trailing spaces tests
1808
    throws_ok { $patron->set_password({ password => 'abcD12d   ' }); }
1808
    throws_ok { $patron->set_password({ password => 'abcDef12d   ' }); }
1809
        'Koha::Exceptions::Password::WhitespaceCharacters',
1809
        'Koha::Exceptions::Password::WhitespaceCharacters',
1810
        'Password contains trailing spaces, exception is thrown';
1810
        'Password contains trailing spaces, exception is thrown';
1811
1811
1812
    # Require strong password tests
1812
    # Require strong password tests
1813
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 1 );
1813
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 1 );
1814
    throws_ok { $patron->set_password({ password => 'abcd   a' }); }
1814
    throws_ok { $patron->set_password({ password => 'abcdef   a' }); }
1815
        'Koha::Exceptions::Password::TooWeak',
1815
        'Koha::Exceptions::Password::TooWeak',
1816
        'Password is too weak, exception is thrown';
1816
        'Password is too weak, exception is thrown';
1817
1817
Lines 1819-1825 subtest '->set_password' => sub { Link Here
1819
    $patron->discard_changes;
1819
    $patron->discard_changes;
1820
    is( $patron->login_attempts, 3, 'Previous tests kept login attemps count' );
1820
    is( $patron->login_attempts, 3, 'Previous tests kept login attemps count' );
1821
1821
1822
    $patron->set_password({ password => 'abcD12 34' });
1822
    $patron->set_password({ password => 'abcD12345e' });
1823
    $patron->discard_changes;
1823
    $patron->discard_changes;
1824
1824
1825
    is( $patron->login_attempts, 0, 'Changing the password resets the login attempts count' );
1825
    is( $patron->login_attempts, 0, 'Changing the password resets the login attempts count' );
Lines 1831-1841 subtest '->set_password' => sub { Link Here
1831
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
1831
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
1832
    $patron->login_attempts(3)->store;
1832
    $patron->login_attempts(3)->store;
1833
    my $old_digest = $patron->password;
1833
    my $old_digest = $patron->password;
1834
    $patron->set_password({ password => 'abcd   a' });
1834
    $patron->set_password({ password => 'abcd   abc' });
1835
    $patron->discard_changes;
1835
    $patron->discard_changes;
1836
1836
1837
    isnt( $patron->password, $old_digest, 'Password has been updated' );
1837
    isnt( $patron->password, $old_digest, 'Password has been updated' );
1838
    ok( checkpw_hash('abcd   a', $patron->password), 'Password hash is correct' );
1838
    ok( checkpw_hash('abcd   abc', $patron->password), 'Password hash is correct' );
1839
    is( $patron->login_attempts, 0, 'Login attemps have been reset' );
1839
    is( $patron->login_attempts, 0, 'Login attemps have been reset' );
1840
1840
1841
    my $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'CHANGE PASS', object => $patron->borrowernumber } )->count;
1841
    my $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'CHANGE PASS', object => $patron->borrowernumber } )->count;
Lines 1843-1849 subtest '->set_password' => sub { Link Here
1843
1843
1844
    # Enable logging password changes
1844
    # Enable logging password changes
1845
    t::lib::Mocks::mock_preference( 'BorrowersLog', 1 );
1845
    t::lib::Mocks::mock_preference( 'BorrowersLog', 1 );
1846
    $patron->set_password({ password => 'abcd   b' });
1846
    $patron->set_password({ password => 'abcd   babc' });
1847
1847
1848
    $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'CHANGE PASS', object => $patron->borrowernumber } )->count;
1848
    $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'CHANGE PASS', object => $patron->borrowernumber } )->count;
1849
    is( $number_of_logs, 1, 'With BorrowerLogs, Koha::Patron->set_password does log password changes' );
1849
    is( $number_of_logs, 1, 'With BorrowerLogs, Koha::Patron->set_password does log password changes' );
(-)a/t/db_dependent/api/v1/patrons_password.t (-9 / +8 lines)
Lines 45-54 subtest 'set() (authorized user tests)' => sub { Link Here
45
45
46
    my ( $patron, $session ) = create_user_and_session({ authorized => 1 });
46
    my ( $patron, $session ) = create_user_and_session({ authorized => 1 });
47
47
48
    t::lib::Mocks::mock_preference( 'minPasswordLength',     3 );
48
    t::lib::Mocks::mock_preference( 'minPasswordLength',     8 );
49
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
49
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
50
50
51
    my $new_password = 'abc';
51
    my $new_password = 'abcdefgh';
52
52
53
    my $tx
53
    my $tx
54
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
54
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
Lines 68-74 subtest 'set() (authorized user tests)' => sub { Link Here
68
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
68
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
69
    $t->request_ok($tx)->status_is(400)->json_is({ error => 'Passwords don\'t match' });
69
    $t->request_ok($tx)->status_is(400)->json_is({ error => 'Passwords don\'t match' });
70
70
71
    t::lib::Mocks::mock_preference( 'minPasswordLength', 5 );
71
    t::lib::Mocks::mock_preference( 'minPasswordLength', 10 );
72
    $tx
72
    $tx
73
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
73
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
74
            . $patron->id
74
            . $patron->id
Lines 76-84 subtest 'set() (authorized user tests)' => sub { Link Here
76
76
77
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
77
    $tx->req->cookies( { name => 'CGISESSID', value => $session->id } );
78
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
78
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
79
    $t->request_ok($tx)->status_is(400)->json_is({ error => 'Password length (3) is shorter than required (5)' });
79
    $t->request_ok($tx)->status_is(400)->json_is({ error => 'Password length (8) is shorter than required (10)' });
80
80
81
    $new_password = 'abc   ';
81
    $new_password = 'abcdefg   ';
82
    $tx
82
    $tx
83
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
83
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
84
            . $patron->id
84
            . $patron->id
Lines 88-94 subtest 'set() (authorized user tests)' => sub { Link Here
88
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
88
    $tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
89
    $t->request_ok($tx)->status_is(400)->json_is({ error => '[Password contains leading/trailing whitespace character(s)]' });
89
    $t->request_ok($tx)->status_is(400)->json_is({ error => '[Password contains leading/trailing whitespace character(s)]' });
90
90
91
    $new_password = 'abcdefg';
91
    $new_password = 'abcdefghijkl';
92
    $tx
92
    $tx
93
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
93
        = $t->ua->build_tx( POST => "/api/v1/patrons/"
94
            . $patron->id
94
            . $patron->id
Lines 134-143 subtest 'set_public() (unprivileged user tests)' => sub { Link Here
134
    t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
134
    t::lib::Mocks::mock_preference( 'RESTPublicAPI', 1 );
135
135
136
    t::lib::Mocks::mock_preference( 'OpacPasswordChange',    0 );
136
    t::lib::Mocks::mock_preference( 'OpacPasswordChange',    0 );
137
    t::lib::Mocks::mock_preference( 'minPasswordLength',     3 );
137
    t::lib::Mocks::mock_preference( 'minPasswordLength',     8 );
138
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
138
    t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
139
139
140
    my $new_password = 'abc';
140
    my $new_password = 'abcdefgh';
141
141
142
    my $tx = $t->ua->build_tx(
142
    my $tx = $t->ua->build_tx(
143
              POST => "/api/v1/public/patrons/"
143
              POST => "/api/v1/public/patrons/"
144
- 

Return to bug 18308