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

(-)a/C4/Auth.pm (-15 / +70 lines)
Lines 646-651 sub checkauth { Link Here
646
        $timeout = $1 * 86400;
646
        $timeout = $1 * 86400;
647
    };
647
    };
648
    $timeout = 600 unless $timeout;
648
    $timeout = 600 unless $timeout;
649
    my $clientip = get_clientip($ENV{'REMOTE_ADDR'}, $ENV{'HTTP_X_FORWARDED_FOR'}, C4::Context->preference('HandleXForwardedFor'));
649
650
650
    _version_check($type,$query);
651
    _version_check($type,$query);
651
    # state variables
652
    # state variables
Lines 720-729 sub checkauth { Link Here
720
            $userid    = undef;
721
            $userid    = undef;
721
            $sessionID = undef;
722
            $sessionID = undef;
722
        }
723
        }
723
        elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
724
        elsif ($ip ne $clientip) {
724
            # Different ip than originally logged in from
725
            # Different ip than originally logged in from
725
            $info{'oldip'}        = $ip;
726
            $info{'oldip'}        = $ip;
726
            $info{'newip'}        = $ENV{'REMOTE_ADDR'};
727
            $info{'newip'}        = $clientip;
727
            $info{'different_ip'} = 1;
728
            $info{'different_ip'} = 1;
728
            $session->delete();
729
            $session->delete();
729
            C4::Context->_unset_userenv($sessionID);
730
            C4::Context->_unset_userenv($sessionID);
Lines 765-771 sub checkauth { Link Here
765
		    $userid = $retuserid if ($retuserid ne '');
766
		    $userid = $retuserid if ($retuserid ne '');
766
		}
767
		}
767
		if ($return) {
768
		if ($return) {
768
               _session_log(sprintf "%20s from %16s logged in  at %30s.\n", $userid,$ENV{'REMOTE_ADDR'},(strftime '%c', localtime));
769
               _session_log(sprintf "%20s from %16s logged in  at %30s.\n", $userid,$clientip,(strftime '%c', localtime));
769
            	if ( $flags = haspermission(  $userid, $flagsrequired ) ) {
770
            	if ( $flags = haspermission(  $userid, $flagsrequired ) ) {
770
					$loggedin = 1;
771
					$loggedin = 1;
771
            	}
772
            	}
Lines 813-819 sub checkauth { Link Here
813
# launch a sequence to check if we have a ip for the branch, i
814
# launch a sequence to check if we have a ip for the branch, i
814
# if we have one we replace the branchcode of the userenv by the branch bound in the ip.
815
# if we have one we replace the branchcode of the userenv by the branch bound in the ip.
815
816
816
					my $ip       = $ENV{'REMOTE_ADDR'};
817
					# if they specify at login, use that
817
					# if they specify at login, use that
818
					if ($query->param('branch')) {
818
					if ($query->param('branch')) {
819
						$branchcode  = $query->param('branch');
819
						$branchcode  = $query->param('branch');
Lines 823-829 sub checkauth { Link Here
823
					if (C4::Context->boolean_preference('IndependantBranches') && C4::Context->boolean_preference('Autolocation')){
823
					if (C4::Context->boolean_preference('IndependantBranches') && C4::Context->boolean_preference('Autolocation')){
824
						# we have to check they are coming from the right ip range
824
						# we have to check they are coming from the right ip range
825
						my $domain = $branches->{$branchcode}->{'branchip'};
825
						my $domain = $branches->{$branchcode}->{'branchip'};
826
						if ($ip !~ /^$domain/){
826
						if ($clientip !~ /^$domain/){
827
							$loggedin=0;
827
							$loggedin=0;
828
							$info{'wrongip'} = 1;
828
							$info{'wrongip'} = 1;
829
						}
829
						}
Lines 833-839 sub checkauth { Link Here
833
					foreach my $br ( keys %$branches ) {
833
					foreach my $br ( keys %$branches ) {
834
						#     now we work with the treatment of ip
834
						#     now we work with the treatment of ip
835
						my $domain = $branches->{$br}->{'branchip'};
835
						my $domain = $branches->{$br}->{'branchip'};
836
						if ( $domain && $ip =~ /^$domain/ ) {
836
						if ( $domain && $clientip =~ /^$domain/ ) {
837
							$branchcode = $branches->{$br}->{'branchcode'};
837
							$branchcode = $branches->{$br}->{'branchcode'};
838
838
839
							# new op dev : add the branchprinter and branchname in the cookie
839
							# new op dev : add the branchprinter and branchname in the cookie
Lines 850-856 sub checkauth { Link Here
850
					$session->param('branchname',$branchname);
850
					$session->param('branchname',$branchname);
851
					$session->param('flags',$userflags);
851
					$session->param('flags',$userflags);
852
					$session->param('emailaddress',$emailaddress);
852
					$session->param('emailaddress',$emailaddress);
853
					$session->param('ip',$session->remote_addr());
853
					$session->param('ip',$clientip);
854
					$session->param('lasttime',time());
854
					$session->param('lasttime',time());
855
					$debug and printf STDERR "AUTH_4: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
855
					$debug and printf STDERR "AUTH_4: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
856
				}
856
				}
Lines 866-872 sub checkauth { Link Here
866
					$session->param('branchname','NO_LIBRARY_SET');
866
					$session->param('branchname','NO_LIBRARY_SET');
867
					$session->param('flags',1);
867
					$session->param('flags',1);
868
					$session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
868
					$session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
869
					$session->param('ip',$session->remote_addr());
869
					$session->param('ip',$clientip);
870
					$session->param('lasttime',time());
870
					$session->param('lasttime',time());
871
				}
871
				}
872
				C4::Context::set_userenv(
872
				C4::Context::set_userenv(
Lines 917-923 sub checkauth { Link Here
917
			C4::Context::set_shelves_userenv('tot',$total);
917
			C4::Context::set_shelves_userenv('tot',$total);
918
918
919
			# setting a couple of other session vars...
919
			# setting a couple of other session vars...
920
			$session->param('ip',$session->remote_addr());
920
            $session->param('ip',$clientip);
921
			$session->param('lasttime',time());
921
			$session->param('lasttime',time());
922
			$session->param('sessiontype','anon');
922
			$session->param('sessiontype','anon');
923
		}
923
		}
Lines 1088-1093 sub check_api_auth { Link Here
1088
    my $dbh     = C4::Context->dbh;
1088
    my $dbh     = C4::Context->dbh;
1089
    my $timeout = C4::Context->preference('timeout');
1089
    my $timeout = C4::Context->preference('timeout');
1090
    $timeout = 600 unless $timeout;
1090
    $timeout = 600 unless $timeout;
1091
    my $clientip = get_clientip($ENV{'REMOTE_ADDR'}, $ENV{'HTTP_X_FORWARDED_FOR'}, C4::Context->preference('HandleXForwardedFor'));
1091
1092
1092
    unless (C4::Context->preference('Version')) {
1093
    unless (C4::Context->preference('Version')) {
1093
        # database has not been installed yet
1094
        # database has not been installed yet
Lines 1139-1145 sub check_api_auth { Link Here
1139
                $userid    = undef;
1140
                $userid    = undef;
1140
                $sessionID = undef;
1141
                $sessionID = undef;
1141
                return ("expired", undef, undef);
1142
                return ("expired", undef, undef);
1142
            } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
1143
            } elsif ( $ip ne $clientip ) {
1143
                # IP address changed
1144
                # IP address changed
1144
                $session->delete();
1145
                $session->delete();
1145
                C4::Context->_unset_userenv($sessionID);
1146
                C4::Context->_unset_userenv($sessionID);
Lines 1229-1235 sub check_api_auth { Link Here
1229
                    }
1230
                    }
1230
                }
1231
                }
1231
1232
1232
                my $ip       = $ENV{'REMOTE_ADDR'};
1233
                # if they specify at login, use that
1233
                # if they specify at login, use that
1234
                if ($query->param('branch')) {
1234
                if ($query->param('branch')) {
1235
                    $branchcode  = $query->param('branch');
1235
                    $branchcode  = $query->param('branch');
Lines 1240-1246 sub check_api_auth { Link Here
1240
                foreach my $br ( keys %$branches ) {
1240
                foreach my $br ( keys %$branches ) {
1241
                    #     now we work with the treatment of ip
1241
                    #     now we work with the treatment of ip
1242
                    my $domain = $branches->{$br}->{'branchip'};
1242
                    my $domain = $branches->{$br}->{'branchip'};
1243
                    if ( $domain && $ip =~ /^$domain/ ) {
1243
                    if ( $domain && $clientip =~ /^$domain/ ) {
1244
                        $branchcode = $branches->{$br}->{'branchcode'};
1244
                        $branchcode = $branches->{$br}->{'branchcode'};
1245
1245
1246
                        # new op dev : add the branchprinter and branchname in the cookie
1246
                        # new op dev : add the branchprinter and branchname in the cookie
Lines 1257-1263 sub check_api_auth { Link Here
1257
                $session->param('branchname',$branchname);
1257
                $session->param('branchname',$branchname);
1258
                $session->param('flags',$userflags);
1258
                $session->param('flags',$userflags);
1259
                $session->param('emailaddress',$emailaddress);
1259
                $session->param('emailaddress',$emailaddress);
1260
                $session->param('ip',$session->remote_addr());
1260
                $session->param('ip',$clientip);
1261
                $session->param('lasttime',time());
1261
                $session->param('lasttime',time());
1262
            } elsif ( $return == 2 ) {
1262
            } elsif ( $return == 2 ) {
1263
                #We suppose the user is the superlibrarian
1263
                #We suppose the user is the superlibrarian
Lines 1270-1276 sub check_api_auth { Link Here
1270
                $session->param('branchname','NO_LIBRARY_SET');
1270
                $session->param('branchname','NO_LIBRARY_SET');
1271
                $session->param('flags',1);
1271
                $session->param('flags',1);
1272
                $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
1272
                $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
1273
                $session->param('ip',$session->remote_addr());
1273
                $session->param('ip',$clientip);
1274
                $session->param('lasttime',time());
1274
                $session->param('lasttime',time());
1275
            }
1275
            }
1276
            C4::Context::set_userenv(
1276
            C4::Context::set_userenv(
Lines 1321-1326 sub check_cookie_auth { Link Here
1321
    my $dbh     = C4::Context->dbh;
1321
    my $dbh     = C4::Context->dbh;
1322
    my $timeout = C4::Context->preference('timeout');
1322
    my $timeout = C4::Context->preference('timeout');
1323
    $timeout = 600 unless $timeout;
1323
    $timeout = 600 unless $timeout;
1324
    my $clientip = get_clientip($ENV{'REMOTE_ADDR'}, $ENV{'HTTP_X_FORWARDED_FOR'}, C4::Context->preference('HandleXForwardedFor'));
1324
1325
1325
    unless (C4::Context->preference('Version')) {
1326
    unless (C4::Context->preference('Version')) {
1326
        # database has not been installed yet
1327
        # database has not been installed yet
Lines 1371-1377 sub check_cookie_auth { Link Here
1371
            $userid    = undef;
1372
            $userid    = undef;
1372
            $sessionID = undef;
1373
            $sessionID = undef;
1373
            return ("expired", undef);
1374
            return ("expired", undef);
1374
        } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
1375
        } elsif ( $ip ne $clientip ) {
1375
            # IP address changed
1376
            # IP address changed
1376
            $session->delete();
1377
            $session->delete();
1377
            C4::Context->_unset_userenv($sessionID);
1378
            C4::Context->_unset_userenv($sessionID);
Lines 1396-1401 sub check_cookie_auth { Link Here
1396
    }
1397
    }
1397
}
1398
}
1398
1399
1400
=head2 get_clientip
1401
1402
  my $clientip = get_clientip($remote_addr, $forwarded_for, $require_routable);
1403
1404
Parses the remote IP address (passed to the function in $remote_addr), the
1405
X-Forwarded-For header (passed to the function in $forwarded_for), and retrieves
1406
the IP address of the client, returning a string representation of the IP
1407
address. If $require_routable is set to "first", this function will always
1408
return the most-distant IP address. If $require_routable is set to "routable",
1409
this function will choose the first routable IP address in the list of relays,
1410
or the address immediately before the closest proxy. If $require_routable is set
1411
to "ignore", this function will always return the most recent hop (i.e. the
1412
remote address). "Ignore" is the default.
1413
1414
=cut
1415
1416
sub get_clientip {
1417
    my $remote_addr = shift;
1418
    my $forwarded_for = shift;
1419
    my $require_routable = shift;
1420
    my $clientip;
1421
1422
    $require_routable ||= 'ignore';
1423
1424
    if ($require_routable eq 'ignore' || !length $forwarded_for) {
1425
        $clientip = $remote_addr;
1426
    } else {
1427
        my @ips = split(', ', $forwarded_for);
1428
        $ips[$#ips + 1] = $remote_addr;
1429
        if ($require_routable eq 'first') {
1430
            $clientip = $ips[0];
1431
        } else { # $require_routable eq 'routable'
1432
            foreach (@ips) {
1433
                if  ( $_ !~ /^(192\.|10\.|127\.|0\.|169\.254\.|2([345][0-9|2[4-9])\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)/) {
1434
                    $clientip = $_;
1435
                    last;
1436
                    # We've found the client if the IP is not in any of:
1437
                    # * 192.0.0.0/8
1438
                    # * 10.0.0.0/8
1439
                    # * 127.0.0.0/8
1440
                    # * 169.254.0.0/16
1441
                    # * 224.0.0.0/4 or 240.0.0.0/4
1442
                    # * 172.16.0.0/12
1443
                }
1444
            }
1445
            if (!length $clientip) {
1446
                $clientip = $ips[$#ips - 1];
1447
            }
1448
        }
1449
    }
1450
1451
    return $clientip;
1452
}
1453
1399
=head2 get_session
1454
=head2 get_session
1400
1455
1401
  use CGI::Session;
1456
  use CGI::Session;
(-)a/installer/data/mysql/sysprefs.sql (-1 / +1 lines)
Lines 328-331 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES(' Link Here
328
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('OpacKohaUrl','1',"Show 'Powered by Koha' text on OPAC footer.",NULL,NULL);
328
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('OpacKohaUrl','1',"Show 'Powered by Koha' text on OPAC footer.",NULL,NULL);
329
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('EasyAnalyticalRecords','0','If on, display in the catalogue screens tools to easily setup analytical record relationships','','YesNo');
329
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('EasyAnalyticalRecords','0','If on, display in the catalogue screens tools to easily setup analytical record relationships','','YesNo');
330
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacShowRecentComments',0,'If ON a link to recent comments will appear in the OPAC masthead',NULL,'YesNo');
330
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacShowRecentComments',0,'If ON a link to recent comments will appear in the OPAC masthead',NULL,'YesNo');
331
331
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('HandleXForwardedFor','ignore','Specify how to handle client IPs and the X-Forwarded-For header.','ignore|first|routable','Choice');
(-)a/installer/data/mysql/updatedatabase.pl (-1 / +8 lines)
Lines 4438-4444 if (C4::Context->preference("Version") < TransformToNum($DBversion)) { Link Here
4438
    SetVersion($DBversion);
4438
    SetVersion($DBversion);
4439
}
4439
}
4440
4440
4441
4442
$DBversion = "3.05.00.011";
4441
$DBversion = "3.05.00.011";
4443
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
4442
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
4444
    $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OPACResultsSidebar','','Define HTML to be included on the search results page, underneath the facets sidebar','70|10','Textarea')");
4443
    $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OPACResultsSidebar','','Define HTML to be included on the search results page, underneath the facets sidebar','70|10','Textarea')");
Lines 4578-4583 if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { Link Here
4578
    SetVersion($DBversion);
4577
    SetVersion($DBversion);
4579
}
4578
}
4580
4579
4580
$DBversion = "3.07.00.XXX";
4581
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
4582
    $dbh->do("INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('HandleXForwardedFor','ignore','Specify how to handle client IPs and the X-Forwarded-For header.','ignore|first|routable','Choice');");
4583
    print "Upgrade to $DBversion done (add HandleXForwardedFor syspref- change if you are using a reverse proxy or load balancer)\n";
4584
    SetVersion($DBversion);
4585
}
4586
4587
4581
=head1 FUNCTIONS
4588
=head1 FUNCTIONS
4582
4589
4583
=head2 DropAllForeignKeys($table)
4590
=head2 DropAllForeignKeys($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref (+8 lines)
Lines 71-76 Administration: Link Here
71
                  tmp: as temporary files.
71
                  tmp: as temporary files.
72
                  memcached: in a memcached server.
72
                  memcached: in a memcached server.
73
        -
73
        -
74
            - pref: HandleXForwardedFor
75
              default: ignore
76
              choices:
77
                  ignore: Always use the address of the machine connecting to Koha
78
                  routable: Use the first routable address or address of the last hop before the proxy
79
                  first: Always use the address of the machine with the web browser
80
            - as the client IP for authenticated sessions.
81
        -
74
            - pref: IndependantBranches
82
            - pref: IndependantBranches
75
              default: 0
83
              default: 0
76
              choices:
84
              choices:
(-)a/t/Auth.t (-1 / +17 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
#
3
# This Koha test module is a stub!  
4
# Add more tests here!!!
5
6
use strict;
7
use warnings;
8
9
use Test::More tests => 5;
10
11
BEGIN {
12
        use_ok('C4::Auth');
13
        ok(C4::Auth::get_clientip('192.168.101.2', '192.168.101.3, 192.168.101.4', 'ignore') eq '192.168.101.2', 'get_clientip: Ignore proxies for client IP');
14
        ok(C4::Auth::get_clientip('192.168.101.2', '192.168.101.3, 192.168.101.4', 'first') eq '192.168.101.3', 'get_clientip: Always use most remote client IP');
15
        ok(C4::Auth::get_clientip('192.168.101.2', '127.0.0.1, 192.168.102.3, 10.0.0.1, 53.42.191.136', 'routable') eq '53.42.191.136', 'get_clientip: Find routable client IP w/reverse proxy');
16
        ok(C4::Auth::get_clientip('192.168.101.2', '127.0.0.1, 192.168.102.3, 10.0.0.1', 'routable') eq '10.0.0.1', 'get_clientip: Handle no-routable IPs w/reverse proxy');
17
}

Return to bug 6800