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

(-)a/C4/Auth.pm (-3 / +9 lines)
Lines 966-971 sub checkauth { Link Here
966
                $info{oldip}        = $more_info->{old_ip};
966
                $info{oldip}        = $more_info->{old_ip};
967
                $info{newip}        = $more_info->{new_ip};
967
                $info{newip}        = $more_info->{new_ip};
968
                $info{different_ip} = 1;
968
                $info{different_ip} = 1;
969
            } elsif ( $return eq 'password_expired' ) {
970
                $info{password_has_expired} = 1;
969
            }
971
            }
970
        }
972
        }
971
    }
973
    }
Lines 1404-1410 sub checkauth { Link Here
1404
        PatronSelfRegistration                => C4::Context->preference("PatronSelfRegistration"),
1406
        PatronSelfRegistration                => C4::Context->preference("PatronSelfRegistration"),
1405
        PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"),
1407
        PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"),
1406
        opac_css_override                     => $ENV{'OPAC_CSS_OVERRIDE'},
1408
        opac_css_override                     => $ENV{'OPAC_CSS_OVERRIDE'},
1407
        too_many_login_attempts               => ( $patron and $patron->account_locked )
1409
        too_many_login_attempts               => ( $patron and $patron->account_locked ),
1410
        password_has_expired                  => ( $patron and $patron->password_expired )
1408
    );
1411
    );
1409
1412
1410
    $template->param( SCO_login => 1 ) if ( $query->param('sco_user_login') );
1413
    $template->param( SCO_login => 1 ) if ( $query->param('sco_user_login') );
Lines 1792-1797 sub check_cookie_auth { Link Here
1792
1795
1793
        } elsif ( $userid ) {
1796
        } elsif ( $userid ) {
1794
            $session->param( 'lasttime', time() );
1797
            $session->param( 'lasttime', time() );
1798
            my $patron = Koha::Patrons->find({ userid => $userid });
1799
            $patron = Koha::Patron->find({ cardnumber => $userid }) unless $patron;
1800
            return ("password_expired", undef ) if $patron->password_expired;
1795
            my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1;
1801
            my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1;
1796
            if ($flags) {
1802
            if ($flags) {
1797
                C4::Context->_new_userenv($sessionID);
1803
                C4::Context->_new_userenv($sessionID);
Lines 1903-1910 sub checkpw { Link Here
1903
    # 0 if auth is nok
1909
    # 0 if auth is nok
1904
    # -1 if user bind failed (LDAP only)
1910
    # -1 if user bind failed (LDAP only)
1905
1911
1906
    if ( $patron and $patron->account_locked ) {
1912
    if ( $patron and ( $patron->account_locked || $patron->password_expired )  ) {
1907
        # Nothing to check, account is locked
1913
        # Nothing to check, account is locked or password expired
1908
    } elsif ($ldap && defined($password)) {
1914
    } elsif ($ldap && defined($password)) {
1909
        my ( $retval, $retcard, $retuserid ) = checkpw_ldap(@_);    # EXTERNAL AUTH
1915
        my ( $retval, $retcard, $retuserid ) = checkpw_ldap(@_);    # EXTERNAL AUTH
1910
        if ( $retval == 1 ) {
1916
        if ( $retval == 1 ) {
(-)a/Koha/Patron.pm (+20 lines)
Lines 267-272 sub store { Link Here
267
                # Make a copy of the plain text password for later use
267
                # Make a copy of the plain text password for later use
268
                $self->plain_text_password( $self->password );
268
                $self->plain_text_password( $self->password );
269
269
270
                $self->password_expiration_date( $self->password
271
                    ? $self->category->get_password_expiry_date
272
                    : undef );
270
                # Create a disabled account if no password provided
273
                # Create a disabled account if no password provided
271
                $self->password( $self->password
274
                $self->password( $self->password
272
                    ? Koha::AuthUtils::hash_password( $self->password )
275
                    ? Koha::AuthUtils::hash_password( $self->password )
Lines 787-792 sub is_expired { Link Here
787
    return 0;
790
    return 0;
788
}
791
}
789
792
793
=head3 password_expired
794
795
my $password_expired = $patron->password_expired;
796
797
Returns 1 if the patron's password is expired or 0;
798
799
=cut
800
801
sub password_expired {
802
    my ($self) = @_;
803
    return 0 unless $self->password_expiration_date;
804
    return 1 if dt_from_string( $self->password_expiration_date ) < dt_from_string->truncate( to => 'day' );
805
    return 0;
806
}
807
790
=head3 is_going_to_expire
808
=head3 is_going_to_expire
791
809
792
my $is_going_to_expire = $patron->is_going_to_expire;
810
my $is_going_to_expire = $patron->is_going_to_expire;
Lines 886-891 sub set_password { Link Here
886
904
887
    my $digest = Koha::AuthUtils::hash_password($password);
905
    my $digest = Koha::AuthUtils::hash_password($password);
888
906
907
    $self->password_expiration_date( $self->category->get_password_expiry_date );
908
889
    # We do not want to call $self->store and retrieve password from DB
909
    # We do not want to call $self->store and retrieve password from DB
890
    $self->password($digest);
910
    $self->password($digest);
891
    $self->login_attempts(0);
911
    $self->login_attempts(0);
(-)a/Koha/Patron/Category.pm (+20 lines)
Lines 113-118 sub get_expiry_date { Link Here
113
    }
113
    }
114
}
114
}
115
115
116
=head3 get_password_expiry_date
117
118
Returns date based on password expiry days set for the category. If the value is not set
119
we return undef, password does not expire
120
121
my $expiry_date = $category->get_password_expiry_date();
122
123
=cut
124
125
sub get_password_expiry_date {
126
    my ($self, $date ) = @_;
127
    if ( $self->password_expiry_days ) {
128
        $date ||= dt_from_string;
129
        $date = dt_from_string( $date ) unless ref $date;
130
        return $date->add( days => $self->password_expiry_days )->ymd;
131
    } else {
132
        return;
133
    }
134
}
135
116
=head3 effective_reset_password
136
=head3 effective_reset_password
117
137
118
Returns if patrons in this category can reset their password. If set in $self->reset_password
138
Returns if patrons in this category can reset their password. If set in $self->reset_password
(-)a/Koha/REST/V1/Auth.pm (-1 / +6 lines)
Lines 491-497 sub _basic_auth { Link Here
491
        Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Invalid password' );
491
        Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Invalid password' );
492
    }
492
    }
493
493
494
    return Koha::Patrons->find({ userid => $user_id });
494
    my $patron = Koha::Patrons->find({ userid => $user_id });
495
    if ( $patron->password_expired ) {
496
        Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Password has expired' );
497
    }
498
499
    return $patron;
495
}
500
}
496
501
497
=head3 _set_userenv
502
=head3 _set_userenv
(-)a/admin/categories.pl (+3 lines)
Lines 63-68 elsif ( $op eq 'add_validate' ) { Link Here
63
    my $description = $input->param('description');
63
    my $description = $input->param('description');
64
    my $enrolmentperiod = $input->param('enrolmentperiod');
64
    my $enrolmentperiod = $input->param('enrolmentperiod');
65
    my $enrolmentperioddate = $input->param('enrolmentperioddate') || undef;
65
    my $enrolmentperioddate = $input->param('enrolmentperioddate') || undef;
66
    my $password_expiry_days = $input->param('password_expiry_days') || undef;
66
    my $upperagelimit = $input->param('upperagelimit');
67
    my $upperagelimit = $input->param('upperagelimit');
67
    my $dateofbirthrequired = $input->param('dateofbirthrequired');
68
    my $dateofbirthrequired = $input->param('dateofbirthrequired');
68
    my $enrolmentfee = $input->param('enrolmentfee');
69
    my $enrolmentfee = $input->param('enrolmentfee');
Lines 103-108 elsif ( $op eq 'add_validate' ) { Link Here
103
        $category->description($description);
104
        $category->description($description);
104
        $category->enrolmentperiod($enrolmentperiod);
105
        $category->enrolmentperiod($enrolmentperiod);
105
        $category->enrolmentperioddate($enrolmentperioddate);
106
        $category->enrolmentperioddate($enrolmentperioddate);
107
        $category->password_expiry_days($password_expiry_days);
106
        $category->upperagelimit($upperagelimit);
108
        $category->upperagelimit($upperagelimit);
107
        $category->dateofbirthrequired($dateofbirthrequired);
109
        $category->dateofbirthrequired($dateofbirthrequired);
108
        $category->enrolmentfee($enrolmentfee);
110
        $category->enrolmentfee($enrolmentfee);
Lines 134-139 elsif ( $op eq 'add_validate' ) { Link Here
134
            description => $description,
136
            description => $description,
135
            enrolmentperiod => $enrolmentperiod,
137
            enrolmentperiod => $enrolmentperiod,
136
            enrolmentperioddate => $enrolmentperioddate,
138
            enrolmentperioddate => $enrolmentperioddate,
139
            password_expiry_days => $password_expiry_days,
137
            upperagelimit => $upperagelimit,
140
            upperagelimit => $upperagelimit,
138
            dateofbirthrequired => $dateofbirthrequired,
141
            dateofbirthrequired => $dateofbirthrequired,
139
            enrolmentfee => $enrolmentfee,
142
            enrolmentfee => $enrolmentfee,
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt (+11 lines)
Lines 162-167 Link Here
162
                        </ol>
162
                        </ol>
163
                    </fieldset>
163
                    </fieldset>
164
                </li>
164
                </li>
165
                <li>
166
                    <label for="password_expiry_days">Password expiration: </label>
167
                    <input type="text" name="password_expiry_days" id="password_expiry_days" value="[% category.password_expiry_days | html %]" size="3" maxlength="5" /> days
168
                </li>
165
                <li>
169
                <li>
166
                    <label for="dateofbirthrequired">Age required: </label>
170
                    <label for="dateofbirthrequired">Age required: </label>
167
                    <input type="text" name="dateofbirthrequired" id="dateofbirthrequired" value="[% category.dateofbirthrequired | html %]" size="3" maxlength="3" /> years
171
                    <input type="text" name="dateofbirthrequired" id="dateofbirthrequired" value="[% category.dateofbirthrequired | html %]" size="3" maxlength="3" /> years
Lines 451-456 Link Here
451
                        [% END %]
455
                        [% END %]
452
                    </td>
456
                    </td>
453
                </tr>
457
                </tr>
458
                <tr><th scope="row">Password expiration: </th><td>[% category.password_expiry_days | html %] days</td></tr>
454
                <tr><th scope="row">Age required: </th><td>[% category.dateofbirthrequired | html %] years</td></tr>
459
                <tr><th scope="row">Age required: </th><td>[% category.dateofbirthrequired | html %] years</td></tr>
455
                <tr><th scope="row">Upperage limit: </th><td>[% category.upperagelimit | html %] years</td></tr>
460
                <tr><th scope="row">Upperage limit: </th><td>[% category.upperagelimit | html %] years</td></tr>
456
                <tr><th scope="row">Enrollment fee: </th><td>[% category.enrolmentfee | $Price %]</td></tr>
461
                <tr><th scope="row">Enrollment fee: </th><td>[% category.enrolmentfee | $Price %]</td></tr>
Lines 519-524 Link Here
519
                    <th scope="col">Category name</th>
524
                    <th scope="col">Category name</th>
520
                    <th scope="col">Type</th>
525
                    <th scope="col">Type</th>
521
                    <th scope="col">Enrollment period</th>
526
                    <th scope="col">Enrollment period</th>
527
                    <th scope="col">Password expiration</th>
522
                    <th scope="col">Age required</th>
528
                    <th scope="col">Age required</th>
523
                    <th scope="col">Upper age limit</th>
529
                    <th scope="col">Upper age limit</th>
524
                    <th scope="col">Enrollment fee</th>
530
                    <th scope="col">Enrollment fee</th>
Lines 561-566 Link Here
561
                                until [% category.enrolmentperioddate | $KohaDates %]
567
                                until [% category.enrolmentperioddate | $KohaDates %]
562
                            [% END %]
568
                            [% END %]
563
                        </td>
569
                        </td>
570
                        [% IF (category.password_expiry_days) %]
571
                            <td>[% category.password_expiry_days | html %] days</td>
572
                        [% ELSE %]
573
                            <td>-</td>
574
                        [% END %]
564
                        [% IF (category.dateofbirthrequired) %]
575
                        [% IF (category.dateofbirthrequired) %]
565
                            <td>[% category.dateofbirthrequired | html %] years</td>
576
                            <td>[% category.dateofbirthrequired | html %] years</td>
566
                        [% ELSE %]
577
                        [% ELSE %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt (+7 lines)
Lines 50-55 Link Here
50
    [% IF Categories.can_any_reset_password && Koha.Preference('OpacBaseURL') %]
50
    [% IF Categories.can_any_reset_password && Koha.Preference('OpacBaseURL') %]
51
        <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-password-recovery.pl">You must reset your password</a>.
51
        <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-password-recovery.pl">You must reset your password</a>.
52
    [% END %]
52
    [% END %]
53
[% ELSIF password_has_expired %]
54
    <div id="login_error"><strong>Error: </strong>Your password has expired!</div>
55
    [% IF 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>.
57
    [% ELSE %]
58
        <p>You must contact the library to have your password reset</p>
59
    [% END %]
53
[% ELSIF invalid_username_or_password %]
60
[% ELSIF invalid_username_or_password %]
54
<div id="login_error"><strong>Error: </strong>Invalid username or password</div>
61
<div id="login_error"><strong>Error: </strong>Invalid username or password</div>
55
[% END %]
62
[% END %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt (-3 / +11 lines)
Lines 167-173 Link Here
167
                            [% END # /IF GoogleOpenIDConnect %]
167
                            [% END # /IF GoogleOpenIDConnect %]
168
                        [% END # /UNLESS OPACShibOnly %]
168
                        [% END # /UNLESS OPACShibOnly %]
169
169
170
                        [% IF !Koha.Preference('OPACShibOnly') or SCO_login or SCI_login %]
170
                        [% IF password_has_expired %]
171
                            <p class="error"><strong>Error: </strong>Your password has expired!</p>
172
                            [% IF Koha.Preference('OpacPasswordChange') && Categories.can_any_reset_password %]
173
                                <div id="resetpassword">
174
                                    <a href="/cgi-bin/koha/opac-password-recovery.pl">Reset your password?</a>
175
                                </div>
176
                            [% ELSE %]
177
                                <p>You must contact the library to reset your password</p>
178
                            [% END %]
179
                        [% ELSIF !Koha.Preference('OPACShibOnly') or SCO_login or SCI_login %]
171
                            [% IF SCO_login %]
180
                            [% IF SCO_login %]
172
                                <form action="/cgi-bin/koha/sco/sco-main.pl" name="auth" id="auth" method="post" autocomplete="off">
181
                                <form action="/cgi-bin/koha/sco/sco-main.pl" name="auth" id="auth" method="post" autocomplete="off">
173
                            [% ELSIF SCI_login %]
182
                            [% ELSIF SCI_login %]
Lines 218-224 Link Here
218
                                    </div>
227
                                    </div>
219
                                [% END %]
228
                                [% END %]
220
                            </form>
229
                            </form>
221
                        [% END # / IF !OPACShibOnly or SCO_login or SCI_login %]
230
                        [% END # / IF password_has_expired / ELSIF !OPACShibOnly or SCO_login or SCI_login %]
222
                    [% END # / IF loginprompt %]
231
                    [% END # / IF loginprompt %]
223
232
224
                    [% ELSE %]
233
                    [% ELSE %]
225
- 

Return to bug 29924