From 3e87d13e6700848b9755610916f8417fd95b95c7 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Tue, 18 Aug 2026 15:21:47 -0400 Subject: [PATCH] Bug 41197: Add unit tests Signed-off-by: David Cook Signed-off-by: Pedro Amorim --- t/Koha/Middleware/CSRF.t | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100755 t/Koha/Middleware/CSRF.t diff --git a/t/Koha/Middleware/CSRF.t b/t/Koha/Middleware/CSRF.t new file mode 100755 index 0000000000..cb9c4f3545 --- /dev/null +++ b/t/Koha/Middleware/CSRF.t @@ -0,0 +1,99 @@ +#!/usr/bin/perl + +# +# Copyright 2026 ByWater Solutions +# +# 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 Test::NoWarnings; +use Test::More tests => 5; + +use HTTP::Request::Common qw( GET POST ); +use Plack::Builder; +use Plack::Request; +use Plack::Test; + +use_ok("Koha::Middleware::CSRF"); + +my $inner_app = sub { + my ($env) = @_; + return [ 200, [ 'Content-Type' => 'text/plain' ], [ $env->{PATH_INFO} ] ]; +}; + +# The OPAC and intranet enable this middleware inside a mount, so the path the +# middleware sees has the mount prefix already stripped ( a request for +# /opac/ilsdi.pl reaches it with a PATH_INFO of /ilsdi.pl ) +my $app = builder { + mount '/opac' => builder { + enable "+Koha::Middleware::CSRF"; + $inner_app; + }; +}; + +subtest 'POSTs without a CSRF token are rejected' => sub { + plan tests => 3; + + test_psgi $app, sub { + my ($cb) = @_; + + my @warnings; + local $SIG{__WARN__} = sub { push @warnings, @_ }; + + my $res = $cb->( POST '/opac/opac-user.pl' ); + is( $res->code, 403, 'POST with no csrf_token is answered with a 403' ); + like( $res->content, qr/Wrong CSRF token/, 'response body says why' ); + like( + $warnings[0], + qr/No CSRF token passed for POST/, + 'the rejection is logged' + ); + }; +}; + +subtest 'GET requests are not subject to CSRF' => sub { + plan tests => 2; + + test_psgi $app, sub { + my ($cb) = @_; + + my $res = $cb->( GET '/opac/opac-account-pay-return.pl?payment_method=Foo' ); + is( $res->code, 200, 'GET reaches the application' ); + is( + $res->content, + '/opac-account-pay-return.pl', + 'the mount prefix is stripped from the path the middleware matches on' + ); + }; +}; + +subtest 'excepted paths are not subject to CSRF' => sub { + plan tests => 2; + + test_psgi $app, sub { + my ($cb) = @_; + + my $res = $cb->( POST '/opac/ilsdi.pl' ); + is( $res->code, 200, 'POST to ilsdi.pl reaches the application' ); + + $res = $cb->( POST '/opac/opac-account-pay-return.pl?payment_method=Foo' ); + is( + $res->code, 200, + 'POST to opac-account-pay-return.pl reaches the application - payment processors cannot obtain a CSRF token' + ); + }; +};