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

(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/two_factor_auth.tt (-48 / +57 lines)
Lines 33-92 Link Here
33
33
34
                [% INCLUDE 'members-toolbar.inc' %]
34
                [% INCLUDE 'members-toolbar.inc' %]
35
35
36
                [% IF op == 'register' %]
36
                <h1>Manage two-factor authentication</h1>
37
                    <h1>Register two-factor authenticator</h1>
38
                    <div class="dialog message">
39
                        <p>We recommend cloud-based mobile authenticator apps such as Authy, Duo Mobile, and LastPass. They can restore access if you lose your hardware device.</p>
40
                        <p>Can't scan the code?</p>
41
                        <p>To add the entry manually, provide the following details to the application on your phone.</p>
42
                        <p>Account: [% issuer | html %]</p>
43
                        <p>Key: [% key_id | html %]</p>
44
                        <p>Time based: Yes</p>
45
                    </div>
46
37
47
                    [% IF invalid_pin %]
38
                [% IF ( missing_key ) %]
48
                        <div class="dialog error">Invalid pin code</div>
39
                    <div id="error_message" class="dialog message">
49
                    [% END %]
40
                        <p>
50
                    <form id="two-factor-auth" action="/cgi-bin/koha/members/two_factor_auth.pl" method="post">
41
                            Operation cannot proceed, please define an encryption key in your configuration.
51
                        <fieldset class="rows">
42
                        </p>
52
                            <input type="hidden" name="csrf_token" value="[% csrf_token | html %]" />
43
                    </div>
53
                            <input type="hidden" name="op" value="register-2FA" />
54
                            <input type="hidden" name="secret32" value="[% secret32 | html %]" />
55
                            <ol>
56
                                <li>
57
                                    <label for="qr_code">QR code: </label>
58
                                    <img id="qr_code" src="[% qr_code | $raw %]" />
59
                                </li>
60
                                <li>
61
                                    <label for="pin_code">Pin code: </label>
62
                                    <input type="text" id="pin_code" name="pin_code" value="" />
63
                                </li>
64
                            </ol>
65
                        </fieldset>
66
                        <fieldset class="action">
67
                            <input type="submit" value="Register with two-factor app" />
68
                            <a class="cancel" href="/cgi-bin/koha/members/two_factor_auth.pl">Cancel</a>
69
                        </fieldset>
70
                    </form>
71
                [% ELSE %]
44
                [% ELSE %]
72
                    <h1>Two-factor authentication</h1>
73
                    [% IF patron.auth_method == "two-factor" %]
74
                        <div class="two-factor-status">Status: Enabled</div>
75
45
46
                    [% IF op == 'register' %]
47
                        <div class="dialog message">
48
                            <p>We recommend cloud-based mobile authenticator apps such as Authy, Duo Mobile, and LastPass. They can restore access if you lose your hardware device.</p>
49
                            <p>Can't scan the code?</p>
50
                            <p>To add the entry manually, provide the following details to the application on your phone.</p>
51
                            <p>Account: [% issuer | html %]</p>
52
                            <p>Key: [% key_id | html %]</p>
53
                            <p>Time based: Yes</p>
54
                        </div>
55
    
56
                        [% IF invalid_pin %]
57
                            <div class="dialog error">Invalid pin code</div>
58
                        [% END %]
76
                        <form id="two-factor-auth" action="/cgi-bin/koha/members/two_factor_auth.pl" method="post">
59
                        <form id="two-factor-auth" action="/cgi-bin/koha/members/two_factor_auth.pl" method="post">
77
                            <input type="hidden" name="csrf_token" value="[% csrf_token | html %]" />
60
                            <fieldset class="rows">
78
                            <input type="hidden" name="op" value="disable-2FA" />
61
                                <input type="hidden" name="csrf_token" value="[% csrf_token | html %]" />
79
                            <input type="submit" value="Disable two-factor authentication" />
62
                                <input type="hidden" name="op" value="register-2FA" />
63
                                <input type="hidden" name="secret32" value="[% secret32 | html %]" />
64
                                <ol>
65
                                    <li>
66
                                        <label for="qr_code">QR code: </label>
67
                                        <img id="qr_code" src="[% qr_code | $raw %]" />
68
                                    </li>
69
                                    <li>
70
                                        <label for="pin_code">Pin code: </label>
71
                                        <input type="text" id="pin_code" name="pin_code" value="" />
72
                                    </li>
73
                                </ol>
74
                            </fieldset>
75
                            <fieldset class="action">
76
                                <input type="submit" value="Register with two-factor app" />
77
                                <a class="cancel" href="/cgi-bin/koha/members/two_factor_auth.pl">Cancel</a>
78
                            </fieldset>
80
                        </form>
79
                        </form>
81
                    [% ELSE %]
80
                    [% ELSE %]
82
                        <div class="two-factor-status">Status: Disabled</div>
81
                        [% IF patron.auth_method == "two-factor" %]
83
82
                            <div class="two-factor-status">Status: Enabled</div>
84
                        <form id="two-factor-auth" action="/cgi-bin/koha/members/two_factor_auth.pl" method="post">
83
    
85
                            <input type="hidden" name="csrf_token" value="[% csrf_token | html %]" />
84
                            <form id="two-factor-auth" action="/cgi-bin/koha/members/two_factor_auth.pl" method="post">
86
                            <input type="hidden" name="op" value="enable-2FA" />
85
                                <input type="hidden" name="csrf_token" value="[% csrf_token | html %]" />
87
                            <input type="submit" value="Enable two-factor authentication" />
86
                                <input type="hidden" name="op" value="disable-2FA" />
88
                        </form>
87
                                <input type="submit" value="Disable two-factor authentication" />
89
88
                            </form>
89
                        [% ELSE %]
90
                            <div class="two-factor-status">Status: Disabled</div>
91
    
92
                            <form id="two-factor-auth" action="/cgi-bin/koha/members/two_factor_auth.pl" method="post">
93
                                <input type="hidden" name="csrf_token" value="[% csrf_token | html %]" />
94
                                <input type="hidden" name="op" value="enable-2FA" />
95
                                <input type="submit" value="Enable two-factor authentication" />
96
                            </form>
97
    
98
                        [% END %]
90
                    [% END %]
99
                    [% END %]
91
                [% END %]
100
                [% END %]
92
            </main>
101
            </main>
(-)a/members/two_factor_auth.pl (-74 / +93 lines)
Lines 42-127 unless ( C4::Context->preference('TwoFactorAuthentication') ) { Link Here
42
    exit;
42
    exit;
43
}
43
}
44
44
45
output_and_exit( $cgi, $cookie, $template, 'Entry encryption_key is missing in koha-conf.xml' )
46
    if !C4::Context->config('encryption_key');
47
48
my $logged_in_user = Koha::Patrons->find($loggedinuser);
45
my $logged_in_user = Koha::Patrons->find($loggedinuser);
46
my $op             = $cgi->param('op') // '';
49
47
50
my $op = $cgi->param('op') // '';
48
if ( !C4::Context->config('encryption_key') ) {
51
my $csrf_pars = {
49
    $template->param( missing_key => 1 );
52
    session_id => scalar $cgi->cookie('CGISESSID'),
50
}
53
    token  => scalar $cgi->param('csrf_token'),
51
else {
54
};
52
55
53
    my $csrf_pars = {
56
if ( $op eq 'register-2FA' ) {
54
        session_id => scalar $cgi->cookie('CGISESSID'),
57
    output_and_exit( $cgi, $cookie, $template, 'wrong_csrf_token' )
55
        token      => scalar $cgi->param('csrf_token'),
58
        unless Koha::Token->new->check_csrf($csrf_pars);
56
    };
59
57
60
    my $pin_code = $cgi->param('pin_code');
58
    if ( $op eq 'register-2FA' ) {
61
    my $secret32 = $cgi->param('secret32');
59
        output_and_exit( $cgi, $cookie, $template, 'wrong_csrf_token' )
62
    my $auth     = Koha::Auth::TwoFactorAuth->new(
60
          unless Koha::Token->new->check_csrf($csrf_pars);
63
        { patron => $logged_in_user, secret32 => $secret32 } );
61
64
62
        my $pin_code = $cgi->param('pin_code');
65
    my $verified = $auth->verify(
63
        my $secret32 = $cgi->param('secret32');
66
        $pin_code,
64
        my $auth     = Koha::Auth::TwoFactorAuth->new(
67
        1,    # range
65
            { patron => $logged_in_user, secret32 => $secret32 } );
68
        $secret32,
66
69
        undef,    # timestamp (defaults to now)
67
        my $verified = $auth->verify(
70
        30,       # interval (default 30)
68
            $pin_code,
71
    );
69
            1,        # range
72
70
            $secret32,
73
    if ($verified) {
71
            undef,    # timestamp (defaults to now)
74
        # FIXME Generate a (new?) secret
72
            30,       # interval (default 30)
75
        $logged_in_user->encode_secret($secret32);
73
        );
76
        $logged_in_user->auth_method('two-factor')->store;
74
77
        $op = 'registered';
75
        if ($verified) {
78
        if( $logged_in_user->notice_email_address ) {
76
79
            $logged_in_user->queue_notice({
77
            # FIXME Generate a (new?) secret
80
                letter_params => {
78
            $logged_in_user->encode_secret($secret32);
81
                    module => 'members', letter_code => '2FA_ENABLE',
79
            $logged_in_user->auth_method('two-factor')->store;
82
                    branchcode => $logged_in_user->branchcode, lang => $logged_in_user->lang,
80
            $op = 'registered';
83
                    tables => { branches => $logged_in_user->branchcode, borrowers => $logged_in_user->id },
81
            if ( $logged_in_user->notice_email_address ) {
84
                },
82
                $logged_in_user->queue_notice(
85
                message_transports => [ 'email' ],
83
                    {
86
            });
84
                        letter_params => {
85
                            module      => 'members',
86
                            letter_code => '2FA_ENABLE',
87
                            branchcode  => $logged_in_user->branchcode,
88
                            lang        => $logged_in_user->lang,
89
                            tables      => {
90
                                branches  => $logged_in_user->branchcode,
91
                                borrowers => $logged_in_user->id
92
                            },
93
                        },
94
                        message_transports => ['email'],
95
                    }
96
                );
97
            }
98
        }
99
        else {
100
            $template->param( invalid_pin => 1, );
101
            $op = 'enable-2FA';
87
        }
102
        }
88
    }
103
    }
89
    else {
90
        $template->param( invalid_pin => 1, );
91
        $op = 'enable-2FA';
92
    }
93
}
94
104
95
if ( $op eq 'enable-2FA' ) {
105
    if ( $op eq 'enable-2FA' ) {
96
    my $secret = Koha::AuthUtils::generate_salt( 'weak', 16 );
106
        my $secret = Koha::AuthUtils::generate_salt( 'weak', 16 );
97
    my $auth = Koha::Auth::TwoFactorAuth->new(
107
        my $auth   = Koha::Auth::TwoFactorAuth->new(
98
        { patron => $logged_in_user, secret => $secret } );
108
            { patron => $logged_in_user, secret => $secret } );
109
110
        $template->param(
111
            issuer   => $auth->issuer,
112
            key_id   => $auth->key_id,
113
            qr_code  => $auth->qr_code,
114
            secret32 => $auth->secret32,
99
115
100
    $template->param(
101
        issuer      => $auth->issuer,
102
        key_id      => $auth->key_id,
103
        qr_code  => $auth->qr_code,
104
        secret32    => $auth->secret32,
105
            # IMPORTANT: get secret32 after qr_code call !
116
            # IMPORTANT: get secret32 after qr_code call !
106
    );
117
        );
107
    $auth->clear;
118
        $auth->clear;
108
    $op = 'register';
119
        $op = 'register';
109
}
120
    }
110
elsif ( $op eq 'disable-2FA' ) {
121
    elsif ( $op eq 'disable-2FA' ) {
111
    output_and_exit( $cgi, $cookie, $template, 'wrong_csrf_token' )
122
        output_and_exit( $cgi, $cookie, $template, 'wrong_csrf_token' )
112
        unless Koha::Token->new->check_csrf($csrf_pars);
123
          unless Koha::Token->new->check_csrf($csrf_pars);
113
    my $auth = Koha::Auth::TwoFactorAuth->new({ patron => $logged_in_user });
124
        my $auth =
114
    $logged_in_user->secret(undef);
125
          Koha::Auth::TwoFactorAuth->new( { patron => $logged_in_user } );
115
    $logged_in_user->auth_method('password')->store;
126
        $logged_in_user->secret(undef);
116
    if( $logged_in_user->notice_email_address ) {
127
        $logged_in_user->auth_method('password')->store;
117
        $logged_in_user->queue_notice({
128
        if ( $logged_in_user->notice_email_address ) {
118
            letter_params => {
129
            $logged_in_user->queue_notice(
119
                module => 'members', letter_code => '2FA_DISABLE',
130
                {
120
                branchcode => $logged_in_user->branchcode, lang => $logged_in_user->lang,
131
                    letter_params => {
121
                tables => { branches => $logged_in_user->branchcode, borrowers => $logged_in_user->id },
132
                        module      => 'members',
122
            },
133
                        letter_code => '2FA_DISABLE',
123
            message_transports => [ 'email' ],
134
                        branchcode  => $logged_in_user->branchcode,
124
        });
135
                        lang        => $logged_in_user->lang,
136
                        tables      => {
137
                            branches  => $logged_in_user->branchcode,
138
                            borrowers => $logged_in_user->id
139
                        },
140
                    },
141
                    message_transports => ['email'],
142
                }
143
            );
144
        }
125
    }
145
    }
126
}
146
}
127
147
128
- 

Return to bug 28998