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

(-)a/installer/data/mysql/atomicupdate/bug_29925_password_reset.pl (+15 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
return {
4
    bug_number => "29925",
5
    description => "Add password reset option",
6
    up => sub {
7
        my ($args) = @_;
8
        my ($dbh, $out) = @$args{qw(dbh out)};
9
        $dbh->do(q{
10
            INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
11
            ('EnableExpiredPasswordReset', '0', NULL, 'Enable ability for patrons with expired password to reset their password directly', 'YesNo')
12
        });
13
        say $out "Added EnableExpirePasswordReset system preference";
14
    },
15
};
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (+8 lines)
Lines 365-370 Patrons: Link Here
365
               0: "Don't require"
365
               0: "Don't require"
366
         - a strong password for staff and patrons
366
         - a strong password for staff and patrons
367
         - (must contain at least one digit, one lowercase and one uppercase).
367
         - (must contain at least one digit, one lowercase and one uppercase).
368
     -
369
         - pref: EnableExpiredPasswordReset
370
           choices:
371
               1: "Enable"
372
               0: "Don't enable"
373
         - the ability for patrons to directly reset their password when it is expired.
374
         - If not enable patrons must either use the 'Forgot your password' feature or have staff
375
         - reset their password.
368
     -
376
     -
369
         - Block a patron's account if it reaches
377
         - Block a patron's account if it reaches
370
         - pref: FailedLoginAttempts
378
         - pref: FailedLoginAttempts
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt (-1 / +3 lines)
Lines 52-58 Link Here
52
    [% END %]
52
    [% END %]
53
[% ELSIF password_has_expired %]
53
[% ELSIF password_has_expired %]
54
    <div id="login_error"><strong>Error: </strong>Your password has expired!</div>
54
    <div id="login_error"><strong>Error: </strong>Your password has expired!</div>
55
    [% IF Categories.can_any_reset_password && Koha.Preference('OpacBaseURL') %]
55
    [% IF Koha.Preference('EnableExpiredPasswordReset') && Koha.Preference('OpacBaseURL') %]
56
        <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-reset-password.pl">You must reset your password</a>.
57
    [% ELSIF Categories.can_any_reset_password && Koha.Preference('OpacBaseURL') %]
56
        <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-password-recovery.pl">You must reset your password</a>.
58
        <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-password-recovery.pl">You must reset your password</a>.
57
    [% ELSE %]
59
    [% ELSE %]
58
        <p>You must contact the library to have your password reset</p>
60
        <p>You must contact the library to have your password reset</p>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt (-2 / +4 lines)
Lines 171-179 Link Here
171
                            <div class="alert alert-info">
171
                            <div class="alert alert-info">
172
                                <p><strong>Error: </strong>Your password has expired!</p>
172
                                <p><strong>Error: </strong>Your password has expired!</p>
173
                            </div>
173
                            </div>
174
                            [% IF Koha.Preference('OpacPasswordChange') && Categories.can_any_reset_password %]
174
                            [% IF Koha.Preference('EnableExpiredPasswordReset') %]
175
                                <a href="/cgi-bin/koha/opac-reset-password.pl">Reset your password</a>.
176
                            [% ELSIF Koha.Preference('OpacPasswordChange') && Categories.can_any_reset_password %]
175
                                <div id="resetpassword">
177
                                <div id="resetpassword">
176
                                    <a href="/cgi-bin/koha/opac-password-recovery.pl">Reset your password?</a>
178
                                    <a href="/cgi-bin/koha/opac-password-recovery.pl">Reset your password</a>
177
                                </div>
179
                                </div>
178
                            [% ELSE %]
180
                            [% ELSE %]
179
                                <p>You must contact the library to reset your password</p>
181
                                <p>You must contact the library to reset your password</p>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-reset-password.tt (+157 lines)
Line 0 Link Here
1
[% USE raw %]
2
[% USE Koha %]
3
[% USE Categories %]
4
[% USE AdditionalContents %]
5
[% PROCESS 'html_helpers.inc' %]
6
[% INCLUDE 'doc-head-open.inc' %]
7
<title>
8
    Reset your password
9
    &rsaquo;
10
 [% IF ( LibraryNameTitle ) %][% LibraryNameTitle | html %][% ELSE %]Koha online[% END %] catalog
11
</title>
12
[% INCLUDE 'doc-head-close.inc' %]
13
[% BLOCK cssinclude %][% END %]
14
</head>
15
[% INCLUDE 'bodytag.inc' bodyid='opac-login-page' bodyclass='scrollto' %]
16
[% INCLUDE 'masthead.inc' %]
17
18
<div class="main">
19
    <nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumbs">
20
        <ol class="breadcrumb">
21
            <li class="breadcrumb-item">
22
                <a href="/cgi-bin/koha/opac-main.pl">Home</a>
23
            </li>
24
            <li class="breadcrumb-item active">
25
                <a href="#" aria-current="page">Reset your password</a>
26
            </li>
27
        </
28
    </nav> <!-- /#breadcrumbs -->
29
30
    <div class="container-fluid">
31
        <div class="row justify-content-center">
32
            <div class="col-md-10 col-lg-6">
33
                <div id="opac-auth" class="maincontent">
34
                    [% IF Koha.Preference( 'opacuserlogin' ) && Koha.Preference('EnableExpiredPasswordReset') %]
35
                        [% IF ( error ) %]
36
                            <div class="alert alert-warning">
37
                                <h2>There was a problem with your submission</h2>
38
                                <p>
39
                                    [% SWITCH error %]
40
                                        [% CASE  'no_change' %]
41
                                            New password must not be the same as old password.
42
                                        [% CASE  'passwords_mismatch' %]
43
                                            Passwords do not match.  Please re-type your new password.
44
                                        [% CASE 'password_too_short' %]
45
                                            Password must be at least [% minPasswordLength | html %] characters long.
46
                                        [% CASE 'password_too_weak' %]
47
                                            Password must contain at least one digit, one lowercase and one uppercase.
48
                                        [% CASE 'password_has_whitespaces' %]
49
                                            Password must not contain leading or trailing whitespaces.
50
                                        [% CASE 'invalid_credentials' %]
51
                                            You entered an incorrect username or password. Please try again! But note that passwords are case sensitive[% IF Koha.Preference('FailedLoginAttempts') %] and that your account will be locked out after a fixed number of failed login attempts[% END %]. Please contact a library staff member if you continue to have problems.
52
                                        [% CASE 'no_expire' %]
53
                                            Please log-in to account to update your password.</br>
54
                                            <a href="/cgi-bin/koha/opac-user.pl" class="nav-link login-link loginModal-trigger"><i class="fa fa-user fa-icon-black fa-fw" aria-hidden="true"></i> <span class="userlabel">Log in to your account</span></a>
55
                                        [% CASE 'account_locked' %]
56
                                            This account has been locked!
57
                                            [% IF Categories.can_any_reset_password && Koha.Preference('OpacBaseURL') %]
58
                                                <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-password-recovery.pl">You must reset your password via e-mail</a>.
59
                                            [% ELSE %]
60
                                                You must contact the library for assistance
61
                                            [% END %]
62
                                        [% CASE %]
63
                                            An unknown error occurred. PLease try again or contact the library for assistance
64
                                    [% END %]
65
                                </p>
66
                            </div>
67
                        [% END %]
68
                        [% IF ( password_updated ) %]
69
                            <div class="alert dialog-alert">
70
                                <h2>Your password has successfully been updated</h2>
71
                                <a href="/cgi-bin/koha/opac-main.pl" class="btn btn-primary">Go to OPAC</a>
72
                                [% IF ( Koha.Preference('staffClientBaseURL') && staff_access ) %]
73
                                    <a href="[% Koha.Preference('staffClientBaseURL') | url %]" class="btn btn-primary">Go to Staff client</a>
74
                                [% END %]
75
                            </div>
76
                        [% ELSE %]
77
                        <form action="/cgi-bin/koha/opac-reset-password.pl" name="mainform" id="mainform" method="post" autocomplete="off">
78
                            <legend class="sr-only">Reset your password</legend>
79
80
                            <fieldset class="brief">
81
                                <div class="form-group">
82
                                    <label for="userid">Login:</label>
83
                                    <input class="form-control" type="text"  size="25" id="userid"  name="userid" />
84
                                </div>
85
                                <div class="form-group">
86
                                    <label for="currentpassword">Current password:</label>
87
                                    <input class="form-control" autocomplete="off" type="password"  size="25" id="currentpassword"  name="currentpassword" />
88
                                </div>
89
                                <div class="form-group">
90
                                    <label for="newpassword">New password:</label>
91
                                    <input class="form-control" autocomplete="off" type="password"  size="25" id="newpassword"  name="newpassword" />
92
                                </div>
93
                                <div class="form-group">
94
                                    <label for="confirmpassword">Confirm new password:</label>
95
                                    <input class="form-control" autocomplete="off" type="password"  size="25" id="confirmpassword"  name="confirmpassword" />
96
                                </div>
97
                                <fieldset class="action">
98
                                    <input type="submit" value="Update password" class="btn btn-primary" />
99
                                </fieldset>
100
                                <input type="hidden" name="op" value="update" />
101
                            </fieldset>
102
                            [% IF Koha.Preference('OpacPasswordChange') && Categories.can_any_reset_password %]
103
                                <div id="resetpassword">
104
                                    <a href="/cgi-bin/koha/opac-password-recovery.pl">Forgot your password?</a>
105
                                </div>
106
                            [% END %]
107
                        </form>
108
                        [% END # /IF Error_messages %]
109
110
                    [% ELSE %]
111
                        <h1>Resetting your password has not been enabled by the library.</h1>
112
                        [% IF Koha.Preference('OpacPasswordChange') && Categories.can_any_reset_password %]
113
                            <div id="resetpassword">
114
                                <a href="/cgi-bin/koha/opac-password-recovery.pl">Forgot your password?</a>
115
                            </div>
116
                        [% ELSE %]
117
                            <p>You must contact the library to reset your password</p>
118
                        [% END %]
119
                    [% END # / IF opacuserlogin %]
120
121
                </div> <!-- /.opac-auth -->
122
            </div> <!-- /.col-md-10 col-lg-6 -->
123
        </div> <!-- /.row -->
124
    </div> <!-- /.container-fluid -->
125
</div> <!-- /.main -->
126
127
[% INCLUDE 'opac-bottom.inc' %]
128
[% BLOCK jsinclude %]
129
    [% Asset.js("lib/jquery/plugins/jquery.validate.min.js") | $raw %]
130
    <script>
131
        jQuery.validator.addMethod("password_no_spaces", function(value, element){
132
            return ( this.optional(element) || !value.match(/^\s/) && !value.match(/\s$/) );
133
        }, _("Password contains leading and/or trailing spaces"));
134
        jQuery.validator.addMethod("password_match", function(value, element){
135
            var new_password_node = $("input[name='newpassword']:first");
136
            return value == $(new_password_node).val();
137
        }, _("Please enter the same password as above"));
138
139
        $(document).ready(function() {
140
            $("#mainform").validate({
141
                rules: {
142
                    currentpassword: {
143
                        required: true,
144
                    },
145
                    newpassword: {
146
                        required: true,
147
                        password_no_spaces: true
148
                    },
149
                    confirmpassword: {
150
                        required: true,
151
                        password_match: true
152
                    }
153
                }
154
            });
155
        });
156
    </script>
157
[% END %]
(-)a/opac/opac-reset-password.pl (-1 / +107 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# 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
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use CGI qw ( -utf8 );
21
22
use C4::Auth qw( get_template_and_user checkpw checkpw_hash );
23
use C4::Context;
24
use C4::Output qw( output_html_with_http_headers );
25
use Koha::Patrons;
26
27
use Try::Tiny qw( catch try );
28
29
my $query = CGI->new;
30
31
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
32
    {
33
        template_name   => "opac-reset-password.tt",
34
        query           => $query,
35
        type            => "opac",
36
        authnotrequired => 1,
37
    }
38
);
39
40
my $op = $query->param('op');
41
42
if ( $op eq 'update' ) {
43
    my $userid          = $query->param('userid');
44
    my $currentpassword = $query->param('currentpassword');
45
    my $newpassword     = $query->param('newpassword');
46
    my $confirmpassword = $query->param('confirmpassword');
47
48
    my $patron = Koha::Patrons->find( { userid => $userid } );
49
    $patron = Koha::Patrons->find( { cardnumber => $userid } ) unless $patron;
50
51
    if ( $patron && $patron->password_expiration_date ) {
52
        if ( $patron->account_locked ) {
53
            $template->param( error => 'account_locked' );
54
        }
55
        elsif ( $currentpassword && $newpassword && $confirmpassword ) {
56
            my $error;
57
            if ( C4::Auth::checkpw_hash( $currentpassword, $patron->password ) ) {
58
59
                if ( $newpassword ne $confirmpassword ) {
60
                    $template->param( 'error' => 'passwords_mismatch' );
61
                }
62
                elsif ( $currentpassword eq $newpassword ) {
63
                    $template->param( 'error' => 'no_change' );
64
                }
65
                else {
66
                    try {
67
                        $patron->set_password( { password => $newpassword } );
68
                        $template->param( 'password_updated' => '1' );
69
                        $template->param( 'staff_access'     => 1 )
70
                          if $patron->has_permission( { catalogue => 1 } );
71
                    }
72
                    catch {
73
                        $error = 'password_too_short'
74
                          if $_->isa('Koha::Exceptions::Password::TooShort');
75
                        $error = 'password_too_weak'
76
                          if $_->isa('Koha::Exceptions::Password::TooWeak');
77
                        $error = 'password_has_whitespaces'
78
                          if $_->isa(
79
                            'Koha::Exceptions::Password::WhitespaceCharacters');
80
                        $template->param( 'error' => $error );
81
                    };
82
                }
83
            }
84
            else {
85
                $template->param( 'error' => 'invalid_credentials' );
86
                $patron->update(
87
                    { login_attempts => $patron->login_attempts + 1 } )
88
                  if !$patron->account_locked;
89
            }
90
        }
91
        else {
92
            $template->param( 'incomplete_form' => '1' );
93
        }
94
    }
95
    elsif ( !$patron ) {
96
        template->param( 'error' => 'invalid_credentials' );
97
    }
98
    elsif ( !$patron->password_expiration_date ) {
99
        $template->param( 'error' => 'no_expire' );
100
    }
101
    else {
102
        $template->param( 'error' => 'unknown' );
103
    }
104
}
105
106
output_html_with_http_headers $query, $cookie, $template->output, undef,
107
  { force_no_caching => 1 };

Return to bug 29925