Last active
May 9, 2017 18:18
Revisions
-
typhonius revised this gist
Mar 12, 2014 . 1 changed file with 20 additions and 27 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -25,35 +25,27 @@ function ac_protect_this_site() { } } // Should we skip the auth check? Default to FALSE. $skip_auth_check = FALSE; // Check if we should skip auth check for this page. if (ah_path_skip_auth()) { $skip_auth_check = TRUE; } // Check if we should disable cache for this page. if (ah_path_no_cache()) { $conf['page_cache_maximum_age'] = 0; } // Is the page restricted to whitelist only? Default to FALSE. $restricted_page = FALSE; // Check to see whether this page is restricted. if (!empty($conf['ah_restricted_paths']) && ah_paths_restrict()) { $restricted_page = TRUE; } $protect_ip = !empty($conf['ah_whitelist']); $protect_password = !empty($conf['ah_basic_auth_credentials']); @@ -67,8 +59,8 @@ function ac_protect_this_site() { // $skip_auth_check = TRUE; // $on_vpn = TRUE; // If not on whitelisted IP prevent access to protected pages. if ($protect_ip && !$on_vpn && $restricted_page) { ah_page_403(); } @@ -158,13 +150,13 @@ function ah_path_skip_auth() { } /** * Check whether a path has been restricted. * */ function ah_paths_restrict() { global $conf; if (isset($_GET['q'])) { // Borrow some code from drupal_match_path() foreach ($conf['ah_restricted_paths'] as &$path) { @@ -174,11 +166,12 @@ function ah_paths_restrict($on_vpn) { $paths = preg_replace('/\\\\\*/', '.*', $conf['ah_restricted_paths']); $paths = '/^(' . join('|', $paths) . ')$/'; // If this is a restricted path, return TRUE. if (preg_match($paths, $_GET['q'])) { return TRUE; } } return FALSE; } /** @@ -227,4 +220,4 @@ function ah_ip_in_list($ip, $list) { } } return FALSE; } -
typhonius revised this gist
Mar 1, 2014 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -82,8 +82,8 @@ function ac_protect_this_site() { * Output a 403 (forbidden access) response. */ function ah_page_403() { header('HTTP/1.0 403 Forbidden'); print "403 Forbidden: Access denied (". $_SERVER['AH_Client_IP'] .")"; exit; } -
typhonius revised this gist
Dec 23, 2013 . 1 changed file with 69 additions and 42 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -13,8 +13,22 @@ function ac_protect_this_site() { // Is the user on the VPN? Default to FALSE. $on_vpn = $cli ? TRUE : FALSE; if (!empty($_SERVER['AH_Client_IP']) && !empty($conf['ah_whitelist'])) { $on_vpn = ah_ip_in_list($_SERVER['AH_Client_IP'], $conf['ah_whitelist']); } // If the IP is not explicitly whitelisted check to see if the IP is blacklisted. if (!$on_vpn && !empty($_SERVER['AH_Client_IP']) && !empty($conf['ah_blacklist'])) { if (ah_ip_in_list($_SERVER['AH_Client_IP'], $conf['ah_blacklist'])) { ah_page_403(); } } // Check to see whether the page requested is specifically restricted // to users on the whitelist. if (!empty($conf['ah_restricted_paths'])) { ah_paths_restrict($on_vpn); } // Should we skip the auth check? Default to FALSE. @@ -35,6 +49,8 @@ function ac_protect_this_site() { // Current business rules: // 1) Dev, stage, and prod are only accessible from whitelisted IPs. // 2) Users on whitelisted IPs must pass basic auth challenge to access. // 3) Users on blacklist and not on whitelist are denied access. // 4) Specific paths are restricted to IPs on the whitelist. // // Always start by assuming we're protecting the site if the relevant variables // are set. Some rule below has to pass before we turn it off. @@ -144,60 +160,71 @@ function ah_path_skip_auth() { /** * Forbid access to user or admin paths if the user is not on an approved IP range. * */ function ah_paths_restrict($on_vpn) { global $conf; if (isset($_GET['q']) && !$on_vpn) { // Borrow some code from drupal_match_path() foreach ($conf['ah_restricted_paths'] as &$path) { $path = preg_quote($path, '/'); } $paths = preg_replace('/\\\\\*/', '.*', $conf['ah_restricted_paths']); $paths = '/^(' . join('|', $paths) . ')$/'; // Deny access if the user is on a restricted path. if (preg_match($paths, $_GET['q'])) { ah_page_403(); } } } /** * Determine if the IP is within the ranges defined in the white/black list. */ function ah_ip_in_list($ip, $list) { foreach ($list as $item) { // Match IPs in CIDR format. if (strpos($item, '/') !== false) { list($range, $mask) = explode('/', $item); // Take the binary form of the IP and range. $ip_dec = ip2long($ip); $range_dec = ip2long($range); // Create the binary form of netmask. $mask_dec = ~ (pow(2, (32 - $mask)) - 1); // Run a bitwise AND to determine whether the IP and range exist // within the same netmask. if (($mask_dec & $ip_dec) == ($mask_dec & $range_dec)) { return TRUE; } } // Match against wildcard IPs or IP ranges. elseif (strpos($item, '*') !== false || strpos($item, '-') !== false) { // Construct a range from wildcard IPs if (strpos($item, '*') !== false) { $item = str_replace('*', 0, $item) . '-' . str_replace('*', 255, $item); } // Match against ranges by converting to long IPs. list($start, $end) = explode('-', $item); if (ip2long($start) <= ip2long($ip) && ip2long($ip) <= ip2long($end)) { return TRUE; } } // Match against single IPs elseif ($ip === $item) { return TRUE; } } return FALSE; } -
typhonius created this gist
Nov 18, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,203 @@ <?php /** * @file * Utilities for use in protecting an environment via basic auth or IP whitelist. */ function ac_protect_this_site() { global $conf; // Test if we are using drush (command-line interface) $cli = drupal_is_cli(); // Is the user on the VPN? Default to FALSE. $on_vpn = $cli ? TRUE : FALSE; if (!empty($_SERVER['AH_Client_IP']) && !empty($conf['ah_whitelist'])) { $on_vpn = ah_ip_in_whitelist($_SERVER['AH_Client_IP'], $conf['ah_whitelist']); } // Should we skip the auth check? Default to FALSE. $skip_auth_check = FALSE; // Check if we should disable cache for this page. if (ah_path_no_cache()) { $conf['page_cache_maximum_age'] = 0; } // Check if we should skip auth check for this page. if (ah_path_skip_auth()) { $skip_auth_check = TRUE; } // Determine if we should password protect the site. // // Current business rules: // 1) Dev, stage, and prod are only accessible from whitelisted IPs. // 2) Users on whitelisted IPs must pass basic auth challenge to access. // // Always start by assuming we're protecting the site if the relevant variables // are set. Some rule below has to pass before we turn it off. $protect_ip = !empty($conf['ah_whitelist']); $protect_password = !empty($conf['ah_basic_auth_credentials']); // Do not protect command line requests, e.g. Drush. if ($cli) { $protect_ip = FALSE; $protect_password = FALSE; } // Un-comment to disable protection, e.g. for load tests. // $skip_auth_check = TRUE; // $on_vpn = TRUE; // If not on whitelisted IP prevent all access. if ($protect_ip && !$on_vpn) { ah_page_403(); } // If not skipping auth, check basic auth. if ($protect_password && !$skip_auth_check) { ah_check_basic_auth(); } } /** * Output a 403 (forbidden access) response. */ function ah_page_403() { print "403 Forbidden: Access denied (". $_SERVER['AH_Client_IP'] .")"; header('HTTP/1.0 403 Forbidden'); exit; } /** * Output a 401 (unauthorized) response. */ function ah_page_401() { header('WWW-Authenticate: Basic realm="This site is protected"'); header('HTTP/1.0 401 Unauthorized'); print "401 Unauthorized: Access denied (". $_SERVER['AH_Client_IP'] .")"; exit; } /** * Check basic auth against allowed values. */ function ah_check_basic_auth() { global $conf; $authorized = FALSE; $php_auth_user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : NULL; $php_auth_pw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : NULL; $credentials = isset($conf['ah_basic_auth_credentials']) ? $conf['ah_basic_auth_credentials'] : NULL; if ($php_auth_user && $php_auth_pw && !empty($credentials)) { if (isset($credentials[$php_auth_user]) && $credentials[$php_auth_user] == $php_auth_pw) { $authorized = TRUE; } } if ($authorized) { return; } // Always fall back to 401. ah_page_401(); } /** * Determine if the current path is in the list of paths to not cache. */ function ah_path_no_cache() { global $conf; $q = isset($_GET['q']) ? $_GET['q'] : NULL; $paths = isset($conf['ah_paths_no_cache']) ? $conf['ah_paths_no_cache'] : NULL; if (!empty($q) && !empty($paths)) { foreach ($paths as $path) { if ($q == $path || strpos($q, $path) === 0) { return TRUE; } } } } /** * Determine if the current path is in the list of paths on which to not check * auth. */ function ah_path_skip_auth() { global $conf; $q = isset($_GET['q']) ? $_GET['q'] : NULL; $paths = isset($conf['ah_paths_skip_auth']) ? $conf['ah_paths_skip_auth'] : NULL; if (!empty($q) && !empty($paths)) { foreach ($paths as $path) { if ($q == $path || strpos($q, $path) === 0) { return TRUE; } } } } /** * Forbid access to user or admin paths if the user is not on an approved IP range. * * @todo Use a $conf variable for this. */ function ah_paths_restrict($on_vpn) { if (isset($_GET['q'])) { $restricted_path = ($_GET['q'] == 'user' || $_GET['q'] == 'admin' || strpos($_GET['q'], 'user/') === 0 || strpos($_GET['q'], 'admin/') === 0); // @TODO - remove debug // header( 'X-AH-debug-restricted-path: ' . ($restricted_path ? "restricted" : "not restricted") ); if ($restricted_path && !$on_vpn) { ah_page_forbidden(); } } } /** * Determine if the IP is within the ranges defined in the whitelist. */ function ah_ip_in_whitelist($ip, $whitelist) { foreach ($whitelist as $cidr) { $range = ah_ip_cidr_range($cidr); if ($range && count($range) == 2) { $ip_long = ip2long($ip); $ip_one_long = $range[0]; $ip_two_long = $range[1]; $lte = $ip_one_long <= $ip_long; $gte = $ip_two_long >= $ip_long; if ($lte && $gte) { return TRUE; } } } } /** * From http://www.php.net/manual/en/function.ip2long.php#109298 */ function ah_ip_cidr_range($cidr) { list($ip, $mask) = explode('/', $cidr); // net mask binary string $maskBinStr = str_repeat("1", $mask ) . str_repeat("0", 32-$mask ); // inverse mask $inverseMaskBinStr = str_repeat("0", $mask ) . str_repeat("1", 32-$mask ); $ipLong = ip2long($ip); $ipMaskLong = bindec($maskBinStr); $inverseIpMaskLong = bindec($inverseMaskBinStr); $netWork = $ipLong & $ipMaskLong; // ignore network ID (eg: 192.168.1.0) $start = $netWork + 1; // ignore brocast IP(eg: 192.168.1.255) $end = ($netWork | $inverseIpMaskLong) - 1; return array($start, $end); }