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

(-)a/Koha/Auth/TwoFactorAuth.pm (+45 lines)
Lines 19-28 use Modern::Perl; Link Here
19
use GD::Barcode;
19
use GD::Barcode;
20
use MIME::Base64 qw( encode_base64 );
20
use MIME::Base64 qw( encode_base64 );
21
21
22
use C4::Letters;
22
use Koha::Exceptions;
23
use Koha::Exceptions;
24
use Koha::Exceptions::Patron;
23
25
24
use base qw( Auth::GoogleAuth );
26
use base qw( Auth::GoogleAuth );
25
27
28
use constant CONFIRM_NOTICE_REG => '2FA_REGISTER';
29
use constant CONFIRM_NOTICE_DEREG => '2FA_DEREGISTER';
30
26
=head1 NAME
31
=head1 NAME
27
32
28
Koha::Auth::TwoFactorAuth- Koha class deal with Two factor authentication
33
Koha::Auth::TwoFactorAuth- Koha class deal with Two factor authentication
Lines 33-39 use Koha::Auth::TwoFactorAuth; Link Here
33
38
34
my $secret = Koha::AuthUtils::generate_salt( 'weak', 16 );
39
my $secret = Koha::AuthUtils::generate_salt( 'weak', 16 );
35
my $auth = Koha::Auth::TwoFactorAuth->new({ patron => $patron, secret => $secret });
40
my $auth = Koha::Auth::TwoFactorAuth->new({ patron => $patron, secret => $secret });
41
my $image_src = $auth->qr_code;
36
my $ok = $auth->verify( $pin_code, 1 );
42
my $ok = $auth->verify( $pin_code, 1 );
43
$auth->send_confirm_notice({ patron => $patron });
37
44
38
It's based on Auth::GoogleAuth
45
It's based on Auth::GoogleAuth
39
46
Lines 101-104 sub qr_code { Link Here
101
    return "data:image/png;base64,". encode_base64( $data, q{} ); # does not contain newlines
108
    return "data:image/png;base64,". encode_base64( $data, q{} ); # does not contain newlines
102
}
109
}
103
110
111
=head3 send_confirm_notice
112
113
    $auth->send_confirm_notice({ patron => $p, deregister => 1 });
114
115
    Send a notice to confirm (de)registering 2FA.
116
    Parameter patron is mandatory.
117
    If there is no deregister param, a register notice is sent.
118
    If the patron has no email address, we throw an exception.
119
120
=cut
121
122
sub send_confirm_notice {
123
    my ( $self, $params ) = @_;
124
    my $patron = $params->{patron};
125
    my $deregister = $params->{deregister};
126
127
    Koha::Exceptions::MissingParameter->throw("Mandatory patron parameter missing")
128
        unless $patron && ref($patron) eq 'Koha::Patron';
129
    Koha::Exceptions::Patron::MissingEmailAddress->throw
130
        if !$patron->notice_email_address;
131
132
    my $letter = C4::Letters::GetPreparedLetter (
133
        module => 'members', # called patrons on interface
134
        letter_code => $deregister ? CONFIRM_NOTICE_DEREG : CONFIRM_NOTICE_REG,
135
        branchcode => $patron->branchcode,
136
        lang => $patron->lang,
137
        tables => {
138
            'branches'    => $patron->branchcode,
139
            'borrowers'   => $patron->id,
140
        },
141
    );
142
    C4::Letters::EnqueueLetter({
143
        letter         => $letter,
144
        borrowernumber => $patron->id,
145
        message_transport_type => 'email',
146
    }) or warn "Couldnt enqueue 2FA notice for patron ". $patron->id;
147
}
148
104
1;
149
1;
(-)a/Koha/Exceptions/Patron.pm (+3 lines)
Lines 8-13 use Exception::Class ( Link Here
8
    'Koha::Exceptions::Patron' => {
8
    'Koha::Exceptions::Patron' => {
9
        isa => 'Koha::Exception',
9
        isa => 'Koha::Exception',
10
    },
10
    },
11
    'Koha::Exceptions::Patron::MissingEmailAddress' => {
12
        description => "Patron has no email address",
13
    },
11
    'Koha::Exceptions::Patron::FailedDelete' => {
14
    'Koha::Exceptions::Patron::FailedDelete' => {
12
        isa         => 'Koha::Exceptions::Patron',
15
        isa         => 'Koha::Exceptions::Patron',
13
        description => "Deleting patron failed"
16
        description => "Deleting patron failed"
(-)a/members/two_factor_auth.pl (+7 lines)
Lines 72-77 if ( $op eq 'register-2FA' ) { Link Here
72
        $logged_in_user->secret($secret32);
72
        $logged_in_user->secret($secret32);
73
        $logged_in_user->auth_method('two-factor')->store;
73
        $logged_in_user->auth_method('two-factor')->store;
74
        $op = 'registered';
74
        $op = 'registered';
75
        if( $logged_in_user->notice_email_address ) {
76
            $auth->send_confirm_notice({ patron => $logged_in_user });
77
        }
75
    }
78
    }
76
    else {
79
    else {
77
        $template->param( invalid_pin => 1, );
80
        $template->param( invalid_pin => 1, );
Lines 97-104 if ( $op eq 'enable-2FA' ) { Link Here
97
elsif ( $op eq 'disable-2FA' ) {
100
elsif ( $op eq 'disable-2FA' ) {
98
    output_and_exit( $cgi, $cookie, $template, 'wrong_csrf_token' )
101
    output_and_exit( $cgi, $cookie, $template, 'wrong_csrf_token' )
99
        unless Koha::Token->new->check_csrf($csrf_pars);
102
        unless Koha::Token->new->check_csrf($csrf_pars);
103
    my $auth = Koha::Auth::TwoFactorAuth->new({ patron => $logged_in_user });
100
    $logged_in_user->secret(undef);
104
    $logged_in_user->secret(undef);
101
    $logged_in_user->auth_method('password')->store;
105
    $logged_in_user->auth_method('password')->store;
106
    if( $logged_in_user->notice_email_address ) {
107
        $auth->send_confirm_notice({ patron => $logged_in_user, deregister => 1 });
108
    }
102
}
109
}
103
110
104
$template->param(
111
$template->param(
(-)a/t/db_dependent/Koha/Auth/TwoFactorAuth.t (-2 / +37 lines)
Lines 1-15 Link Here
1
use Modern::Perl;
1
use Modern::Perl;
2
use Test::More tests => 2;
2
use Test::More tests => 3;
3
use Test::Exception;
3
use Test::Exception;
4
use Test::MockModule;
4
5
5
use t::lib::Mocks;
6
use t::lib::Mocks;
6
use t::lib::TestBuilder;
7
use t::lib::TestBuilder;
7
8
8
use Koha::Database;
9
use Koha::Database;
9
use Koha::Auth::TwoFactorAuth;
10
use Koha::Auth::TwoFactorAuth;
11
use Koha::Exceptions;
12
use Koha::Exceptions::Patron;
13
use Koha::Notice::Messages;
10
14
11
our $schema = Koha::Database->new->schema;
15
our $schema = Koha::Database->new->schema;
12
our $builder = t::lib::TestBuilder->new;
16
our $builder = t::lib::TestBuilder->new;
17
our $mocked_stuffer =  Test::MockModule->new('Email::Stuffer');
18
$mocked_stuffer->mock( 'send_or_die', sub { warn 'I do not send mails now'; } );
13
19
14
subtest 'new' => sub {
20
subtest 'new' => sub {
15
    plan tests => 10;
21
    plan tests => 10;
Lines 79-81 subtest 'qr_code' => sub { Link Here
79
85
80
    $schema->storage->txn_rollback;
86
    $schema->storage->txn_rollback;
81
};
87
};
82
- 
88
89
subtest 'send_confirm_notice' => sub {
90
    plan tests => 4;
91
    $schema->storage->txn_begin;
92
93
    t::lib::Mocks::mock_preference('TwoFactorAuthentication', 1);
94
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
95
    $patron->secret('you2wont2guess2it'); # this is base32 btw
96
    $patron->auth_method('two-factor');
97
    $patron->store;
98
    my $auth = Koha::Auth::TwoFactorAuth->new({ patron => $patron });
99
100
    # Trivial tests: no patron, no email
101
    throws_ok { $auth->send_confirm_notice; }
102
        'Koha::Exceptions::MissingParameter',
103
        'Croaked on missing patron';
104
    $patron->set({ email => undef, emailpro => undef, B_email => undef });
105
    throws_ok { $auth->send_confirm_notice({ patron => $patron }) }
106
        'Koha::Exceptions::Patron::MissingEmailAddress',
107
        'Croaked on missing email';
108
109
    $patron->email('noreply@doof.nl')->store;
110
    $auth->send_confirm_notice({ patron => $patron });
111
    is( Koha::Notice::Messages->search({ borrowernumber => $patron->id, letter_code => '2FA_REGISTER' })->count, 1, 'Found message' );
112
    $auth->send_confirm_notice({ patron => $patron, deregister => 1 });
113
    is( Koha::Notice::Messages->search({ borrowernumber => $patron->id, letter_code => '2FA_DEREGISTER' })->count, 1, 'Found message' );
114
115
    $schema->storage->txn_rollback;
116
    $mocked_stuffer->unmock;
117
};

Return to bug 29894