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

(-)a/C4/Auth.pm (-11 / +2 lines)
Lines 484-497 sub get_template_and_user { Link Here
484
        OPACBaseURL        => C4::Context->preference('OPACBaseURL'),
484
        OPACBaseURL        => C4::Context->preference('OPACBaseURL'),
485
        minPasswordLength  => $minPasswordLength,
485
        minPasswordLength  => $minPasswordLength,
486
    );
486
    );
487
    if ( C4::Context->config('dev_install') ) {
488
        # Dealing with debug_programming_error ( set from plack.psgi)
489
        $template->param(
490
            dev_install        => 1,
491
            debug_programming_error => scalar $in->{query}->param('debug_programming_error'),
492
        );
493
        $in->{query}->delete('debug_programming_error');
494
    }
495
    if ( $in->{'type'} eq "intranet" ) {
487
    if ( $in->{'type'} eq "intranet" ) {
496
488
497
        $template->param(
489
        $template->param(
Lines 648-656 sub get_template_and_user { Link Here
648
    $template->param( logged_in_user     => $patron );
640
    $template->param( logged_in_user     => $patron );
649
    $template->param( sessionID          => $sessionID );
641
    $template->param( sessionID          => $sessionID );
650
642
651
    if ( $in->{query}->param('invalid_csrf_token') ) {
643
    if ( $ENV{KOHA_ERROR} ) {
652
        Koha::Logger->get->debug("The form submission failed (Wrong CSRF token).");
644
        C4::Output::output_and_exit( $in->{query}, $cookie, $template, $ENV{KOHA_ERROR} );
653
        C4::Output::output_and_exit( $in->{query}, $cookie, $template, 'wrong_csrf_token' );
654
    }
645
    }
655
646
656
    return ( $template, $borrowernumber, $cookie, $flags );
647
    return ( $template, $borrowernumber, $cookie, $flags );
(-)a/Koha/Middleware/CSRF.pm (+82 lines)
Line 0 Link Here
1
package Koha::Middleware::CSRF;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use parent qw(Plack::Middleware);
21
22
use Koha::Logger;
23
24
sub call {
25
    my ( $self, $env ) = @_;
26
    my $req = Plack::Request->new($env);
27
28
    my %stateless_methods = (
29
        GET     => 1,
30
        HEAD    => 1,
31
        OPTIONS => 1,
32
        TRACE   => 1,
33
    );
34
35
    my %stateful_methods = (
36
        POST   => 1,
37
        PUT    => 1,
38
        DELETE => 1,
39
        PATCH  => 1,
40
    );
41
42
    my $original_op    = $req->param('op');
43
    my $request_method = $req->method // q{};
44
    my ( $error );
45
    if ( $stateless_methods{$request_method} && defined $original_op && $original_op =~ m{^cud-} ) {
46
        $error = sprintf "Programming error - op '%s' must not start with 'cud-' for %s", $original_op,
47
            $request_method;
48
    } elsif ( $stateful_methods{$request_method} ) {
49
50
        # Get the CSRF token from the param list or the header
51
        my $csrf_token = $req->param('csrf_token') || $req->header('HTTP_CSRF_TOKEN');
52
53
        if ( defined $req->param('op') && $original_op !~ m{^cud-} ) {
54
            $error = sprintf "Programming error - op '%s' must start with 'cud-' for %s", $original_op,
55
                $request_method;
56
        } elsif ( !$csrf_token ) {
57
            $error = sprintf "Programming error - No CSRF token passed for %s", $request_method;
58
        } else {
59
            unless (
60
                Koha::Token->new->check_csrf(
61
                    {
62
                        session_id => scalar $req->cookies->{CGISESSID},
63
                        token      => $csrf_token,
64
                    }
65
                )
66
                )
67
            {
68
                $error = "wrong_csrf_token";
69
            }
70
        }
71
    }
72
73
    if ( $error ) {
74
        Koha::Logger->get->warn( $error );
75
        $env->{KOHA_ERROR} = $error;
76
        $env->{PATH_INFO} = '/intranet/errors/403.pl';
77
    }
78
79
    return $self->app->($env);
80
}
81
82
1;
(-)a/debian/templates/plack.psgi (-49 / +2 lines)
Lines 47-101 use CGI qw(-utf8 ); # we will loose -utf8 under plack, otherwise Link Here
47
        $CGI::PARAM_UTF8 = 1;
47
        $CGI::PARAM_UTF8 = 1;
48
        Koha::Caches->flush_L1_caches();
48
        Koha::Caches->flush_L1_caches();
49
        Koha::Cache::Memory::Lite->flush();
49
        Koha::Cache::Memory::Lite->flush();
50
51
        my %stateless_methods = (
52
            GET     => 1,
53
            HEAD    => 1,
54
            OPTIONS => 1,
55
            TRACE   => 1,
56
        );
57
58
        my %stateful_methods = (
59
            POST   => 1,
60
            PUT    => 1,
61
            DELETE => 1,
62
            PATCH  => 1,
63
        );
64
65
        my $original_op    = $q->param('op');
66
        my $request_method = $q->request_method // q{};
67
        if ( $stateless_methods{$request_method} && defined $original_op && $original_op =~ m{^cud-} ) {
68
            Koha::Logger->get->warn("Programming error - op '$original_op' must not start with 'cud-' for $request_method");
69
            $q->param( 'op', '' );
70
            $q->param( 'debug_programming_error', "'$original_op' must not start with 'cud-' for $request_method" );
71
        } elsif ( $stateful_methods{$request_method} ) {
72
            # Get the CSRF token from the param list or the header
73
            my $csrf_token = $q->param('csrf_token') || $q->http('HTTP_CSRF_TOKEN');
74
75
            if ( defined $q->param('op') && $original_op !~ m{^cud-} ) {
76
                Koha::Logger->get->warn("Programming error - op '$original_op' must start with 'cud-' for $request_method");
77
                $q->param( 'op', '' );
78
                $q->param( 'debug_programming_error', "'$original_op' must start with 'cud-' for $request_method" );
79
            }
80
81
            die "Programming error - No CSRF token passed for $request_method"
82
                unless $csrf_token;
83
84
            unless (
85
                Koha::Token->new->check_csrf(
86
                    {
87
                        session_id => scalar $q->cookie('CGISESSID'),
88
                        token      => $csrf_token,
89
                    }
90
                )
91
                )
92
            {
93
                Koha::Logger->get->debug("The form submission failed (Wrong CSRF token).");
94
                $q->param( 'op', '' );
95
                $q->param( 'invalid_csrf_token', 1);
96
            }
97
        }
98
99
        return $q;
50
        return $q;
100
    };
51
    };
101
}
52
}
Lines 126-131 builder { Link Here
126
    enable "+Koha::Middleware::RealIP";
77
    enable "+Koha::Middleware::RealIP";
127
78
128
    mount '/opac'          => builder {
79
    mount '/opac'          => builder {
80
        enable "+Koha::Middleware::CSRF";
129
        #NOTE: it is important that these are relative links
81
        #NOTE: it is important that these are relative links
130
        enable 'ErrorDocument',
82
        enable 'ErrorDocument',
131
            400 => 'errors/400.pl',
83
            400 => 'errors/400.pl',
Lines 145-150 builder { Link Here
145
        $opac;
97
        $opac;
146
    };
98
    };
147
    mount '/intranet'      => builder {
99
    mount '/intranet'      => builder {
100
        enable "+Koha::Middleware::CSRF";
148
        #NOTE: it is important that these are relative links
101
        #NOTE: it is important that these are relative links
149
        enable 'ErrorDocument',
102
        enable 'ErrorDocument',
150
            400 => 'errors/400.pl',
103
            400 => 'errors/400.pl',
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/messages.inc (-4 lines)
Lines 1-6 Link Here
1
<div id="messages">
1
<div id="messages">
2
    [% INCLUDE 'blocking_errors.inc' %]
2
    [% INCLUDE 'blocking_errors.inc' %]
3
    [% IF dev_install && debug_programming_error %]
4
        <div class="dialog alert">Programming error: [% debug_programming_error %]</div>
5
    [% END %]
6
</div>
3
</div>
7
- 

Return to bug 36148