Bugzilla – Attachment 108558 Details for
Bug 23816
Allow to have different password strength and length settings for different patron categories
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 23816: Add minimum password length and require strong password overrides by category
Bug-23816-Add-minimum-password-length-and-require-.patch (text/plain), 47.37 KB, created by
Katrin Fischer
on 2020-08-18 21:24:52 UTC
(
hide
)
Description:
Bug 23816: Add minimum password length and require strong password overrides by category
Filename:
MIME Type:
Creator:
Katrin Fischer
Created:
2020-08-18 21:24:52 UTC
Size:
47.37 KB
patch
obsolete
>From de36b40f69541cfe88a8ba74c96d6fd34aa55bef Mon Sep 17 00:00:00 2001 >From: Agustin Moyano <agustinmoyano@theke.io> >Date: Wed, 15 Apr 2020 17:13:02 -0300 >Subject: [PATCH] Bug 23816: Add minimum password length and require strong > password overrides by category >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >This patch adds the capability to override minPasswordLenth and RequireStrongPassword settings by category > >To test: >1. koha-shell kohadev >2. koha-mysql kohadev > >3. drop database koha_kohadev; >4. create database koha_kohadev; > >5. go to admin page and start webinstaller. There continue the steps until onboarding. >6. reach step 3 of onboarding and create a new administrator patron >CHECH => Password control woks as normal (Minimum length 3 and strong required) > >7. finish Koha installation and enter admin with your new administrator >8. set minPasswordLength to 3 and RequireStrongPassword to âDonât requireâ >9. Create a new category (CAT2 from now on.. CAT1 is the category you made in onboarding process) and set minimum password length to 8 and require strong password >10. Create two new patrons, one with CAT1(patron1) and one with CAT2 (patron2) >CHECK => In both cases, try different combinations of length and strength. For patron1 the only requirement is to have 3 letters, but for patron2 the minimum length will be 8 and will require strong password. >CHECK => Try changing patron category before saving. Password requirements will change with category change. > >11. Edit CAT1 and set minimum password length to 5 >12. Go to patron1 details page, and change password. >CHECH => Now password minimum length is 5, but still it doesnât require strong password > >13. Edit CAT1, leave blank minimum password length and set require strong password to yes. >14. Go to patron1 details page, and change password. >CHECH => Password minimum length is back to 3, but now strong password is required > >15. Set minimum password length in CAT2 to 12. >16. Go to patron2 details page, and click to fill a random generated password >CHECK => generated password should be 12 characters length > >17. Set PatronSelfRegistration to Allow in admin settings >18. Go to OPAC and fill self registration from. >CHECK => Play with patron category. For each change in category, password requirements are modified. >CHECK => Set CAT1 as patron category, set âaA1â as password (or another valid password for CAT1) and before hitting submit button, change to CAT2. Form should enter invalid state, and CAT2 password requirements should be displayed as error in password input. > >19. Create a patron for CAT1 and another for CAT2, leaving password blank >CHECK => For CAT1âs patron, generated password length is 8 (minimum length for generated passwords), but for CAT2âs patron should be 12 > >20. In admin set PatronSelfRegistrationVerifyByEmail to require >21. Fill self registration form again with CAT2 as category >CHECK => Password requirements works as previous case. >22. Leave password blank and click submit > >23. select * from message_queue; >24. Copy the link in the message and paste it in OPAC >CHECH => Generated password is 12 characters long. (Copy user id for next steps) > >25. In admin set OpacResetPassword to Allow >26. Go back to OPAC, reload and click on âForgot password?â link >27. Paste user id and click submit >28. Repeat steps 23 and 24 >CHECK => Info message says âYour password must contain at least 12 characters, including UPPERCASE, lowercase and numbers.â >CHECK => enter an invalid password and youâll get the same message in warning. > >29. Login OPAC with the last user and your newly created password >30. Go to âChange your passwordâ option >CHECK => Info message says âYour password must contain at least 12 characters, including UPPERCASE, lowercase and numbers.â >CHECK => enter an invalid password and youâll get the same message in below âNew passwordâ input. > >31. prove t/db_dependent/AuthUtils.t t/db_dependent/Koha/Patron/Category.t > >32. Sign off > >Sponsored-by: Northeast Kansas Library - NEKLS > >Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com> > >Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> >--- > Koha/AuthUtils.pm | 19 +++++----- > Koha/Patron.pm | 4 +- > Koha/Patron/Category.pm | 32 ++++++++++++++++ > admin/categories.pl | 8 ++++ > .../prog/en/includes/password_check.inc | 40 ++++++++++++++------ > .../prog/en/modules/admin/categories.tt | 37 ++++++++++++++++++ > .../prog/en/modules/members/member-password.tt | 15 ++++---- > .../prog/en/modules/members/memberentrygen.tt | 7 ++-- > .../prog/en/modules/onboarding/onboardingstep3.tt | 5 +-- > .../bootstrap/en/includes/password_check.inc | 44 +++++++++++++++------- > .../bootstrap/en/modules/opac-memberentry.tt | 36 +++++++++++++----- > .../opac-tmpl/bootstrap/en/modules/opac-passwd.tt | 9 ++--- > .../bootstrap/en/modules/opac-password-recovery.tt | 6 +-- > members/memberentry.pl | 6 ++- > misc/admin/set_password.pl | 13 ++++--- > opac/opac-memberentry.pl | 8 ++-- > opac/opac-password-recovery.pl | 15 +++++++- > opac/opac-registration-verify.pl | 3 +- > 18 files changed, 224 insertions(+), 83 deletions(-) > >diff --git a/Koha/AuthUtils.pm b/Koha/AuthUtils.pm >index 7c4dcd1002..a325c9cbdd 100644 >--- a/Koha/AuthUtils.pm >+++ b/Koha/AuthUtils.pm >@@ -139,21 +139,21 @@ sub generate_salt { > > =head2 is_password_valid > >-my ( $is_valid, $error ) = is_password_valid( $password ); >+my ( $is_valid, $error ) = is_password_valid( $password, $category ); > >-return $is_valid == 1 if the password match minPasswordLength and RequireStrongPassword conditions >+return $is_valid == 1 if the password match category's minimum password length and strength if provided, or general minPasswordLength and RequireStrongPassword conditions > otherwise return $is_valid == 0 and $error will contain the error ('too_short' or 'too_weak') > > =cut > > sub is_password_valid { >- my ($password) = @_; >- my $minPasswordLength = C4::Context->preference('minPasswordLength'); >+ my ($password, $category) = @_; >+ my $minPasswordLength = $category?$category->effective_min_password_length:C4::Context->preference('minPasswordLength'); > $minPasswordLength = 3 if not $minPasswordLength or $minPasswordLength < 3; > if ( length($password) < $minPasswordLength ) { > return ( 0, 'too_short' ); > } >- elsif ( C4::Context->preference('RequireStrongPassword') ) { >+ elsif ( $category?$category->effective_require_strong_password:C4::Context->preference('RequireStrongPassword') ) { > return ( 0, 'too_weak' ) > if $password !~ m|(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{$minPasswordLength,}|; > } >@@ -163,20 +163,21 @@ sub is_password_valid { > > =head2 generate_password > >-my password = generate_password(); >+my password = generate_password($category); > >-Generate a password according to the minPasswordLength and RequireStrongPassword. >+Generate a password according to category's minimum password length and strength if provided, or to the minPasswordLength and RequireStrongPassword system preferences. > > =cut > > sub generate_password { >- my $minPasswordLength = C4::Context->preference('minPasswordLength'); >+ my ($category) = @_; >+ my $minPasswordLength = $category?$category->effective_min_password_length:C4::Context->preference('minPasswordLength'); > $minPasswordLength = 8 if not $minPasswordLength or $minPasswordLength < 8; > > my ( $password, $is_valid ); > do { > $password = random_string('.' x $minPasswordLength ); >- ( $is_valid, undef ) = is_password_valid( $password ); >+ ( $is_valid, undef ) = is_password_valid( $password, $category ); > } while not $is_valid; > return $password; > } >diff --git a/Koha/Patron.pm b/Koha/Patron.pm >index 5436ccc448..12b8bb24da 100644 >--- a/Koha/Patron.pm >+++ b/Koha/Patron.pm >@@ -744,11 +744,11 @@ sub set_password { > my $password = $args->{password}; > > unless ( $args->{skip_validation} ) { >- my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $password ); >+ my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $password, $self->category ); > > if ( !$is_valid ) { > if ( $error eq 'too_short' ) { >- my $min_length = C4::Context->preference('minPasswordLength'); >+ my $min_length = $self->category->effective_min_password_length; > $min_length = 3 if not $min_length or $min_length < 3; > > my $password_length = length($password); >diff --git a/Koha/Patron/Category.pm b/Koha/Patron/Category.pm >index 72493cda7a..346a5d9778 100644 >--- a/Koha/Patron/Category.pm >+++ b/Koha/Patron/Category.pm >@@ -255,6 +255,38 @@ sub effective_change_password { > : C4::Context->preference('OpacPasswordChange'); > } > >+=head3 effective_min_password_length >+ >+ $category->effective_min_password_length() >+ >+Retrieve category's password length if setted, or minPasswordLength otherwise >+ >+=cut >+ >+sub effective_min_password_length { >+ my ($self) = @_; >+ >+ return C4::Context->preference('minPasswordLength') unless defined $self->min_password_length; >+ >+ return $self->min_password_length; >+} >+ >+=head3 effective_require_strong_password >+ >+ $category->effective_require_strong_password() >+ >+Retrieve category's password strength if setted, or RequireStrongPassword otherwise >+ >+=cut >+ >+sub effective_require_strong_password { >+ my ($self) = @_; >+ >+ return C4::Context->preference('RequireStrongPassword') unless defined $self->require_strong_password; >+ >+ return $self->require_strong_password; >+} >+ > =head3 override_hidden_items > > if ( $patron->category->override_hidden_items ) { >diff --git a/admin/categories.pl b/admin/categories.pl >index f9144e7ced..d0b2d058f0 100755 >--- a/admin/categories.pl >+++ b/admin/categories.pl >@@ -94,10 +94,14 @@ elsif ( $op eq 'add_validate' ) { > my $default_privacy = $input->param('default_privacy'); > my $reset_password = $input->param('reset_password'); > my $change_password = $input->param('change_password'); >+ my $min_password_length = $input->param('min_password_length'); >+ my $require_strong_password = $input->param('require_strong_password'); > my @branches = grep { $_ ne q{} } $input->multi_param('branches'); > > $reset_password = undef if $reset_password eq -1; > $change_password = undef if $change_password eq -1; >+ $min_password_length = undef unless length($min_password_length); >+ $require_strong_password = undef if $require_strong_password eq -1; > > my $is_a_modif = $input->param("is_a_modif"); > >@@ -129,6 +133,8 @@ elsif ( $op eq 'add_validate' ) { > $category->default_privacy($default_privacy); > $category->reset_password($reset_password); > $category->change_password($change_password); >+ $category->min_password_length($min_password_length); >+ $category->require_strong_password($require_strong_password); > eval { > $category->store; > $category->replace_branch_limitations( \@branches ); >@@ -157,6 +163,8 @@ elsif ( $op eq 'add_validate' ) { > default_privacy => $default_privacy, > reset_password => $reset_password, > change_password => $change_password, >+ min_password_length => $min_password_length, >+ require_strong_password => $require_strong_password, > }); > eval { > $category->store; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/password_check.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/password_check.inc >index 9f4266b792..1c11896c57 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/password_check.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/password_check.inc >@@ -1,20 +1,37 @@ > [% USE Koha %] >-[% BLOCK add_password_check %] > <!-- password_check.inc --> > <script> > var pwd_title = ""; > var pattern_title = ""; > var new_password_node_name = "[% new_password | html %]"; >- [% IF Koha.Preference('RequireStrongPassword') %] >- pwd_title = _("Password must contain at least %s characters, including UPPERCASE, lowercase and numbers").format([% minPasswordLength | html %]); >- pattern_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{[% minPasswordLength | html %],}/; >- [% ELSIF minPasswordLength %] >- pwd_title = _("Password must contain at least %s characters").format([% minPasswordLength | html %]); >- pattern_regex = /.{[% minPasswordLength | html %],}/; >- [% END %] >- jQuery.validator.addMethod("password_strong", function(value, element){ >- return this.optional(element) || value == '****' || pattern_regex.test(value); >- }, pwd_title); >+ var category_selector = "[% category_selector | html %]"; >+ var STRONG_MSG = _("Password must contain at least %s characters, including UPPERCASE, lowercase and numbers"); >+ var WEAK_MSG = _("Password must contain at least %s characters"); >+ >+ if(category_selector && $('select'+category_selector).length) { >+ jQuery.validator.addMethod("password_strong", function(value, element){ >+ var require_strong = $('select'+category_selector+' option:selected').data('pwdStrong'); >+ var min_lenght = $('select'+category_selector+' option:selected').data('pwdLength'); >+ var regex_text = require_strong?"(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{"+min_lenght+",}":".{"+min_lenght+",}"; >+ var pattern_regex = new RegExp(regex_text); >+ return this.optional(element) || pattern_regex.test(value); >+ }, function(unused, element) { >+ var require_strong = $('select'+category_selector+' option:selected').data('pwdStrong'); >+ var min_lenght = $('select'+category_selector+' option:selected').data('pwdLength'); >+ return (require_strong?STRONG_MSG:WEAK_MSG).format(min_lenght) >+ }); >+ } else { >+ [% IF RequireStrongPassword %] >+ pwd_title = STRONG_MSG.format([% minPasswordLength | html %]); >+ pattern_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{[% minPasswordLength | html %],}/; >+ [% ELSIF minPasswordLength %] >+ pwd_title = WEAK_MSG.format([% minPasswordLength | html %]); >+ pattern_regex = /.{[% minPasswordLength | html %],}/; >+ [% END %] >+ jQuery.validator.addMethod("password_strong", function(value, element){ >+ return this.optional(element) || value == '****' || pattern_regex.test(value); >+ }, pwd_title); >+ } > jQuery.validator.addMethod("password_no_spaces", function(value, element){ > return ( this.optional(element) || !value.match(/^\s/) && !value.match(/\s$/) ); > }, _("Password contains leading and/or trailing spaces")); >@@ -24,4 +41,3 @@ > }, _("Please enter the same password as above")); > </script> > <!-- / password_check.inc --> >-[% END %] >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 77146a78db..091936f38b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt >@@ -229,6 +229,43 @@ > [% END %] > </select> > </li> >+ <li> >+ <label for="min_password_length">Minimum password length:</label> >+ <input id="min_password_length" type="number" name="min_password_length" value="[% category.min_password_length | html %]"/> >+ <span>Leave blank to use system default ([% Koha.Preference('minPasswordLength') | html %])</span> >+ </li> >+ <li class="pwd_setting_wrapper"> >+ <label for="require_strong_password">Require strong password:</label> >+ <select id="require_strong_password" name="require_strong_password"> >+ [% IF category.require_strong_password.defined %] >+ [% IF category.require_strong_password %] >+ [% IF Koha.Preference('RequireStrongPassword') %] >+ <option value="-1">Follow system preference RequireStrongPassword (yes)</option> >+ [% ELSE %] >+ <option value="-1">Follow system preference RequireStrongPassword (no)</option> >+ [% END %] >+ <option value="1" selected="selected">Yes</option> >+ <option value="0">No</option> >+ [% ELSE %] >+ [% IF Koha.Preference('RequireStrongPassword') %] >+ <option value="-1">Follow system preference RequireStrongPassword (yes)</option> >+ [% ELSE %] >+ <option value="-1">Follow system preference RequireStrongPassword (no)</option> >+ [% END %] >+ <option value="1">Yes</option> >+ <option value="0" selected="selected">No</option> >+ [% END %] >+ [% ELSE %] >+ [% IF Koha.Preference('RequireStrongPassword') %] >+ <option value="-1">Follow system preference RequireStrongPassword (yes)</option> >+ [% ELSE %] >+ <option value="-1">Follow system preference RequireStrongPassword (no)</option> >+ [% END %] >+ <option value="1">Yes</option> >+ <option value="0">No</option> >+ [% END %] >+ </select> >+ </li> > <li><label for="block_expired">Block expired patrons:</label> > <select name="BlockExpiredPatronOpacActions" id="block_expired"> > [% IF not category or category.BlockExpiredPatronOpacActions == -1%] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-password.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-password.tt >index e20d72e1b7..a0a1b2ea79 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-password.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-password.tt >@@ -37,7 +37,7 @@ > <li>You have entered a username that already exists. Please choose another one.</li> > [% END %] > [% IF ( ERROR_password_too_short ) %] >- <li id="ERROR_short_password">Password must be at least [% Koha.Preference('minPasswordLength') | html %] characters long.</li> >+ <li id="ERROR_short_password">Password must be at least [% patron.category.effective_min_password_length | html %] characters long.</li> > [% END %] > [% IF ( ERROR_password_too_weak ) %] > <li id="ERROR_weak_password">Password must contain at least one digit, one lowercase and one uppercase.</li> >@@ -63,9 +63,9 @@ > <ol> > <li><label for="newuserid">New username:</label> > <input type="hidden" name="member" value="[% patron.borrowernumber | html %]" /><input type="text" id="newuserid" name="newuserid" size="20" value="[% patron.userid | html %]" /></li> >- [% SET password_pattern = ".{" _ Koha.Preference('minPasswordLength') _ ",}" %] >- [% IF Koha.Preference('RequireStrongPassword') %] >- [% SET password_pattern = '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{' _ Koha.Preference('minPasswordLength') _ ',}' %] >+ [% SET password_pattern = ".{" _ patron.category.effective_min_password_length _ ",}" %] >+ [% IF patron.category.effective_require_strong_password %] >+ [% SET password_pattern = '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{' _ patron.category.effective_min_password_length _ ',}' %] > [% END %] > <li> > <label for="newpassword">New password:</label> >@@ -105,7 +105,7 @@ > function generate_password() { > // Always generate a strong password > var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; >- var length = [% Koha.Preference('minPasswordLength') | html %]; >+ var length = [% patron.category.effective_min_password_length | html %]; > if ( length < 8 ) length = 8; > var password=''; > for ( var i = 0 ; i < length ; i++){ >@@ -117,7 +117,7 @@ > $("body").on('click', "#fillrandom",function(e) { > e.preventDefault(); > var password = ''; >- var pattern_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{[% Koha.Preference('minPasswordLength') | html %],}/; >+ var pattern_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{[% patron.category.effective_min_password_length | html %],}/; > while ( ! pattern_regex.test( password ) ) { > password = generate_password(); > } >@@ -156,8 +156,7 @@ > }); > }); > </script> >- [% PROCESS 'password_check.inc' %] >- [% PROCESS 'add_password_check' new_password => 'newpassword' %] >+ [% PROCESS 'password_check.inc' new_password => 'newpassword', minPasswordLength => patron.category.effective_min_password_length, RequireStrongPassword => patron.category.effective_require_strong_password %] > [% END %] > > [% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt >index 3c218b00ff..08a3fb7048 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt >@@ -817,9 +817,9 @@ legend:hover { > [% IF ( typeloo.typename_X ) %]<optgroup label="Statistical">[% END %] > [% END %] > [% IF ( categoryloo.categorycodeselected ) %] >- <option value="[% categoryloo.categorycode | html %]" selected="selected" data-typename="[% typeloo.typename | html %]">[% categoryloo.categoryname | html %]</option> >+ <option value="[% categoryloo.categorycode | html %]" selected="selected" data-pwd-length="[% categoryloo.effective_min_password_length | html %]" data-pwd-strong="[% categoryloo.effective_require_strong_password | html %]" data-typename="[% typeloo.typename | html %]">[% categoryloo.categoryname | html %]</option> > [% ELSE %] >- <option value="[% categoryloo.categorycode | html %]" data-typename="[% typeloo.typename | html %]">[% categoryloo.categoryname | html %]</option> >+ <option value="[% categoryloo.categorycode | html %]" data-pwd-length="[% categoryloo.effective_min_password_length | html %]" data-pwd-strong="[% categoryloo.effective_require_strong_password | html %]" data-typename="[% typeloo.typename | html %]">[% categoryloo.categoryname | html %]</option> > [% END %] > [% IF ( loop.last ) %] > </optgroup> >@@ -1717,8 +1717,7 @@ legend:hover { > </script> > [% Asset.js("js/members.js") | $raw %] > [% Asset.js("js/messaging-preference-form.js") | $raw %] >- [% PROCESS 'password_check.inc' %] >- [% PROCESS 'add_password_check' new_password => 'password' %] >+ [% PROCESS 'password_check.inc' new_password => 'password', category_selector => '#categorycode_entry', minPasswordLength => patron.category.effective_min_password_length, RequireStrongPassword => patron.category.effective_require_strong_password %] > [% END %] > > [% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/onboarding/onboardingstep3.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/onboarding/onboardingstep3.tt >index 63314b6fa8..a5702eb7eb 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/onboarding/onboardingstep3.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/onboarding/onboardingstep3.tt >@@ -61,7 +61,7 @@ > <label for="categorycode_entry" class="required"> Patron category</label> > <select id="categorycode_entry" name="categorycode_entry"> > [% FOREACH category IN categories %] >- <option value = "[% category.categorycode | html %]">[% category.description | html %]</option> >+ <option value = "[% category.categorycode | html %]" data-pwd-length="[% category.effective_min_password_length | html %]" data-pwd-strong="[% category.effective_require_strong_password | html %]">[% category.description | html %]</option> > [% END %] > </select> > <span class="required">Required</span><br><br> >@@ -116,8 +116,7 @@ > [% INCLUDE 'validator-strings.inc' %] > [% INCLUDE 'installer-strings.inc' %] > [% Asset.js("js/onboarding.js") | $raw %] >- [% PROCESS 'password_check.inc' %] >- [% PROCESS 'add_password_check' new_password => 'password' %] >+ [% PROCESS 'password_check.inc' new_password => 'password', category_selector => '#categorycode_entry', RequireStrongPassword => Koha.Preference('RequireStrongPassword') %] > [% END %] > > [% INCLUDE 'installer-intranet-bottom.inc' %] >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/password_check.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/password_check.inc >index 1a94309ae8..338d07bbbb 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/password_check.inc >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/password_check.inc >@@ -1,25 +1,41 @@ > [% USE Koha %] >-[% BLOCK add_password_check %] > <script> > var pwd_title = ""; > var pattern_title = ""; > var new_password_node_name = "[% new_password | html %]"; >- [% IF Koha.Preference('RequireStrongPassword') %] >- pwd_title = _("Password must contain at least %s characters, including UPPERCASE, lowercase and numbers").format([% minPasswordLength | html %]); >- pattern_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{[% minPasswordLength | html %],}/; >- [% ELSIF minPasswordLength %] >- pwd_title = _("Password must contain at least %s characters").format([% minPasswordLength | html %]); >- pattern_regex = /.{[% minPasswordLength | html %],}/; >- [% END %] >- jQuery.validator.addMethod("password_strong", function(value, element){ >- return this.optional(element) || pattern_regex.test(value); >- }, pwd_title); >+ var category_selector = "[% category_selector | html %]"; >+ var STRONG_MSG = _("Password must contain at least %s characters, including UPPERCASE, lowercase and numbers"); >+ var WEAK_MSG = _("Password must contain at least %s characters"); >+ >+ if(category_selector && $('select'+category_selector).length) { >+ jQuery.validator.addMethod("password_strong", function(value, element){ >+ var require_strong = $('select'+category_selector+' option:selected').data('pwdStrong'); >+ var min_lenght = $('select'+category_selector+' option:selected').data('pwdLength'); >+ var regex_text = require_strong?"(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{"+min_lenght+",}":".{"+min_lenght+",}"; >+ var pattern_regex = new RegExp(regex_text); >+ return this.optional(element) || pattern_regex.test(value); >+ }, function(unused, element) { >+ var require_strong = $('select'+category_selector+' option:selected').data('pwdStrong'); >+ var min_lenght = $('select'+category_selector+' option:selected').data('pwdLength'); >+ return (require_strong?STRONG_MSG:WEAK_MSG).format(min_lenght) >+ }); >+ } else { >+ [% IF RequireStrongPassword %] >+ pwd_title = STRONG_MSG.format([% minPasswordLength | html %]); >+ pattern_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{[% minPasswordLength | html %],}/; >+ [% ELSIF minPasswordLength %] >+ pwd_title = WEAK_MSG.format([% minPasswordLength | html %]); >+ pattern_regex = /.{[% minPasswordLength | html %],}/; >+ [% END %] >+ jQuery.validator.addMethod("password_strong", function(value, element){ >+ return this.optional(element) || value == '****' || pattern_regex.test(value); >+ }, pwd_title); >+ } > jQuery.validator.addMethod("password_no_spaces", function(value, element){ > return ( this.optional(element) || !value.match(/^\s/) && !value.match(/\s$/) ); > }, _("Password contains leading and/or trailing spaces")); > jQuery.validator.addMethod("password_match", function(value, element){ > var new_password_node = $("input[name='" + new_password_node_name + "']:first"); >- return this.optional(element) || value == $(new_password_node).val(); >+ return value == $(new_password_node).val(); > }, _("Please enter the same password as above")); >-</script> >-[% END %] >+</script> >\ No newline at end of file >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >index 7acd45af30..319fd72110 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >@@ -82,7 +82,7 @@ > [% IF field == "B_email" %]<li>Alternate address information: <a href="#borrower_B_email">email address</a></li>[% END %] > [% IF field == "password_match" %]<li>Passwords do not match! <a href="#password">password</a></li>[% END %] > [% IF field == "password_too_short" %] >- <li>Password must be at least [% minPasswordLength | html %] characters long.</li> >+ <li>Password must be at least [% patron.category.effective_min_password_length | html %] characters long.</li> > [% END %] > [% IF field == "password_too_weak" %] > <li>Password must contain at least one digit, one lowercase and one uppercase.</li> >@@ -252,9 +252,9 @@ > <select id="borrower_categorycode" name="borrower_categorycode"> > [% FOREACH c IN Categories.all() %] > [% IF c.categorycode == Koha.Preference('PatronSelfRegistrationDefaultCategory') %] >- <option value="[% c.categorycode | html %]" selected="selected">[% c.description | html %]</option> >+ <option value="[% c.categorycode | html %]" data-pwd-length="[% c.effective_min_password_length | html %]" data-pwd-strong="[% c.effective_require_strong_password | html %]" selected="selected">[% c.description | html %]</option> > [% ELSE %] >- <option value="[% c.categorycode | html %]">[% c.description | html %]</option> >+ <option value="[% c.categorycode | html %]" data-pwd-length="[% c.effective_min_password_length | html %]" data-pwd-strong="[% c.effective_require_strong_password | html %]">[% c.description | html %]</option> > [% END %] > [% END %] > </select> >@@ -858,10 +858,14 @@ > <fieldset class="rows" id="memberentry_password"> > <legend id="contact_legend">Password</legend> > <div class="alert alert-info"> >- [% IF ( Koha.Preference('RequireStrongPassword') ) %] >- <p>Your password must contain at least [% Koha.Preference('minPasswordLength') | html %] characters, including UPPERCASE, lowercase and numbers.</p> >+ [% IF patron %] >+ [% IF ( patron.category.effective_require_strong_password ) %] >+ <p>Your password must contain at least [% patron.category.effective_min_password_length | html %] characters, including UPPERCASE, lowercase and numbers.</p> >+ [% ELSE %] >+ <p>Your password must be at least [% patron.category.effective_min_password_length | html %] characters long.</p> >+ [% END %] > [% ELSE %] >- <p>Your password must be at least [% Koha.Preference('minPasswordLength') | html %] characters long.</p> >+ <p id="password_alert"></p> > [% END %] > [% UNLESS mandatory.defined('password') %] > <p>If you do not enter a password a system generated password will be created.</p> >@@ -1008,8 +1012,7 @@ > [% INCLUDE 'opac-bottom.inc' %] > [% BLOCK jsinclude %] > [% Asset.js("lib/jquery/plugins/jquery.validate.min.js") | $raw %] >- [% PROCESS 'password_check.inc' %] >- [% PROCESS 'add_password_check' new_password => 'borrower_password' %] >+ > <script> > //<![CDATA[ > $(document).ready(function() { >@@ -1170,7 +1173,22 @@ > }); > }); > [% END %] >+ >+ [% UNLESS patron %] >+ var PWD_STRONG_MSG = _("Password must contain at least %s characters, including UPPERCASE, lowercase and numbers"); >+ var PWD_WEAK_MSG = _("Password must contain at least %s characters"); >+ $(document).ready(function() { >+ var setPwdMessage = function() { >+ var require_strong = $('select#borrower_categorycode option:selected').data('pwdStrong'); >+ var min_lenght = $('select#borrower_categorycode option:selected').data('pwdLength'); >+ $('#password_alert').html((require_strong?PWD_STRONG_MSG:PWD_WEAK_MSG).format(min_lenght)); >+ }; >+ setPwdMessage(); >+ $('select#borrower_categorycode').change(setPwdMessage); >+ }); >+ [% END %] > //]]> > </script> >-[% INCLUDE 'calendar.inc' %] >+ [% PROCESS 'password_check.inc' new_password => 'borrower_password', category_selector => '#borrower_categorycode', RequireStrongPassword => patron.category.effective_require_strong_password, minPasswordLength => patron.category.effective_min_password_length %] >+ > [% END %] >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-passwd.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-passwd.tt >index 5c1816f89c..73579f1a57 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-passwd.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-passwd.tt >@@ -57,10 +57,10 @@ > > <form action="/cgi-bin/koha/opac-passwd.pl" name="mainform" id="mainform" method="post" autocomplete="off"> > <fieldset> >- [% IF ( Koha.Preference('RequireStrongPassword') ) %] >- <div class="alert alert-info">Your password must contain at least [% Koha.Preference('minPasswordLength') | html %] characters, including UPPERCASE, lowercase and numbers.</div> >+ [% IF ( logged_in_user.category.effective_require_strong_password ) %] >+ <div class="alert alert-info">Your password must contain at least [% logged_in_user.category.effective_min_password_length | html %] characters, including UPPERCASE, lowercase and numbers.</div> > [% ELSE %] >- <div class="alert alert-info">Your password must be at least [% Koha.Preference('minPasswordLength') | html %] characters long.</div> >+ <div class="alert alert-info">Your password must be at least [% logged_in_user.category.effective_min_password_length | html %] characters long.</div> > [% END %] > <label for="Oldkey">Current password:</label> <input type="password" id="Oldkey" size="25" name="Oldkey" /> > <label for="Newkey">New password:</label> <input type="password" id="Newkey" size="25" name="Newkey" /> >@@ -94,8 +94,7 @@ > [% INCLUDE 'opac-bottom.inc' %] > [% BLOCK jsinclude %] > [% Asset.js("lib/jquery/plugins/jquery.validate.min.js") | $raw %] >- [% PROCESS 'password_check.inc' %] >- [% PROCESS 'add_password_check' new_password => 'Newkey' %] >+ [% PROCESS 'password_check.inc' new_password => 'Newkey', minPasswordLength => logged_in_user.category.effective_min_password_length, RequireStrongPassword => logged_in_user.category.effective_require_strong_password %] > <script> > $(document).ready(function() { > $("#mainform").validate({ >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt >index 6e8ff8ae95..3ca70e7881 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt >@@ -107,10 +107,10 @@ > <form action="/cgi-bin/koha/opac-password-recovery.pl" method="post" autocomplete="off"> > <input type="hidden" name="koha_login_context" value="opac" /> > <fieldset> >- [% IF ( Koha.Preference('RequireStrongPassword') ) %] >- <div class="alert alert-info">Your password must contain at least [% Koha.Preference('minPasswordLength') | html %] characters, including UPPERCASE, lowercase and numbers.</div> >+ [% IF ( RequireStrongPassword ) %] >+ <div class="alert alert-info">Your password must contain at least [% minPasswordLength | html %] characters, including UPPERCASE, lowercase and numbers.</div> > [% ELSE %] >- <div class="alert alert-info">Your password must be at least [% Koha.Preference('minPasswordLength') | html %] characters long.</div> >+ <div class="alert alert-info">Your password must be at least [% minPasswordLength | html %] characters long.</div> > [% END %] > <label for="password">New password:</label> > <input type="password" id="password" size="40" name="password" /> >diff --git a/members/memberentry.pl b/members/memberentry.pl >index 985a96446c..7559398678 100755 >--- a/members/memberentry.pl >+++ b/members/memberentry.pl >@@ -368,7 +368,7 @@ if ($op eq 'save' || $op eq 'insert'){ > # the edited values list when editing certain sub-forms. Get it straight > # from the DB if absent. > my $userid = $newdata{ userid } // $borrower_data->{ userid }; >- my $p = $borrowernumber ? Koha::Patrons->find( $borrowernumber ) : Koha::Patron->new; >+ my $p = $borrowernumber ? Koha::Patrons->find( $borrowernumber ) : Koha::Patron->new(); > $p->userid( $userid ); > unless ( $p->has_valid_userid ) { > push @errors, "ERROR_login_exist"; >@@ -379,7 +379,7 @@ if ($op eq 'save' || $op eq 'insert'){ > push @errors, "ERROR_password_mismatch" if ( $password ne $password2 ); > > if ( $password and $password ne '****' ) { >- my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $password ); >+ my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $password, Koha::Patron::Categories->find($categorycode) ); > unless ( $is_valid ) { > push @errors, 'ERROR_password_too_short' if $error eq 'too_short'; > push @errors, 'ERROR_password_too_weak' if $error eq 'too_weak'; >@@ -668,6 +668,8 @@ foreach my $category_type (qw(C A S P I X)) { > push @categoryloop, > { 'categorycode' => $patron_category->categorycode, > 'categoryname' => $patron_category->description, >+ 'effective_min_password_length' => $patron_category->effective_min_password_length, >+ 'effective_require_strong_password' => $patron_category->effective_require_strong_password, > 'categorycodeselected' => > ( defined($categorycode) && $patron_category->categorycode eq $categorycode ), > }; >diff --git a/misc/admin/set_password.pl b/misc/admin/set_password.pl >index 0915143503..feec8f330f 100755 >--- a/misc/admin/set_password.pl >+++ b/misc/admin/set_password.pl >@@ -44,11 +44,6 @@ unless ( $userid or $patron_id or $cardnumber ) { > pod2usage("cardnumber is mandatory") unless $cardnumber; > } > >-unless ($password) { >- my $generator = String::Random->new( rand_gen => \&alt_rand ); >- $password = $generator->randregex('[A-Za-z][A-Za-z0-9_]{6}.[A-Za-z][A-Za-z0-9_]{6}\d'); >-} >- > my $filter; > > if ( $userid ) { >@@ -70,6 +65,14 @@ unless ( $patrons->count > 0 ) { > } > > my $patron = $patrons->next; >+ >+unless ($password) { >+ my $generator = String::Random->new( rand_gen => \&alt_rand ); >+ my $n = $patron->category->effective_min_password_length; >+ $n = $n<6?6:$n; >+ $password = $generator->randregex('[A-Za-z][A-Za-z0-9_]{6}.[A-Za-z][A-Za-z0-9_]{'.$n.'}\d'); >+} >+ > $patron->set_password({ password => $password, skip_validation => 1 }); > > print $patron->userid . " " . $password . "\n"; >diff --git a/opac/opac-memberentry.pl b/opac/opac-memberentry.pl >index a076cd31b0..37ade6703f 100755 >--- a/opac/opac-memberentry.pl >+++ b/opac/opac-memberentry.pl >@@ -41,7 +41,7 @@ use Koha::Patron::Attributes; > use Koha::Patron::Images; > use Koha::Patron::Modification; > use Koha::Patron::Modifications; >-use Koha::Patrons; >+use Koha::Patron::Categories; > use Koha::Token; > > my $cgi = new CGI; >@@ -177,7 +177,7 @@ if ( $action eq 'create' ) { > $verification_token = md5_hex( time().{}.rand().{}.$$ ); > } > >- $borrower{password} = Koha::AuthUtils::generate_password unless $borrower{password}; >+ $borrower{password} = Koha::AuthUtils::generate_password(Koha::Patron::Categories->find($borrower{categorycode})) unless $borrower{password}; > $borrower{verification_token} = $verification_token; > > Koha::Patron::Modification->new( \%borrower )->store(); >@@ -216,7 +216,7 @@ if ( $action eq 'create' ) { > ); > > $borrower{categorycode} ||= C4::Context->preference('PatronSelfRegistrationDefaultCategory'); >- $borrower{password} ||= Koha::AuthUtils::generate_password; >+ $borrower{password} ||= Koha::AuthUtils::generate_password(Koha::Patron::Categories->find($borrower{categorycode})); > my $consent_dt = delete $borrower{gdpr_proc_consent}; > my $patron = Koha::Patron->new( \%borrower )->store; > Koha::Patron::Consent->new({ borrowernumber => $patron->borrowernumber, type => 'GDPR_PROCESSING', given_on => $consent_dt })->store if $consent_dt; >@@ -467,7 +467,7 @@ sub CheckForInvalidFields { > push( @invalidFields, "password_match" ); > } > if ( $borrower->{'password'} ) { >- my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $borrower->{password} ); >+ my ( $is_valid, $error ) = Koha::AuthUtils::is_password_valid( $borrower->{password}, Koha::Patron::Categories->find($borrower->{categorycode}) ); > unless ( $is_valid ) { > push @invalidFields, 'password_too_short' if $error eq 'too_short'; > push @invalidFields, 'password_too_weak' if $error eq 'too_weak'; >diff --git a/opac/opac-password-recovery.pl b/opac/opac-password-recovery.pl >index a695165b56..d688e365a9 100755 >--- a/opac/opac-password-recovery.pl >+++ b/opac/opac-password-recovery.pl >@@ -54,7 +54,6 @@ if ( $query->param('sendEmail') || $query->param('resendEmail') ) { > #try with the main email > my $borrower; > my $search_results; >- > # Find the borrower by userid, card number, or email > if ($username) { > $search_results = Koha::Patrons->search( { -or => { userid => $username, cardnumber => $username }, login_attempts => { '!=', Koha::Patron::ADMINISTRATIVE_LOCKOUT } } ); >@@ -124,6 +123,7 @@ if ( $query->param('sendEmail') || $query->param('resendEmail') ) { > if ($hasError) { > $template->param( > hasError => 1, >+ > errNoBorrowerFound => $errNoBorrowerFound, > errTooManyEmailFound => $errTooManyEmailFound, > errAlreadyStartRecovery => $errAlreadyStartRecovery, >@@ -154,13 +154,18 @@ elsif ( $query->param('passwordReset') ) { > ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey); > > my $error; >+ my $min_password_length = C4::Context->preference('minPasswordPreference'); >+ my $require_strong_password = C4::Context->preference('RequireStrongPassword'); > if ( not $borrower_number ) { > $error = 'errLinkNotValid'; > } elsif ( $password ne $repeatPassword ) { > $error = 'errPassNotMatch'; > } else { >+ my $borrower = Koha::Patrons->find($borrower_number); >+ $min_password_length = $borrower->category->effective_min_password_length; >+ $require_strong_password = $borrower->category->effective_require_strong_password; > try { >- Koha::Patrons->find($borrower_number)->set_password({ password => $password }); >+ $borrower->set_password({ password => $password }); > > CompletePasswordRecovery($uniqueKey); > $template->param( >@@ -187,6 +192,8 @@ elsif ( $query->param('passwordReset') ) { > uniqueKey => $uniqueKey, > hasError => 1, > $error => 1, >+ minPasswordLength => $min_password_length, >+ RequireStrongPassword => $require_strong_password > ); > } > } >@@ -198,6 +205,8 @@ elsif ($uniqueKey) { #reset password form > $errLinkNotValid = 1; > } > >+ my $borrower = Koha::Patrons->find($borrower_number); >+ > $template->param( > new_password => 1, > email => $email, >@@ -205,6 +214,8 @@ elsif ($uniqueKey) { #reset password form > username => $username, > errLinkNotValid => $errLinkNotValid, > hasError => ( $errLinkNotValid ? 1 : 0 ), >+ minPasswordLength => $borrower->category->effective_min_password_length, >+ RequireStrongPassword => $borrower->category->effective_require_strong_password > ); > } > else { #password recovery form (to send email) >diff --git a/opac/opac-registration-verify.pl b/opac/opac-registration-verify.pl >index d408d5c5ae..f5cd15acd7 100755 >--- a/opac/opac-registration-verify.pl >+++ b/opac/opac-registration-verify.pl >@@ -27,6 +27,7 @@ use Koha::AuthUtils; > use Koha::Patrons; > use Koha::Patron::Consent; > use Koha::Patron::Modifications; >+use Koha::Patron::Categories; > > my $cgi = new CGI; > my $dbh = C4::Context->dbh; >@@ -59,7 +60,7 @@ if ( > ); > > my $patron_attrs = $m->unblessed; >- $patron_attrs->{password} ||= Koha::AuthUtils::generate_password; >+ $patron_attrs->{password} ||= Koha::AuthUtils::generate_password(Koha::Patron::Categories->find($patron_attrs->{categorycode})); > my $consent_dt = delete $patron_attrs->{gdpr_proc_consent}; > $patron_attrs->{categorycode} ||= C4::Context->preference('PatronSelfRegistrationDefaultCategory'); > delete $patron_attrs->{timestamp}; >-- >2.11.0
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 23816
:
103099
|
103100
|
103101
|
103102
|
103103
|
103104
|
103108
|
103109
|
103110
|
103111
|
103112
|
103113
|
103805
|
103806
|
103807
|
103808
|
103809
|
103810
|
107158
|
107159
|
107160
|
107161
|
107162
|
107163
|
108554
|
108555
|
108556
|
108557
|
108558
|
108559
|
108571
|
108572
|
109243
|
109244
|
109245
|
109249
|
109250
|
109251
|
109252
|
109253
|
109254
|
109255
|
109256
|
109257
|
109520
|
109521
|
109522
|
109523
|
109524
|
109525
|
109526
|
109527
|
109528
|
109833
|
109834