Koha/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-password.tt
Magnus Enger c98c1994ea
Bug 22706: Add plugin hooks for Norwegian national patron database
The main point of this patch is to make it possible to integrate Koha
with the Norwegian national patron database (NNPDB). Code for this was
earlier introduced in Bug 11401 and removed again in Bug 21068.

To test this is mainly a question of spotting regressions, it should
still be possible to set and change a password in all possible ways:
- Setting a password for a new user
- Changing a password in the staff client
- Changing a password in the OPAC
If these work as expected, everything should be OK.

A nice side effect of this work is that it will allow for plugins that
validate passwords. I have created a tiny plugin that enforces PIN
codes of 4 digits. (Yeah, I know, those are the worst passwords, but
some libraries do require them.) It is published here:
https://github.com/Libriotech/koha-plugin-pin
To test this way, install the plugin and try to change the password
of an exsisting user to something that is not a 4 digit PIN. You
should get an error that says "The password was rejected by a plugin".

Signed-off-by: Brendan Gallagher <brendan@bywatersolutions.com>

Updated 2019-10-23:
- Moved the plugin checks to before the call to $self->SUPER::store to
  make sure patrons are not saved if the password fails a plugin check
- Made the plugin checks in set_password respect skip_validation while
  retaining the functionality for NNPDB

Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
2019-10-29 12:19:49 +00:00

163 lines
6.9 KiB
Text

[% USE raw %]
[% USE Asset %]
[% USE Koha %]
[% USE Branches %]
[% SET footerjs = 1 %]
[% INCLUDE 'doc-head-open.inc' %]
<title>Koha &rsaquo; Patrons &rsaquo; [% IF ( newpassword ) %]Password updated [% ELSE %]Update password for [% patron.surname | html %], [% patron.firstname | html %][% END %]</title>
[% INCLUDE 'doc-head-close.inc' %]
</head>
<body id="pat_member-password" class="pat">
[% INCLUDE 'header.inc' %]
[% INCLUDE 'patron-search.inc' %]
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> &rsaquo; <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | html %]">[% patron.firstname | html %] [% patron.surname | html %]</a> &rsaquo; [% IF ( newpassword ) %]Password Updated[% ELSE %]Change username and/or password[% END %]</div>
<div class="main container-fluid">
<div class="row">
<div class="col-sm-10 col-sm-push-2">
<main>
[% INCLUDE 'members-toolbar.inc' %]
[% IF ( newpassword ) %]
<h1>Password Updated</h1>
[% ELSE %]
<form method="post" id="changepasswordf" action="/cgi-bin/koha/members/member-password.pl">
<input type="hidden" name="destination" value="[% destination | html %]" />
<input type="hidden" name="borrowernumber" id="borrowernumber" value="[% patron.borrowernumber | html %]" />
[% IF ( errormsg ) %]
<div class="dialog alert">
<h4>The following errors have occurred:</h4>
<ul>
[% IF ( BADUSERID ) %]
<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>
[% END %]
[% IF ( ERROR_password_too_weak ) %]
<li id="ERROR_weak_password">Password must contain at least one digit, one lowercase and one uppercase.</li>
[% END %]
[% IF ( ERROR_password_has_whitespaces ) %]
<li id="ERROR_weak_password">Password must not contain leading or trailing whitespaces.</li>
[% END %]
[% IF ( ERROR_from_plugin ) %]
<li id="ERROR_from_plugin">The password was rejected by a plugin.</li>
[% END %]
[% IF ( NOPERMISSION ) %]
<li>You do not have permission to edit this patron's login information.</li>
[% END %]
[% IF ( NOMATCH ) %]
<li><strong>The passwords entered do not match</strong>. Please re-enter the new password.</li>
[% END %]
</ul>
</div>
[% END %]
<fieldset class="brief"><legend>Change username and/or password for [% patron.firstname | html %] [% patron.surname | html %]</legend>
<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') _ ',}' %]
[% END %]
<li>
<label for="newpassword">New password:</label>
<div class="hint">Koha cannot display existing passwords. Leave the field blank to leave password unchanged.</div>
<input name="newpassword" id="newpassword" type="password" size="20" />
</li>
<li>
<label for="newpassword2">Confirm new password:</label>
<input name="newpassword2" id="newpassword2" type="password" size="20" />
</li>
</ol>
</fieldset>
<fieldset class="action">
<input type="hidden" name="csrf_token" value="[% csrf_token | html %]" />
<input type="submit" value="Save" />
<a class="cancel" href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | html %]">Cancel</a>
</fieldset>
</form>[% END %]
<div class="loading hide"><strong>Processing...</strong><img src="[% interface | html %]/[% theme | html %]/img/loading.gif" alt="" /></div>
</main>
</div> <!-- /.col-sm-10.col-sm-push-2 -->
<div class="col-sm-2 col-sm-pull-10">
<aside>
[% INCLUDE 'circ-menu.inc' %]
</aside>
</div> <!-- /.col-sm-2.col-sm-pull-10 -->
</div> <!-- /.row -->
[% MACRO jsinclude BLOCK %]
[% INCLUDE 'str/members-menu.inc' %]
[% Asset.js("js/members-menu.js") | $raw %]
<script>
function generate_password() {
// Always generate a strong password
var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
var length = [% Koha.Preference('minPasswordLength') | html %];
if ( length < 8 ) length = 8;
var password='';
for ( var i = 0 ; i < length ; i++){
password += chars.charAt(Math.floor(Math.random()*chars.length));
}
return password;
}
$(document).ready(function() {
$("body").on('click', "#fillrandom",function(e) {
e.preventDefault();
var password = '';
var pattern_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{[% Koha.Preference('minPasswordLength') | html %],}/;
while ( ! pattern_regex.test( password ) ) {
password = generate_password();
}
$("#newpassword").val(password);
$("#newpassword").attr('type', 'text');
$("#newpassword2").val(password);
$("#newpassword2").attr('type', 'text');
});
$("div.hint").eq(0).after(" <div class=\"hint\"><a href=\"#\" id=\"fillrandom\">"+_("Click to fill with a randomly generated suggestion. ")+"<strong>"+_("Passwords will be displayed as text")+"</strong>.</a></div>");
$(document).ajaxStart(function () {
$("input[name^=newpassword]").hide();
$("label[for=newpassword2]").hide();
$(".hint:last").after($(".loading").show());
});
$(document).ajaxStop(function () {
$("input[name^=newpassword]").show();
$("label[for=newpassword2]").show();
$(".loading").hide();
$("label.error").hide();
});
[% IF NOMATCH %]
$("#newpassword").addClass('focus');
[% END %]
$("#changepasswordf").validate({
rules: {
newpassword: {
password_strong: true,
password_no_spaces: true
},
newpassword2: {
password_match: true
}
}
});
});
</script>
[% PROCESS 'password_check.inc' %]
[% PROCESS 'add_password_check' new_password => 'newpassword' %]
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]