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

(-)a/Koha/AuthUtils.pm (+48 lines)
Lines 22-27 use Crypt::Eksblowfish::Bcrypt qw(bcrypt en_base64); Link Here
22
use Encode qw( encode is_utf8 );
22
use Encode qw( encode is_utf8 );
23
use Fcntl qw/O_RDONLY/; # O_RDONLY is used in generate_salt
23
use Fcntl qw/O_RDONLY/; # O_RDONLY is used in generate_salt
24
use List::MoreUtils qw/ any /;
24
use List::MoreUtils qw/ any /;
25
use String::Random qw( random_string );
26
27
use C4::Context;
25
28
26
use base 'Exporter';
29
use base 'Exporter';
27
30
Lines 134-139 sub generate_salt { Link Here
134
    return $string;
137
    return $string;
135
}
138
}
136
139
140
=head2 is_password_valid
141
142
my ( $is_valid, $error ) = is_password_valid( $password );
143
144
return $is_valid == 1 if the password match minPasswordLength and RequireStrongPassword conditions
145
otherwise return $is_valid == 0 and $error will contain the error ('too_short' or 'too_weak')
146
147
=cut
148
149
sub is_password_valid {
150
    my ($password) = @_;
151
    my $minPasswordLength = C4::Context->preference('minPasswordLength');
152
    $minPasswordLength = 3 if not $minPasswordLength or $minPasswordLength < 3;
153
    if ( length($password) < $minPasswordLength ) {
154
        return ( 0, 'too_short' );
155
    }
156
    elsif ( C4::Context->preference('RequireStrongPassword') ) {
157
        return ( 0, 'too_weak' )
158
          if $password !~ m|(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{$minPasswordLength,}|;
159
    }
160
    return ( 0, 'has_whitespaces' ) if $password =~ m[^\s|\s$];
161
    return ( 1, undef );
162
}
163
164
=head2 generate_password
165
166
my password = generate_password();
167
168
Generate a password according to the minPasswordLength and RequireStrongPassword.
169
170
=cut
171
172
sub generate_password {
173
    my $minPasswordLength = C4::Context->preference('minPasswordLength');
174
    $minPasswordLength = 8 if not $minPasswordLength or $minPasswordLength < 8;
175
176
    my ( $password, $is_valid );
177
    do {
178
        $password = random_string('.' x $minPasswordLength );
179
        ( $is_valid, undef ) = is_password_valid( $password );
180
    } while not $is_valid;
181
    return $password;
182
}
183
184
137
=head2 get_script_name
185
=head2 get_script_name
138
186
139
This returns the correct script name, for use in redirecting back to the correct page after showing
187
This returns the correct script name, for use in redirecting back to the correct page after showing
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-password.tt (-3 / +9 lines)
Lines 93-101 Link Here
93
		[% IF ( BADUSERID ) %]
93
		[% IF ( BADUSERID ) %]
94
        <li>You have entered a username that already exists. Please choose another one.</li>
94
        <li>You have entered a username that already exists. Please choose another one.</li>
95
		[% END %]
95
		[% END %]
96
		[% IF ( SHORTPASSWORD ) %]
96
        [% IF ( ERROR_password_too_short ) %]
97
		<li><strong>The password entered is too short</strong>. Password must be at least [% minPasswordLength %] characters.</li>
97
            <li id="ERROR_short_password">Password must be at least [% minPasswordLength %] characters long.</li>
98
		[% END %]
98
        [% END %]
99
        [% IF ( ERROR_password_too_weak ) %]
100
            <li id="ERROR_weak_password">Password must contain at least one digit, one lowercase and one uppercase.</li>
101
        [% END %]
102
        [% IF ( ERROR_password_has_whitespaces ) %]
103
            <li id="ERROR_weak_password">Password must not contain leading or trailing whitespaces.</li>
104
        [% END %]
99
		[% IF ( NOPERMISSION ) %]
105
		[% IF ( NOPERMISSION ) %]
100
		<li>You do not have permission to edit this patron's login information.</li>
106
		<li>You do not have permission to edit this patron's login information.</li>
101
		[% END %]
107
		[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt (-5 / +14 lines)
Lines 198-206 $(document).ready(function() { Link Here
198
			[% IF ( ERROR_dateexpiry ) %]
198
			[% IF ( ERROR_dateexpiry ) %]
199
				<li id="ERROR_dateexpiry">Date of expiration is invalid.</li>
199
				<li id="ERROR_dateexpiry">Date of expiration is invalid.</li>
200
			[% END %]
200
			[% END %]
201
			[% IF ( ERROR_short_password ) %]
201
            [% IF ( ERROR_password_too_short ) %]
202
				<li id="ERROR_short_password">Password must be at least [% minPasswordLength %] characters long.</li>
202
                <li id="ERROR_short_password">Password must be at least [% minPasswordLength %] characters long.</li>
203
			[% END %]
203
            [% END %]
204
            [% IF ( ERROR_password_too_weak ) %]
205
                <li id="ERROR_weak_password">Password must contain at least one digit, one lowercase and one uppercase.</li>
206
            [% END %]
207
            [% IF ( ERROR_password_has_whitespaces ) %]
208
                <li id="ERROR_weak_password">Password must not contain leading or trailing whitespaces.</li>
209
            [% END %]
204
			[% IF ( ERROR_password_mismatch ) %]
210
			[% IF ( ERROR_password_mismatch ) %]
205
				<li id="ERROR_password_mismatch">Passwords do not match.</li>
211
				<li id="ERROR_password_mismatch">Passwords do not match.</li>
206
			[% END %]
212
			[% END %]
Lines 887-894 $(document).ready(function() { Link Here
887
				[% END %]
893
				[% END %]
888
			[% END %]
894
			[% END %]
889
			[% END %]
895
			[% END %]
890
	  [% IF ( mandatorypassword ) %]<span class="required">Required</span>[% END %][% IF ( ERROR_short_password ) %]<span class="required">Password is too short</span>[% END %]
896
            [% IF ( mandatorypassword ) %]<span class="required">Required</span>[% END %]
891
    <div class="hint">Minimum password length: [% minPasswordLength %]</div>
897
            [% IF ( ERROR_password_too_short ) %]<span class="required">Password is too short</span>[% END %]
898
            [% IF ( ERROR_password_too_weak ) %]<span class="required">Password is too weak</span>[% END %]
899
            [% IF ( ERROR_password_has_whitespaces ) %]<span class="required">Password has leading or trailing whitespaces</span>[% END %]
900
            <div class="hint">Minimum password length: [% minPasswordLength %]</div>
892
		</li>
901
		</li>
893
		<li>
902
		<li>
894
			[% IF ( mandatorypassword ) %]
903
			[% IF ( mandatorypassword ) %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt (-2 / +9 lines)
Lines 63-70 Link Here
63
                                [% IF field == "emailpro" %]<li>Contact information: <a href="#borrower_emailpro">secondary email address</a></li>[% END %]
63
                                [% IF field == "emailpro" %]<li>Contact information: <a href="#borrower_emailpro">secondary email address</a></li>[% END %]
64
                                [% IF field == "B_email" %]<li>Alternate address information: <a href="#borrower_B_email">email address</a></li>[% END %]
64
                                [% IF field == "B_email" %]<li>Alternate address information: <a href="#borrower_B_email">email address</a></li>[% END %]
65
                                [% IF field == "password_match" %]<li>Passwords do not match! <a href="#password">password</a></li>[% END %]
65
                                [% IF field == "password_match" %]<li>Passwords do not match! <a href="#password">password</a></li>[% END %]
66
                                [% IF field == "password_invalid" %]<li>Password does not meet minimum requirements! <a href="#password">password</a></li>[% END %]
66
                                [% IF field == "password_too_short" %]
67
                                [% IF field == "password_spaces" %]<li>Password contains leading and/or trailing spaces! <a href="#password">password</a></li>[% END %]
67
                                    <li>Password must be at least [% minPasswordLength %] characters long.</li>
68
                                [% END %]
69
                                [% IF field == "password_too_weak" %]
70
                                    <li>Password must contain at least one digit, one lowercase and one uppercase.</li>
71
                                [% END %]
72
                                [% IF field == "password_has_whitespaces" %]
73
                                    <li>Password must not contain leading or trailing whitespaces.</li>
74
                                [% END %]
68
                                [% IF field == "duplicate_email" %]
75
                                [% IF field == "duplicate_email" %]
69
                                    <li>This email address already exists in our database.</li>
76
                                    <li>This email address already exists in our database.</li>
70
                                [% END %]
77
                                [% END %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-passwd.tt (-6 / +10 lines)
Lines 29-46 Link Here
29
                        <div class="alert">
29
                        <div class="alert">
30
                            <h3>There was a problem with your submission</h3>
30
                            <h3>There was a problem with your submission</h3>
31
                            <p>
31
                            <p>
32
                                [% IF ( PassMismatch ) %]
32
                                [% IF ( passwords_mismatch ) %]
33
                                Passwords do not match.  Please re-type your new password.
33
                                Passwords do not match.  Please re-type your new password.
34
                                [% END %]
34
                                [% END %]
35
                                [% IF ( ShortPass ) %]
35
                                [% IF password_too_short %]
36
                                Your new password must be at least [% minPasswordLength%] characters long.
36
                                    Password must be at least [% minPasswordLength %] characters long.
37
                                [% END %]
37
                                [% END %]
38
                                [% IF password_too_weak %]
39
                                    Password must contain at least one digit, one lowercase and one uppercase.
40
                                [% END %]
41
                                [% IF password_has_whitespaces %]
42
                                    Password must not contain leading or trailing whitespaces.
43
                                [% END %]
44
38
                                [% IF ( WrongPass ) %]
45
                                [% IF ( WrongPass ) %]
39
                                Your current password was entered incorrectly.  If this problem persists, please ask a librarian to reset your password for you.
46
                                Your current password was entered incorrectly.  If this problem persists, please ask a librarian to reset your password for you.
40
                                [% END %]
47
                                [% END %]
41
                                [% IF PasswordContainsTrailingSpaces %]
42
                                    Your password contains leading and/or trailing spaces.
43
                                [% END %]
44
                            </p>
48
                            </p>
45
                        </div>
49
                        </div>
46
                    [% END # /IF Error_messages %]
50
                    [% END # /IF Error_messages %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt (-4 / +7 lines)
Lines 60-68 Link Here
60
                        <br/>If you did not receive this email, you can request a new one: <a href="/cgi-bin/koha/opac-password-recovery.pl?resendEmail=true&email=[% email %]&username=[% username %]">Get new password recovery link</a>
60
                        <br/>If you did not receive this email, you can request a new one: <a href="/cgi-bin/koha/opac-password-recovery.pl?resendEmail=true&email=[% email %]&username=[% username %]">Get new password recovery link</a>
61
                    [% ELSIF (errPassNotMatch) %]
61
                    [% ELSIF (errPassNotMatch) %]
62
                        The passwords do not match.
62
                        The passwords do not match.
63
                    [% ELSIF (errPassTooShort) %]
63
                    [% ELSIF password_too_short %]
64
                        Your chosen password is too short.
64
                        <li>Password must be at least [% minPasswordLength %] characters long.</li>
65
                        <br/>The password must contain at least [% minPassLength %] characters.
65
                    [% ELSIF password_too_weak %]
66
                        <li>Password must contain at least one digit, one lowercase and one uppercase.</li>
67
                    [% ELSIF password_has_whitespaces %]
68
                        <li>Password must not contain leading or trailing whitespaces.</li>
66
                    [% ELSIF (errLinkNotValid) %]
69
                    [% ELSIF (errLinkNotValid) %]
67
                        The link you clicked is either invalid, or expired.
70
                        The link you clicked is either invalid, or expired.
68
                        <br/>Be sure you used the link from the email, or contact library staff for assistance.
71
                        <br/>Be sure you used the link from the email, or contact library staff for assistance.
Lines 92-98 Link Here
92
                    <form action="/cgi-bin/koha/opac-password-recovery.pl" method="post">
95
                    <form action="/cgi-bin/koha/opac-password-recovery.pl" method="post">
93
                        <input type="hidden" name="koha_login_context" value="opac" />
96
                        <input type="hidden" name="koha_login_context" value="opac" />
94
                        <fieldset>
97
                        <fieldset>
95
                            <div class="alert alert-info">The password must contain at least [% minPassLength %] characters.</div>
98
                            <div class="alert alert-info">The password must contain at least [% minPasswordLength %] characters.</div>
96
                            <label for="password">New password:</label>
99
                            <label for="password">New password:</label>
97
                            <input type="password" id="password" size="40" name="password" />
100
                            <input type="password" id="password" size="40" name="password" />
98
                            <label for="repeatPassword">Confirm new password:</label>
101
                            <label for="repeatPassword">Confirm new password:</label>
(-)a/members/member-password.pl (-4 / +10 lines)
Lines 15-20 use C4::Members; Link Here
15
use C4::Circulation;
15
use C4::Circulation;
16
use CGI qw ( -utf8 );
16
use CGI qw ( -utf8 );
17
use C4::Members::Attributes qw(GetBorrowerAttributes);
17
use C4::Members::Attributes qw(GetBorrowerAttributes);
18
use Koha::AuthUtils;
18
use Koha::Patron::Images;
19
use Koha::Patron::Images;
19
use Koha::Token;
20
use Koha::Token;
20
21
Lines 62-72 if ( ( $member ne $loggedinuser ) && ( $bor->{'category_type'} eq 'S' ) ) { Link Here
62
63
63
push( @errors, 'NOMATCH' ) if ( ( $newpassword && $newpassword2 ) && ( $newpassword ne $newpassword2 ) );
64
push( @errors, 'NOMATCH' ) if ( ( $newpassword && $newpassword2 ) && ( $newpassword ne $newpassword2 ) );
64
65
65
my $minpw = C4::Context->preference('minPasswordLength');
66
if ( $newpassword and not @errors ) {
66
$minpw = 3 if not $minpw or $minpw < 3;
67
    my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $newpassword );
67
push( @errors, 'SHORTPASSWORD' ) if ( $newpassword && $minpw && ( length($newpassword) < $minpw ) );
68
    unless ( $is_valid ) {
69
        push @errors, 'ERROR_password_too_short' if $error eq 'too_short';
70
        push @errors, 'ERROR_password_too_weak' if $error eq 'too_weak';
71
        push @errors, 'ERROR_password_has_whitespaces' if $error eq 'has_whitespaces';
72
    }
73
}
68
74
69
if ( $newpassword && !scalar(@errors) ) {
75
if ( $newpassword and not @errors) {
70
76
71
    die "Wrong CSRF token"
77
    die "Wrong CSRF token"
72
        unless Koha::Token->new->check_csrf({
78
        unless Koha::Token->new->check_csrf({
(-)a/members/memberentry.pl (-4 / +11 lines)
Lines 39-44 use C4::Koha; Link Here
39
use C4::Log;
39
use C4::Log;
40
use C4::Letters;
40
use C4::Letters;
41
use C4::Form::MessagingPreferences;
41
use C4::Form::MessagingPreferences;
42
use Koha::AuthUtils;
42
use Koha::AuthorisedValues;
43
use Koha::AuthorisedValues;
43
use Koha::Patron::Debarments;
44
use Koha::Patron::Debarments;
44
use Koha::Cities;
45
use Koha::Cities;
Lines 343-355 if ($op eq 'save' || $op eq 'insert'){ Link Here
343
  unless (Check_Userid($userid,$borrowernumber)) {
344
  unless (Check_Userid($userid,$borrowernumber)) {
344
    push @errors, "ERROR_login_exist";
345
    push @errors, "ERROR_login_exist";
345
  }
346
  }
346
  
347
347
  my $password = $input->param('password');
348
  my $password = $input->param('password');
348
  my $password2 = $input->param('password2');
349
  my $password2 = $input->param('password2');
349
  push @errors, "ERROR_password_mismatch" if ( $password ne $password2 );
350
  push @errors, "ERROR_password_mismatch" if ( $password ne $password2 );
350
  my $minpw = C4::Context->preference('minPasswordLength');
351
351
  $minpw = 3 if not $minpw or $minpw < 3;
352
  if ( $password and $password ne '****' ) {
352
  push @errors, "ERROR_short_password" if( $password && $minpw && $password ne '****' && (length($password) < $minpw) );
353
      my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $password );
354
      unless ( $is_valid ) {
355
          push @errors, 'ERROR_password_too_short' if $error eq 'too_short';
356
          push @errors, 'ERROR_password_too_weak' if $error eq 'too_weak';
357
          push @errors, 'ERROR_password_has_whitespaces' if $error eq 'has_whitespaces';
358
      }
359
  }
353
360
354
  # Validate emails
361
  # Validate emails
355
  my $emailprimary = $input->param('email');
362
  my $emailprimary = $input->param('email');
(-)a/opac/opac-memberentry.pl (-7 / +8 lines)
Lines 26-31 use C4::Auth; Link Here
26
use C4::Output;
26
use C4::Output;
27
use C4::Members;
27
use C4::Members;
28
use C4::Form::MessagingPreferences;
28
use C4::Form::MessagingPreferences;
29
use Koha::AuthUtils;
29
use Koha::Patrons;
30
use Koha::Patrons;
30
use Koha::Patron::Modification;
31
use Koha::Patron::Modification;
31
use Koha::Patron::Modifications;
32
use Koha::Patron::Modifications;
Lines 144-150 if ( $action eq 'create' ) { Link Here
144
                $verification_token = md5_hex( time().{}.rand().{}.$$ );
145
                $verification_token = md5_hex( time().{}.rand().{}.$$ );
145
            }
146
            }
146
147
147
            $borrower{password}           = random_string("..........");
148
            $borrower{password}           = Koha::AuthUtils::generate_password;
148
            $borrower{verification_token} = $verification_token;
149
            $borrower{verification_token} = $verification_token;
149
150
150
            Koha::Patron::Modification->new( \%borrower )->store();
151
            Koha::Patron::Modification->new( \%borrower )->store();
Lines 365-372 sub CheckMandatoryFields { Link Here
365
}
366
}
366
367
367
sub CheckForInvalidFields {
368
sub CheckForInvalidFields {
368
    my $minpw = C4::Context->preference('minPasswordLength');
369
    $minpw = 3 if not $minpw or $minpw < 3;
370
    my $borrower = shift;
369
    my $borrower = shift;
371
    my @invalidFields;
370
    my @invalidFields;
372
    if ($borrower->{'email'}) {
371
    if ($borrower->{'email'}) {
Lines 388-398 sub CheckForInvalidFields { Link Here
388
    if ( $borrower->{'password'} ne $borrower->{'password2'} ){
387
    if ( $borrower->{'password'} ne $borrower->{'password2'} ){
389
        push(@invalidFields, "password_match");
388
        push(@invalidFields, "password_match");
390
    }
389
    }
391
    if ( $borrower->{'password'}  && $minpw && (length($borrower->{'password'}) < $minpw) ) {
392
       push(@invalidFields, "password_invalid");
393
    }
394
    if ( $borrower->{'password'} ) {
390
    if ( $borrower->{'password'} ) {
395
       push(@invalidFields, "password_spaces") if ($borrower->{'password'} =~ /^\s/ or $borrower->{'password'} =~ /\s$/);
391
        my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $borrower->{password} );
392
          unless ( $is_valid ) {
393
              push @invalidFields, 'password_too_short' if $error eq 'too_short';
394
              push @invalidFields, 'password_too_weak' if $error eq 'too_weak';
395
              push @invalidFields, 'password_has_whitespaces' if $error eq 'has_whitespaces';
396
          }
396
    }
397
    }
397
398
398
    return \@invalidFields;
399
    return \@invalidFields;
(-)a/opac/opac-passwd.pl (-29 / +28 lines)
Lines 45-91 my ( $template, $borrowernumber, $cookie ) = get_template_and_user( Link Here
45
);
45
);
46
46
47
my $borr = C4::Members::GetMember( borrowernumber => $borrowernumber );
47
my $borr = C4::Members::GetMember( borrowernumber => $borrowernumber );
48
my $minpasslen = C4::Context->preference("minPasswordLength");
49
$minpasslen = 3 if not $minpasslen or $minpasslen < 3;
50
if ( C4::Context->preference("OpacPasswordChange") ) {
48
if ( C4::Context->preference("OpacPasswordChange") ) {
51
    my $sth =  $dbh->prepare("UPDATE borrowers SET password = ? WHERE borrowernumber=?");
49
    my $sth =  $dbh->prepare("UPDATE borrowers SET password = ? WHERE borrowernumber=?");
52
    if (   $query->param('Oldkey')
50
    if (   $query->param('Oldkey')
53
        && $query->param('Newkey')
51
        && $query->param('Newkey')
54
        && $query->param('Confirm') )
52
        && $query->param('Confirm') )
55
    {
53
    {
54
        my $error;
55
        my $new_password = $query->param('Newkey');
56
        my $confirm_password = $query->param('Confirm');
56
        if ( goodkey( $dbh, $borrowernumber, $query->param('Oldkey') ) ) {
57
        if ( goodkey( $dbh, $borrowernumber, $query->param('Oldkey') ) ) {
57
            if ( $query->param('Newkey') =~ m|^\s+| or $query->param('Newkey') =~ m|\s+$| ) {
58
58
                $template->param(
59
            if ( $new_password ne $confirm_password ) {
59
                    Error_messages => 1,
60
                    PasswordContainsTrailingSpaces => 1,
61
                );
62
            }
63
            elsif ( $query->param('Newkey') eq $query->param('Confirm')
64
                && length( $query->param('Confirm') ) >= $minpasslen )
65
            {    # Record password
66
                my $clave = hash_password( $query->param('Newkey') );
67
                $sth->execute( $clave, $borrowernumber );
68
                $template->param( 'password_updated' => '1' );
69
                $template->param( 'borrowernumber'   => $borrowernumber );
70
            }
71
            elsif ( $query->param('Newkey') ne $query->param('Confirm') ) {
72
                $template->param( 'Ask_data'       => '1' );
73
                $template->param( 'Error_messages' => '1' );
74
                $template->param( 'PassMismatch'   => '1' );
75
            }
76
            elsif ( length( $query->param('Confirm') ) < $minpasslen ) {
77
                $template->param( 'Ask_data'       => '1' );
60
                $template->param( 'Ask_data'       => '1' );
78
                $template->param( 'Error_messages' => '1' );
61
                $template->param( 'Error_messages' => '1' );
79
                $template->param( 'ShortPass'      => '1' );
62
                $template->param( 'passwords_mismatch'   => '1' );
80
            }
63
            } else {
81
            else {
64
                my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $new_password );
82
                $template->param( 'Error_messages' => '1' );
65
                unless ( $is_valid ) {
66
                    $error = 'password_too_short' if $error eq 'too_short';
67
                    $error = 'password_too_weak' if $error eq 'too_weak';
68
                    $error = 'password_has_whitespaces' if $error eq 'has_whitespaces';
69
                } else {
70
                    # Password is valid and match
71
                    my $clave = hash_password( $new_password );
72
                    $sth->execute( $clave, $borrowernumber );
73
                    $template->param( 'password_updated' => '1' );
74
                    $template->param( 'borrowernumber'   => $borrowernumber );
75
                }
83
            }
76
            }
84
        }
77
        }
85
        else {
78
        else {
86
            $template->param( 'Ask_data'       => '1' );
79
            $error = 'WrongPass';
87
            $template->param( 'Error_messages' => '1' );
80
        }
88
            $template->param( 'WrongPass'      => '1' );
81
        if ($error) {
82
            $template->param(
83
                Ask_data       => 1,
84
                Error_messages => 1,
85
                $error         => 1,
86
            );
87
89
        }
88
        }
90
    }
89
    }
91
    else {
90
    else {
(-)a/opac/opac-password-recovery.pl (-32 / +25 lines)
Lines 45-52 my $errBadEmail; Link Here
45
45
46
#new password form error
46
#new password form error
47
my $errLinkNotValid;
47
my $errLinkNotValid;
48
my $errPassNotMatch;
49
my $errPassTooShort;
50
48
51
if ( $query->param('sendEmail') || $query->param('resendEmail') ) {
49
if ( $query->param('sendEmail') || $query->param('resendEmail') ) {
52
50
Lines 132-169 if ( $query->param('sendEmail') || $query->param('resendEmail') ) { Link Here
132
elsif ( $query->param('passwordReset') ) {
130
elsif ( $query->param('passwordReset') ) {
133
    ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
131
    ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
134
132
135
    my $minPassLength = C4::Context->preference('minPasswordLength');
133
    my $error;
136
    $minPassLength = 3 if not $minPassLength or $minPassLength < 3;
134
    if ( not $borrower_number ) {
137
    #validate password length & match
135
        $error = 'errLinkNotValid';
138
    if (   ($borrower_number)
136
    } elsif ( $password ne $repeatPassword ) {
139
        && ( $password eq $repeatPassword )
137
        $error = 'errPassNotMatch';
140
        && ( length($password) >= $minPassLength ) )
138
    } else {
141
    {    #apply changes
139
        my ( $is_valid, $err) = Koha::AuthUtils::is_password_valid( $password );
142
        Koha::Patrons->find($borrower_number)->update_password( $username, hash_password($password) );
140
        unless ( $is_valid ) {
143
        CompletePasswordRecovery($uniqueKey);
141
            $error = 'password_too_short' if $err eq 'too_short';
144
        $template->param(
142
            $error = 'password_too_weak' if $err eq 'too_weak';
145
            password_reset_done => 1,
143
            $error = 'password_has_whitespaces' if $err eq 'has_whitespaces';
146
            username            => $username
144
        } else {
147
        );
145
            Koha::Patrons->find($borrower_number)->update_password( $username, hash_password($password) );
148
    }
146
            CompletePasswordRecovery($uniqueKey);
149
    else {    #errors
147
            $template->param(
150
        if ( !$borrower_number ) {    #parameters not valid
148
                password_reset_done => 1,
151
            $errLinkNotValid = 1;
149
                username            => $username
152
        }
150
            );
153
        elsif ( $password ne $repeatPassword ) {    #passwords does not match
154
            $errPassNotMatch = 1;
155
        }
156
        elsif ( length($password) < $minPassLength ) {    #password too short
157
            $errPassTooShort = 1;
158
        }
151
        }
152
    }
153
    if ( $error ) {
159
        $template->param(
154
        $template->param(
160
            new_password    => 1,
155
            new_password => 1,
161
            email           => $email,
156
            email        => $email,
162
            uniqueKey       => $uniqueKey,
157
            uniqueKey    => $uniqueKey,
163
            errLinkNotValid => $errLinkNotValid,
158
            hasError     => 1,
164
            errPassNotMatch => $errPassNotMatch,
159
            $error       => 1,
165
            errPassTooShort => $errPassTooShort,
166
            hasError        => 1
167
        );
160
        );
168
    }
161
    }
169
}
162
}
(-)a/t/AuthUtils.t (-2 / +48 lines)
Lines 1-6 Link Here
1
# This file is part of Koha.
1
# This file is part of Koha.
2
#
2
#
3
# Copyright (C) 2013 Equinox Software, Inc.
3
# Copyright (C) 2013 Equinox Software, Inc.
4
# Copyright 2017 Koha Development Team
4
#
5
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# under the terms of the GNU General Public License as published by
Lines 16-26 Link Here
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
18
use Modern::Perl;
19
use Modern::Perl;
19
use Test::More tests => 1;
20
use Test::More tests => 3;
20
21
22
use t::lib::Mocks;
21
use Koha::AuthUtils qw/hash_password/;
23
use Koha::AuthUtils qw/hash_password/;
22
24
23
my $hash1 = hash_password('password');
25
my $hash1 = hash_password('password');
24
my $hash2 = hash_password('password');
26
my $hash2 = hash_password('password');
25
27
26
ok($hash1 ne $hash2, 'random salts used when generating password hash');
28
ok($hash1 ne $hash2, 'random salts used when generating password hash');
27
- 
29
30
subtest 'is_password_valid' => sub {
31
    plan tests => 12;
32
33
    my ( $is_valid, $error );
34
35
    t::lib::Mocks::mock_preference('RequireStrongPassword', 0);
36
    t::lib::Mocks::mock_preference('minPasswordLength', 0);
37
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '12' );
38
    is( $is_valid, 0, 'min password size should be 3' );
39
    is( $error, 'too_short', 'min password size should be 3' );
40
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( ' 123' );
41
    is( $is_valid, 0, '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 ' );
44
    is( $is_valid, 0, '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' );
47
    is( $is_valid, 1, 'min password size should be 3' );
48
49
    t::lib::Mocks::mock_preference('RequireStrongPassword', 1);
50
    t::lib::Mocks::mock_preference('minPasswordLength', 8);
51
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( '12345678' );
52
    is( $is_valid, 0, 'password should be strong' );
53
    is( $error, 'too_weak', 'password should be strong' );
54
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( 'abcd1234' );
55
    is( $is_valid, 0, 'strong password should contain uppercase' );
56
    is( $error, 'too_weak', 'strong password should contain uppercase' );
57
58
    ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( 'abcD1234' );
59
    is( $is_valid, 1, 'strong password should contain uppercase' );
60
};
61
62
subtest 'generate_password' => sub {
63
    plan tests => 1;
64
    t::lib::Mocks::mock_preference('RequireStrongPassword', 1);
65
    t::lib::Mocks::mock_preference('minPasswordLength', 8);
66
    my $all_valid = 1;
67
    for ( 1 .. 10 ) {
68
        my $password = Koha::AuthUtils::generate_password;
69
        my ( $is_valid, undef ) = Koha::AuthUtils::is_password_valid( $password );
70
        $all_valid = 0 unless $is_valid;
71
    }
72
    is ( $all_valid, 1, 'generate_password should generate valid passwords' );
73
};

Return to bug 18298