@@ -, +, @@ --- .../prog/en/includes/members-toolbar.inc | 4 + .../en/modules/members/two_factor_auth.tt | 115 ++++++++++++++++++ members/two_factor_auth.pl | 106 ++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/two_factor_auth.tt create mode 100644 members/two_factor_auth.pl --- a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc @@ -52,6 +52,10 @@
  • Set permissions
  • [% END %] + [% IF Koha.Preference('TwoFactorAuthentication') && logged_in_user.borrowernumber == patron.borrowernumber %] +
  • Enable Two-Factor Authentication
  • + [% END %] + [% IF CAN_user_borrowers_edit_borrowers && useDischarge %]
  • Discharge
  • [% END %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/two_factor_auth.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/members/two_factor_auth.tt @@ -0,0 +1,115 @@ +[% USE raw %] +[% USE Koha %] +[% USE Asset %] +[% SET footerjs = 1 %] +[% INCLUDE 'doc-head-open.inc' %] +Two-Factor Authentication › Patrons › Koha +[% INCLUDE 'doc-head-close.inc' %] + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'patron-search.inc' %] + + + +
    +
    +
    +
    + + [% INCLUDE 'members-toolbar.inc' %] + + [% IF op == 'register' %] +

    Register Two-Factor Authenticator

    +
    +

    We recommend cloud-based mobile authenticator apps such as Authy, Duo Mobile, and LastPass. They can restore access if you lose your hardware device.

    +

    Can't scan the code?

    +

    To add the entry manually, provide the following details to the application on your phone.

    +

    Account: [% issuer %]

    +

    Key: [% key_id %]

    +

    Time based: Yes

    +
    + + [% IF invalid_pin %] +
    Invalid pin code
    + [% END %] +
    +
    + + + +
      +
    1. + + +
    2. +
    3. + + +
    4. +
    +
    +
    + + Cancel +
    +
    + [% ELSE %] +

    Two-Factor Authentication

    + [% IF patron.auth_method == "two-factor" %] +
    Status: Enabled
    + +
    + + + +
    + [% ELSE %] +
    Status: Disabled
    + +
    + + + +
    + + [% END %] + [% END %] +
    +
    + +
    + +
    +
    + + +[% MACRO jsinclude BLOCK %] + [% INCLUDE 'str/members-menu.inc' %] + [% Asset.js("js/members-menu.js") | $raw %] + +[% END %] + +[% INCLUDE 'intranet-bottom.inc' %] --- a/members/two_factor_auth.pl +++ a/members/two_factor_auth.pl @@ -0,0 +1,106 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use CGI; + +use C4::Auth qw( get_template_and_user ); +use C4::Output qw( output_and_exit output_html_with_http_headers ); + +use Koha::Patrons; +use Koha::Auth::TwoFactorAuth; + +my $cgi = CGI->new; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => 'members/two_factor_auth.tt', + query => $cgi, + type => 'intranet', + flagsrequired => { editcatalogue => '*' }, + } +); + +unless ( C4::Context->preference('TwoFactorAuthentication') ) { + print $cgi->redirect("/cgi-bin/koha/errors/404.pl"); + exit; +} + +my $logged_in_user = Koha::Patrons->find($loggedinuser); + +my $op = $cgi->param('op') // ''; + +if ( $op eq 'register-2FA' ) { + my $pin_code = $cgi->param('pin_code'); + my $secret32 = $cgi->param('secret32'); + my $auth = Koha::Auth::TwoFactorAuth::get_auth( + { patron => $logged_in_user, secret32 => $secret32 } ); + + my $verified = $auth->verify( + $pin_code, + 1, # range + $secret32, + undef, # timestamp (defaults to now) + 30, # interval (default 30) + ); + + if ($verified) { + $logged_in_user->secret($secret32); + $op = 'registered'; + + # FIXME Generate a (new?) secret + $logged_in_user->auth_method('two-factor')->store; + } + else { + $template->param( invalid_pin => 1, ); + $op = 'enable-2FA'; + } +} + +if ( $op eq 'enable-2FA' ) { + + my $secret = Koha::AuthUtils::generate_salt( 'weak', 16 ); + my $auth = Koha::Auth::TwoFactorAuth::get_auth( + { patron => $logged_in_user, secret => $secret } ); + + my $secret32 = $auth->generate_secret32; + my $qr_code_url = + $auth->qr_code( $secret32, $auth->key_id, $auth->issuer, ); + + $template->param( + issuer => $auth->issuer, + key_id => $auth->key_id, + secret32 => $secret32, + qr_code_url => $qr_code_url, + ); + $auth->clear; + $op = 'register'; +} +elsif ( $op eq 'disable-2FA' ) { + $logged_in_user->auth_method('password')->store; +} + +$template->param( + csrf_token => Koha::Token->new->generate_csrf( + { session_id => scalar $cgi->cookie('CGISESSID') } + ), + patron => $logged_in_user, + op => $op, +); + +output_html_with_http_headers $cgi, $cookie, $template->output; --