Bugzilla – Attachment 133742 Details for
Bug 29924
Introduce password expiration to patron categories
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 29924: Add password expiration feature
Bug-29924-Add-password-expiration-feature.patch (text/plain), 14.64 KB, created by
Nick Clemens
on 2022-04-25 11:32:39 UTC
(
hide
)
Description:
Bug 29924: Add password expiration feature
Filename:
MIME Type:
Creator:
Nick Clemens
Created:
2022-04-25 11:32:39 UTC
Size:
14.64 KB
patch
obsolete
>From 4377b3af12e275ea06c882e3185da67e166f26b3 Mon Sep 17 00:00:00 2001 >From: Nick Clemens <nick@bywatersolutions.com> >Date: Fri, 21 Jan 2022 17:01:10 +0000 >Subject: [PATCH] Bug 29924: Add password expiration feature > >This patch adds the ability to define password_expiry_days for a patron >category. > >When defined a patron's password will expire after X days and they will >be required to reset their password. If OPAC resets are enabled for the >catgeory they may do so on their own, otherwise they will need to >contact the library > >To test: > 1 - Apply patch, updatedatabase > 2 - Set 'Password expiration' for a patron category > Home-> Administration-> Patron categories-> Edit > 3 - Create a new patron in this category with a userid/password set, > and an email > 4 - Confirm their password_expiration_date field is set > SELECT password_expiration_date FROM borrowers WHERE borrowernumber=51; > 5 - Create a new patron, do not set a password > 6 - Confirm their password_expiration_date field is NULL > 7 - Update the patron with an expiration to be expired > UPDATE borrowers SET password_expiration_date='2022-01-01' WHERE borrowernumber=51; > 8 - Give the borrower catalogue permission > 9 - Attempt to log in to Straff interface >10 - Confirm you are signed out and notified that password must be > reset >11 - Attempt to sign in to OPAC >12 - Confirm you are signed out and notified password must be reset >13 - Enable password reset for the patron's category and perform a > password reset > Note: you will have to find the link in the message_queue unless > you have emails setup on your test environment > SELECT * FROM message_queue WHERE borrowernumber=51; >14 - Confirm that you can now sign in and password_expiration_date field > is set 10 days in the future >15 - Expire the patron's password again >16 - Change the patron's password via the staff interface >17 - Confirm they can sign in and the expiration is updated > >Signed-off-by: Owen Leonard <oleonard@myacpl.org> > >Signed-off-by: Bob Bennhoff <bbennhoff@clicweb.org> > >Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com> >--- > C4/Auth.pm | 12 ++++++++--- > Koha/Patron.pm | 20 +++++++++++++++++++ > Koha/Patron/Category.pm | 20 +++++++++++++++++++ > Koha/REST/V1/Auth.pm | 7 ++++++- > admin/categories.pl | 3 +++ > .../prog/en/modules/admin/categories.tt | 11 ++++++++++ > .../intranet-tmpl/prog/en/modules/auth.tt | 7 +++++++ > .../bootstrap/en/modules/opac-auth.tt | 13 ++++++++++-- > 8 files changed, 87 insertions(+), 6 deletions(-) > >diff --git a/C4/Auth.pm b/C4/Auth.pm >index c1c27e0eb9..4007179cc3 100644 >--- a/C4/Auth.pm >+++ b/C4/Auth.pm >@@ -966,6 +966,8 @@ sub checkauth { > $info{oldip} = $more_info->{old_ip}; > $info{newip} = $more_info->{new_ip}; > $info{different_ip} = 1; >+ } elsif ( $return eq 'password_expired' ) { >+ $info{password_has_expired} = 1; > } > } > } >@@ -1404,7 +1406,8 @@ sub checkauth { > PatronSelfRegistration => C4::Context->preference("PatronSelfRegistration"), > PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"), > opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'}, >- too_many_login_attempts => ( $patron and $patron->account_locked ) >+ too_many_login_attempts => ( $patron and $patron->account_locked ), >+ password_has_expired => ( $patron and $patron->password_expired ) > ); > > $template->param( SCO_login => 1 ) if ( $query->param('sco_user_login') ); >@@ -1792,6 +1795,9 @@ sub check_cookie_auth { > > } elsif ( $userid ) { > $session->param( 'lasttime', time() ); >+ my $patron = Koha::Patrons->find({ userid => $userid }); >+ $patron = Koha::Patron->find({ cardnumber => $userid }) unless $patron; >+ return ("password_expired", undef ) if $patron->password_expired; > my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1; > if ($flags) { > C4::Context->_new_userenv($sessionID); >@@ -1903,8 +1909,8 @@ sub checkpw { > # 0 if auth is nok > # -1 if user bind failed (LDAP only) > >- if ( $patron and $patron->account_locked ) { >- # Nothing to check, account is locked >+ if ( $patron and ( $patron->account_locked || $patron->password_expired ) ) { >+ # Nothing to check, account is locked or password expired > } elsif ($ldap && defined($password)) { > my ( $retval, $retcard, $retuserid ) = checkpw_ldap(@_); # EXTERNAL AUTH > if ( $retval == 1 ) { >diff --git a/Koha/Patron.pm b/Koha/Patron.pm >index c424c30174..e2384ecf3f 100644 >--- a/Koha/Patron.pm >+++ b/Koha/Patron.pm >@@ -267,6 +267,9 @@ sub store { > # Make a copy of the plain text password for later use > $self->plain_text_password( $self->password ); > >+ $self->password_expiration_date( $self->password >+ ? $self->category->get_password_expiry_date >+ : undef ); > # Create a disabled account if no password provided > $self->password( $self->password > ? Koha::AuthUtils::hash_password( $self->password ) >@@ -787,6 +790,21 @@ sub is_expired { > return 0; > } > >+=head3 password_expired >+ >+my $password_expired = $patron->password_expired; >+ >+Returns 1 if the patron's password is expired or 0; >+ >+=cut >+ >+sub password_expired { >+ my ($self) = @_; >+ return 0 unless $self->password_expiration_date; >+ return 1 if dt_from_string( $self->password_expiration_date ) < dt_from_string->truncate( to => 'day' ); >+ return 0; >+} >+ > =head3 is_going_to_expire > > my $is_going_to_expire = $patron->is_going_to_expire; >@@ -886,6 +904,8 @@ sub set_password { > > my $digest = Koha::AuthUtils::hash_password($password); > >+ $self->password_expiration_date( $self->category->get_password_expiry_date ); >+ > # We do not want to call $self->store and retrieve password from DB > $self->password($digest); > $self->login_attempts(0); >diff --git a/Koha/Patron/Category.pm b/Koha/Patron/Category.pm >index 892d00c2ae..c6837ca00f 100644 >--- a/Koha/Patron/Category.pm >+++ b/Koha/Patron/Category.pm >@@ -113,6 +113,26 @@ sub get_expiry_date { > } > } > >+=head3 get_password_expiry_date >+ >+Returns date based on password expiry days set for the category. If the value is not set >+we return undef, password does not expire >+ >+my $expiry_date = $category->get_password_expiry_date(); >+ >+=cut >+ >+sub get_password_expiry_date { >+ my ($self, $date ) = @_; >+ if ( $self->password_expiry_days ) { >+ $date ||= dt_from_string; >+ $date = dt_from_string( $date ) unless ref $date; >+ return $date->add( days => $self->password_expiry_days )->ymd; >+ } else { >+ return; >+ } >+} >+ > =head3 effective_reset_password > > Returns if patrons in this category can reset their password. If set in $self->reset_password >diff --git a/Koha/REST/V1/Auth.pm b/Koha/REST/V1/Auth.pm >index 7bbf97fc05..8c9adc15a8 100644 >--- a/Koha/REST/V1/Auth.pm >+++ b/Koha/REST/V1/Auth.pm >@@ -491,7 +491,12 @@ sub _basic_auth { > Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Invalid password' ); > } > >- return Koha::Patrons->find({ userid => $user_id }); >+ my $patron = Koha::Patrons->find({ userid => $user_id }); >+ if ( $patron->password_expired ) { >+ Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Password has expired' ); >+ } >+ >+ return $patron; > } > > =head3 _set_userenv >diff --git a/admin/categories.pl b/admin/categories.pl >index 368960f9cd..e41a28904d 100755 >--- a/admin/categories.pl >+++ b/admin/categories.pl >@@ -63,6 +63,7 @@ elsif ( $op eq 'add_validate' ) { > my $description = $input->param('description'); > my $enrolmentperiod = $input->param('enrolmentperiod'); > my $enrolmentperioddate = $input->param('enrolmentperioddate') || undef; >+ my $password_expiry_days = $input->param('password_expiry_days') || undef; > my $upperagelimit = $input->param('upperagelimit'); > my $dateofbirthrequired = $input->param('dateofbirthrequired'); > my $enrolmentfee = $input->param('enrolmentfee'); >@@ -103,6 +104,7 @@ elsif ( $op eq 'add_validate' ) { > $category->description($description); > $category->enrolmentperiod($enrolmentperiod); > $category->enrolmentperioddate($enrolmentperioddate); >+ $category->password_expiry_days($password_expiry_days); > $category->upperagelimit($upperagelimit); > $category->dateofbirthrequired($dateofbirthrequired); > $category->enrolmentfee($enrolmentfee); >@@ -134,6 +136,7 @@ elsif ( $op eq 'add_validate' ) { > description => $description, > enrolmentperiod => $enrolmentperiod, > enrolmentperioddate => $enrolmentperioddate, >+ password_expiry_days => $password_expiry_days, > upperagelimit => $upperagelimit, > dateofbirthrequired => $dateofbirthrequired, > enrolmentfee => $enrolmentfee, >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >index d3f0916d1d..a3e623e604 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >@@ -162,6 +162,10 @@ > </ol> > </fieldset> > </li> >+ <li> >+ <label for="password_expiry_days">Password expiration: </label> >+ <input type="text" name="password_expiry_days" id="password_expiry_days" value="[% category.password_expiry_days | html %]" size="3" maxlength="5" /> days >+ </li> > <li> > <label for="dateofbirthrequired">Age required: </label> > <input type="text" name="dateofbirthrequired" id="dateofbirthrequired" value="[% category.dateofbirthrequired | html %]" size="3" maxlength="3" /> years >@@ -451,6 +455,7 @@ > [% END %] > </td> > </tr> >+ <tr><th scope="row">Password expiration: </th><td>[% category.password_expiry_days | html %] days</td></tr> > <tr><th scope="row">Age required: </th><td>[% category.dateofbirthrequired | html %] years</td></tr> > <tr><th scope="row">Upperage limit: </th><td>[% category.upperagelimit | html %] years</td></tr> > <tr><th scope="row">Enrollment fee: </th><td>[% category.enrolmentfee | $Price %]</td></tr> >@@ -519,6 +524,7 @@ > <th scope="col">Category name</th> > <th scope="col">Type</th> > <th scope="col">Enrollment period</th> >+ <th scope="col">Password expiration</th> > <th scope="col">Age required</th> > <th scope="col">Upper age limit</th> > <th scope="col">Enrollment fee</th> >@@ -561,6 +567,11 @@ > until [% category.enrolmentperioddate | $KohaDates %] > [% END %] > </td> >+ [% IF (category.password_expiry_days) %] >+ <td>[% category.password_expiry_days | html %] days</td> >+ [% ELSE %] >+ <td>-</td> >+ [% END %] > [% IF (category.dateofbirthrequired) %] > <td>[% category.dateofbirthrequired | html %] years</td> > [% ELSE %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt >index 310e2b568e..4dd1505c04 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt >@@ -50,6 +50,13 @@ > [% IF Categories.can_any_reset_password && Koha.Preference('OpacBaseURL') %] > <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-password-recovery.pl">You must reset your password</a>. > [% END %] >+[% ELSIF password_has_expired %] >+ <div id="login_error"><strong>Error: </strong>Your password has expired!</div> >+ [% IF Categories.can_any_reset_password && Koha.Preference('OpacBaseURL') %] >+ <a href="[% Koha.Preference('OpacBaseURL') | url %]/cgi-bin/koha/opac-password-recovery.pl">You must reset your password</a>. >+ [% ELSE %] >+ <p>You must contact the library to have your password reset</p> >+ [% END %] > [% ELSIF invalid_username_or_password %] > <div id="login_error"><strong>Error: </strong>Invalid username or password</div> > [% END %] >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt >index 99fc207edc..dc8f2d9c1a 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt >@@ -167,7 +167,16 @@ > [% END # /IF GoogleOpenIDConnect %] > [% END # /UNLESS OPACShibOnly %] > >- [% IF !Koha.Preference('OPACShibOnly') or SCO_login or SCI_login %] >+ [% IF password_has_expired %] >+ <p class="error"><strong>Error: </strong>Your password has expired!</p> >+ [% IF Koha.Preference('OpacPasswordChange') && Categories.can_any_reset_password %] >+ <div id="resetpassword"> >+ <a href="/cgi-bin/koha/opac-password-recovery.pl">Reset your password?</a> >+ </div> >+ [% ELSE %] >+ <p>You must contact the library to reset your password</p> >+ [% END %] >+ [% ELSIF !Koha.Preference('OPACShibOnly') or SCO_login or SCI_login %] > [% IF SCO_login %] > <form action="/cgi-bin/koha/sco/sco-main.pl" name="auth" id="auth" method="post" autocomplete="off"> > [% ELSIF SCI_login %] >@@ -218,7 +227,7 @@ > </div> > [% END %] > </form> >- [% END # / IF !OPACShibOnly or SCO_login or SCI_login %] >+ [% END # / IF password_has_expired / ELSIF !OPACShibOnly or SCO_login or SCI_login %] > [% END # / IF loginprompt %] > > [% ELSE %] >-- >2.30.2
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 29924
:
129705
|
129706
|
129707
|
129708
|
129762
|
129763
|
129764
|
129765
|
129766
|
129823
|
129953
|
129954
|
129955
|
129956
|
129957
|
130116
|
130117
|
130118
|
130119
|
130120
|
130495
|
130500
|
130501
|
130502
|
130503
|
130504
|
130505
|
130557
|
130558
|
130559
|
130560
|
130561
|
130562
|
130563
|
130677
|
130678
|
130679
|
130680
|
130681
|
130682
|
130683
|
131128
|
132059
|
132060
|
132061
|
132062
|
132063
|
132064
|
132065
|
132066
|
132084
|
132085
|
132086
|
132087
|
132088
|
132089
|
132090
|
132091
|
132092
|
133741
|
133742
|
133743
|
133744
|
133745
|
133746
|
133747
|
133748
|
133801
|
133802
|
133803
|
133804
|
133805
|
133806
|
133807
|
133808
|
133809
|
133810
|
133989
|
134758