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

(-)a/C4/Auth.pm (-21 / +30 lines)
Lines 1198-1214 sub checkauth { Link Here
1198
1198
1199
                        # we have to check they are coming from the right ip range
1199
                        # we have to check they are coming from the right ip range
1200
                        my $domain = $branches->{$branchcode}->{'branchip'};
1200
                        my $domain = $branches->{$branchcode}->{'branchip'};
1201
                        $domain =~ s|\.\*||g;
1201
                        next unless ($domain);
1202
                        if ( $ip !~ /^$domain/ ) {
1202
                        if ( !in_iprange($domain) ) {
1203
                            $loggedin = 0;
1203
                            $loggedin = 0;
1204
                            $auth_state = 'failed';
1204
                            $auth_state = 'failed';
1205
                            $cookie = $cookie_mgr->replace_in_list( $cookie, $query->cookie(
1205
                            $cookie   = $cookie_mgr->replace_in_list(
1206
                                -name     => 'CGISESSID',
1206
                                $cookie,
1207
                                -value    => '',
1207
                                $query->cookie(
1208
                                -HttpOnly => 1,
1208
                                    -name     => 'CGISESSID',
1209
                                -secure => ( C4::Context->https_enabled() ? 1 : 0 ),
1209
                                    -value    => '',
1210
                                -sameSite => 'Lax',
1210
                                    -HttpOnly => 1,
1211
                            ));
1211
                                    -secure => ( C4::Context->https_enabled() ? 1 : 0 ),
1212
                                    -sameSite => 'Lax',
1213
                                )
1214
                            );
1212
                            $info{'wrongip'} = 1;
1215
                            $info{'wrongip'} = 1;
1213
                        }
1216
                        }
1214
                    }
1217
                    }
Lines 1217-1227 sub checkauth { Link Here
1217
1220
1218
                        #     now we work with the treatment of ip
1221
                        #     now we work with the treatment of ip
1219
                        my $domain = $branches->{$br}->{'branchip'};
1222
                        my $domain = $branches->{$br}->{'branchip'};
1220
                        if ( $domain && $ip =~ /^$domain/ ) {
1223
                        next unless ($domain);
1224
                        if ( in_iprange($domain) ) {
1221
                            $branchcode = $branches->{$br}->{'branchcode'};
1225
                            $branchcode = $branches->{$br}->{'branchcode'};
1222
1226
1223
                            # new op dev : add the branchname to the cookie
1227
                            # new op dev : add the branchname to the cookie
1224
                            $branchname    = $branches->{$br}->{'branchname'};
1228
                            $branchname = $branches->{$br}->{'branchname'};
1225
                        }
1229
                        }
1226
                    }
1230
                    }
1227
1231
Lines 1658-1675 sub check_api_auth { Link Here
1658
                if ( $query->param('branch') ) {
1662
                if ( $query->param('branch') ) {
1659
                    $branchcode = $query->param('branch');
1663
                    $branchcode = $query->param('branch');
1660
                    my $library = Koha::Libraries->find($branchcode);
1664
                    my $library = Koha::Libraries->find($branchcode);
1661
                    $branchname = $library? $library->branchname: '';
1665
                    $branchname = $library ? $library->branchname: '';
1662
                }
1666
                }
1663
                my $branches = { map { $_->branchcode => $_->unblessed } Koha::Libraries->search->as_list };
1667
                my $branches = { map { $_->branchcode => $_->unblessed } Koha::Libraries->search->as_list };
1664
                foreach my $br ( keys %$branches ) {
1668
                foreach my $br ( keys %$branches ) {
1665
1669
1666
                    #     now we work with the treatment of ip
1670
                    #     now we work with the treatment of ip
1667
                    my $domain = $branches->{$br}->{'branchip'};
1671
                    my $domain = $branches->{$br}->{'branchip'};
1668
                    if ( $domain && $ip =~ /^$domain/ ) {
1672
                    next unless ($domain);
1673
                    if ( in_iprange($domain) ) {
1669
                        $branchcode = $branches->{$br}->{'branchcode'};
1674
                        $branchcode = $branches->{$br}->{'branchcode'};
1670
1675
1671
                        # new op dev : add the branchname to the cookie
1676
                        # new op dev : add the branchname to the cookie
1672
                        $branchname    = $branches->{$br}->{'branchname'};
1677
                        $branchname = $branches->{$br}->{'branchname'};
1673
                    }
1678
                    }
1674
                }
1679
                }
1675
                $session->param( 'number',       $borrowernumber );
1680
                $session->param( 'number',       $borrowernumber );
Lines 2328-2341 Returns 1 if the remote address is in the provided iprange, or 0 otherwise. Link Here
2328
2333
2329
sub in_iprange {
2334
sub in_iprange {
2330
    my ($iprange) = @_;
2335
    my ($iprange) = @_;
2331
    my $result = 1;
2336
    return 1 unless $iprange;
2332
    my @allowedipranges = $iprange ? split(' ', $iprange) : ();
2337
    my $result = 0;
2333
    if (scalar @allowedipranges > 0) {
2338
2339
    my @allowedipranges = $iprange ? split( ' ', $iprange ) : ();
2340
    if (@allowedipranges) {
2334
        my @rangelist;
2341
        my @rangelist;
2335
        eval { @rangelist = Net::CIDR::range2cidr(@allowedipranges); }; return 0 if $@;
2342
        eval { @rangelist = Net::CIDR::range2cidr(@allowedipranges); };
2336
        eval { $result = Net::CIDR::cidrlookup($ENV{'REMOTE_ADDR'}, @rangelist) } || Koha::Logger->get->warn('cidrlookup failed for ' . join(' ',@rangelist) );
2343
        return 0 if $@;
2337
     }
2344
        eval { $result = Net::CIDR::cidrlookup( $ENV{'REMOTE_ADDR'}, @rangelist ) }
2338
     return $result ? 1 : 0;
2345
            || Koha::Logger->get->warn( 'cidrlookup failed for ' . join( ' ', @rangelist ) );
2346
    }
2347
    return $result ? 1 : 0;
2339
}
2348
}
2340
2349
2341
sub getborrowernumber {
2350
sub getborrowernumber {
(-)a/Koha/Library.pm (+6 lines)
Lines 58-63 sub store { Link Here
58
        $flush = 1 if ( $self_from_storage->branchname ne $self->branchname );
58
        $flush = 1 if ( $self_from_storage->branchname ne $self->branchname );
59
    }
59
    }
60
60
61
    if ( $self->branchip =~ /\*/ ) {
62
        my $branchip = $self->branchip;
63
        $branchip =~ s/\*//g;
64
        $branchip =~ s/\.{2,}/./g;
65
        $self->branchip( $branchip );
66
    }
61
    $self = $self->SUPER::store;
67
    $self = $self->SUPER::store;
62
68
63
    if ($flush) {
69
    if ($flush) {
(-)a/installer/data/mysql/atomicupdate/bug_28657.pl (+26 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
return {
4
    bug_number  => "28657",
5
    description => "expand branches.branchip to allow for multiple ip ranges and remove '*'",
6
    up          => sub {
7
        my ($args) = @_;
8
        my ( $dbh, $out ) = @$args{qw(dbh out)};
9
10
        $dbh->do(
11
            q{ALTER TABLE `branches` MODIFY `branchip` mediumtext DEFAULT NULL COMMENT 'the IP address(s) for your library or branch'}
12
        );
13
        say $out "Modify column 'branches.branchip' to mediumtext";
14
15
        my $sth_select = $dbh->prepare(q{SELECT branchip,branchcode FROM branches WHERE branchip like '%*%'});
16
        my $sth_update = $dbh->prepare(q{UPDATE branches SET branchip = ? WHERE branchcode = ?});
17
        $sth_select->execute;
18
        my $results = $sth_select->fetchall_arrayref( {} );
19
        foreach (@$results) {
20
            $_->{'branchip'} =~ s/\*//g;
21
            $_->{'branchip'} =~ s/\.{2,}/./g;
22
            $sth_update->execute( $_->{'branchip'}, $_->{'branchcode'} );
23
        }
24
        say $out "Update column 'branches.branchip' to remove '*'";
25
    },
26
};
(-)a/installer/data/mysql/kohastructure.sql (-1 / +1 lines)
Lines 1648-1654 CREATE TABLE `branches` ( Link Here
1648
  `branchreturnpath` longtext DEFAULT NULL COMMENT 'the email to be used as Return-Path',
1648
  `branchreturnpath` longtext DEFAULT NULL COMMENT 'the email to be used as Return-Path',
1649
  `branchurl` longtext DEFAULT NULL COMMENT 'the URL for your library or branch''s website',
1649
  `branchurl` longtext DEFAULT NULL COMMENT 'the URL for your library or branch''s website',
1650
  `issuing` tinyint(4) DEFAULT NULL COMMENT 'unused in Koha',
1650
  `issuing` tinyint(4) DEFAULT NULL COMMENT 'unused in Koha',
1651
  `branchip` varchar(15) DEFAULT NULL COMMENT 'the IP address for your library or branch',
1651
  `branchip` mediumtext DEFAULT NULL COMMENT 'the IP address(s) for your library or branch',
1652
  `branchnotes` longtext DEFAULT NULL COMMENT 'notes related to your library or branch',
1652
  `branchnotes` longtext DEFAULT NULL COMMENT 'notes related to your library or branch',
1653
  `geolocation` varchar(255) DEFAULT NULL COMMENT 'geolocation of your library',
1653
  `geolocation` varchar(255) DEFAULT NULL COMMENT 'geolocation of your library',
1654
  `marcorgcode` varchar(16) DEFAULT NULL COMMENT 'MARC Organization Code, see http://www.loc.gov/marc/organizations/orgshome.html, when empty defaults to syspref MARCOrgCode',
1654
  `marcorgcode` varchar(16) DEFAULT NULL COMMENT 'MARC Organization Code, see http://www.loc.gov/marc/organizations/orgshome.html, when empty defaults to syspref MARCOrgCode',
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt (-2 / +2 lines)
Lines 249-256 Link Here
249
                </li>
249
                </li>
250
                <li>
250
                <li>
251
                    <label for="branchip">IP: </label>
251
                    <label for="branchip">IP: </label>
252
                    <input type="text" name="branchip" id="branchip"  size="15" maxlength="15" value="[% library.branchip | html %]" />
252
                    <input type="text" name="branchip" id="branchip"  size="60" value="[% library.branchip | html %]" />
253
                    <div class="hint">Can be entered as a single IP, or a subnet such as 192.168.1.*</div>
253
                    <div class="hint">Can be entered as a single IP, an IP range such as 192.168.1. or 192.168.1.10-192.168.1.50 or 192.168.1.0/24, or multiple space separated IP addresses or ranges.</div>
254
                </li>
254
                </li>
255
                <li>
255
                <li>
256
                    <label for="marcorgcode">MARC organization code</label>
256
                    <label for="marcorgcode">MARC organization code</label>
(-)a/t/Auth.t (-14 / +15 lines)
Lines 16-37 Link Here
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
use Test::More tests => 12;
19
use Test::More tests => 14;
20
use Test::Warn;
20
use Test::Warn;
21
21
22
use C4::Auth qw( in_iprange );
22
use C4::Auth qw( in_iprange );
23
23
24
$ENV{REMOTE_ADDR} = '192.168.1.30';
24
$ENV{REMOTE_ADDR} = '192.168.1.30';
25
25
26
ok(in_iprange("192.168.1.30"), 'simple single ip matching remote ip');
26
is( 1, in_iprange("192.168.1.30"), 'simple single ip matching remote ip' );
27
ok(!in_iprange("192.168.1.31"), 'simple single ip not match remote ip');
27
is( 0, in_iprange("192.168.1.31"), 'simple single ip not match remote ip' );
28
ok(in_iprange("192.168.1.1/24"), 'simple ip range/24 with remote ip in it');
28
is( 1, in_iprange("192.168.1.1/24"), 'simple ip range/24 with remote ip in it' );
29
ok(!in_iprange("192.168.2.1/24"), 'simple ip range/24 with remote ip not in it');
29
is( 0, in_iprange("192.168.2.1/24"), 'simple ip range/24 with remote ip not in it' );
30
ok(in_iprange("192.168.2.1/16"), 'simple ip range/16 with remote ip in it');
30
is( 1, in_iprange("192.168.2.1/16"), 'simple ip range/16 with remote ip in it' );
31
ok(!in_iprange("192.168.1.10-30"), 'invalidly represented IP range with remote ip in it');
31
is( 0, in_iprange("192.168.1.10-30"), 'invalidly represented IP range with remote ip in it' );
32
ok(in_iprange("192.168.1.10-192.168.1.30"), 'validly represented ip range with remote ip in it');
32
is( 1, in_iprange("192.168.1.10-192.168.1.30"), 'validly represented ip range with remote ip in it' );
33
ok(in_iprange("127.0.0.1 192.168.1.30 192.168.2.10-192.168.2.25"), 'multiple ips and ranges, including the remote ip');
33
is( 1, in_iprange("127.0.0.1 192.168.1.30 192.168.2.10-192.168.2.25"), 'multiple ips and ranges, including the remote ip' );
34
ok(!in_iprange("127.0.0.1 8.8.8.8 192.168.2.1/24 192.168.3.1/24 192.168.1.1-192.168.1.29"), "multiple ip and ip ranges, with the remote ip in none of them");
34
is( 0, in_iprange("127.0.0.1 8.8.8.8 192.168.2.1/24 192.168.3.1/24 192.168.1.1-192.168.1.29" ), "multiple ip and ip ranges, with the remote ip in none of them" );
35
ok(in_iprange(""), "blank list given, no preference set - implies everything goes through.");
35
is( 1, in_iprange(""), "blank list given, no preference set - implies everything goes through." );
36
ok(in_iprange(), "no list given, no preference set - implies everything goes through.");
36
is( 1, in_iprange(), "no list given, no preference set - implies everything goes through." );
37
ok(in_iprange("192.168.1.1/36"), 'simple invalid ip range/36 with remote ip in it');
37
is( 0, in_iprange("192.168.1.1/36"), 'simple invalid ip range/36 with remote ip in it' );
38
is( 1, in_iprange("192.168.1."), 'simple ip range missing last octet with remote ip in it' );
39
is( 1, in_iprange("192.168.1.*"), 'simple ip range with "*" with remote ip in it.  Undocumented feature; this should not work, but it does.' );
38
- 

Return to bug 28657