diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php index 549d92040b9b1e95cbbc2eb583795dd582388f66..9ee54bd1c8629a5f6d244df5336722b7f5fae5c4 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php @@ -152,7 +152,7 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource { if(!is_array($entry['hint.cidr'])) continue; foreach ($entry['hint.cidr'] AS $hint_entry) { - if (SimpleSAML_Utilities::ipCIDRcheck($hint_entry, $ip)) { + if (SimpleSAML_Utils_Net::ipCIDRcheck($hint_entry, $ip)) { if ($type === 'entityid') { return $entry['entityid']; } else { diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php index 44a9fbfd1ec612cbc22e287995ac0471460a2441..a79613c2989af1608ad6913c863e81bd477b3d90 100644 --- a/lib/SimpleSAML/Utilities.php +++ b/lib/SimpleSAML/Utilities.php @@ -506,6 +506,7 @@ class SimpleSAML_Utilities { /** * Check whether an IP address is part of an CIDR. + * @deprecated This method will be removed in version 2.0. */ static function ipCIDRcheck($cidr, $ip = null) { if ($ip == null) $ip = $_SERVER['REMOTE_ADDR']; diff --git a/lib/SimpleSAML/Utils/Net.php b/lib/SimpleSAML/Utils/Net.php new file mode 100644 index 0000000000000000000000000000000000000000..f1511091acedf7d9a6a7a3401c0500c43ba962ed --- /dev/null +++ b/lib/SimpleSAML/Utils/Net.php @@ -0,0 +1,82 @@ +<?php + + +/** + * Net-related utility classes. + * + * @package SimpleSAMLphp + */ +class SimpleSAML_Utils_Net +{ + + /** + * Check whether an IP address is part of a CIDR. + * + * @param string $cidr The network CIDR address. + * @param string $ip The IP address to check. Optional. Current remote address will be used if none specified. Do + * not rely on default parameter if running behind load balancers. + * + * @return boolean True if the IP address belongs to the specified CIDR, false otherwise. + * + * @author Andreas Ă…kre Solberg, UNINETT AS <andreas.solberg@uninett.no> + * @author Olav Morken, UNINETT AS <olav.morken@uninett.no> + * @author Brook Schofield, TERENA + * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> + */ + static function ipCIDRcheck($cidr, $ip = null) + { + if ($ip == null) { + $ip = $_SERVER['REMOTE_ADDR']; + } + if (strpos($cidr, '/') == false) { + return false; + } + + list ($net, $mask) = explode('/', $cidr); + + if (strstr($ip, ':') || strstr($net, ':')) { + // Validate IPv6 with inet_pton, convert to hex with bin2hex + // then store as a long with hexdec + + $ip_pack = inet_pton($ip); + $net_pack = inet_pton($net); + + if ($ip_pack === false || $net_pack === false) { + // not valid IPv6 address (warning already issued) + return false; + } + + $ip_ip = str_split(bin2hex($ip_pack), 8); + foreach ($ip_ip as &$value) { + $value = hexdec($value); + } + + $ip_net = str_split(bin2hex($net_pack), 8); + foreach ($ip_net as &$value) { + $value = hexdec($value); + } + } else { + $ip_ip[0] = ip2long($ip); + $ip_net[0] = ip2long($net); + } + + for ($i = 0; $mask > 0 && $i < sizeof($ip_ip); $i++) { + if ($mask > 32) { + $iteration_mask = 32; + } else { + $iteration_mask = $mask; + } + $mask -= 32; + + $ip_mask = ~((1 << (32 - $iteration_mask)) - 1); + + $ip_net_mask = $ip_net[$i] & $ip_mask; + $ip_ip_mask = $ip_ip[$i] & $ip_mask; + + if ($ip_ip_mask != $ip_net_mask) { + return false; + } + } + return true; + } +} diff --git a/modules/negotiate/lib/Auth/Source/Negotiate.php b/modules/negotiate/lib/Auth/Source/Negotiate.php index a29a0c2fb49c2ae24ef25f9b7cd1befbda083e9e..e956a00edbced318a7efd43913c7ed97f3706276 100644 --- a/modules/negotiate/lib/Auth/Source/Negotiate.php +++ b/modules/negotiate/lib/Auth/Source/Negotiate.php @@ -186,7 +186,7 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source { return TRUE; $ip = $_SERVER['REMOTE_ADDR']; foreach ($this->subnet as $cidr) { - $ret = SimpleSAML_Utilities::ipCIDRcheck($cidr); + $ret = SimpleSAML_Utils_Net::ipCIDRcheck($cidr); if ($ret) { SimpleSAML_Logger::debug('Negotiate: Client "'.$ip.'" matched subnet.'); return TRUE; diff --git a/tests/Utils/Net.php b/tests/Utils/Net.php new file mode 100644 index 0000000000000000000000000000000000000000..474811aff9c7d45e9212f1935b8fd6c8c0fd4dbb --- /dev/null +++ b/tests/Utils/Net.php @@ -0,0 +1,41 @@ +<?php +/** + * Class Utils_Net + */ + +class Utils_Net extends PHPUnit_Framework_TestCase +{ + + + /** + * Test the function that checks for IPs belonging to a CIDR. + */ + public function testIpCIDRcheck() + { + // check CIDR w/o mask + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0', '127.0.0.1')); + + // check wrong CIDR w/ mask + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.256/24', '127.0.0.1')); + + // check wrong IP + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/24', '127.0.0')); + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.*')); + + // check limits for standard classes + $this->assertEquals(true, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.0')); + $this->assertEquals(true, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.255')); + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.256')); + + $this->assertEquals(true, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/16', '127.0.0.0')); + $this->assertEquals(true, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/16', '127.0.255.255')); + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/16', '127.0.255.256')); + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/16', '127.0.256.255')); + + // check limits for non-standard classes + $this->assertEquals(true, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/23', '127.0.0.0')); + $this->assertEquals(true, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/23', '127.0.1.255')); + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/23', '127.0.1.256')); + $this->assertEquals(false, SimpleSAML_Utils_Net::ipCIDRcheck('127.0.0.0/23', '127.0.2.0')); + } +} \ No newline at end of file