input, Forge] // Require: ->validate() or access::verify_csrf\( if ($function && $open_braces >= 2) { if ($token[0] == T_STRING) { if ($token[1] == "access" && self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && in_array($tokens[$token_number + 2][1], array("forbidden", "required")) && self::_token_matches("(", $tokens, $token_number + 3)) { $token_number += 3; $function->checks_authorization(true); } else if ($token[1] == "access" && self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING, "verify_csrf"), $tokens, $token_number + 2) && self::_token_matches("(", $tokens, $token_number + 3)) { $token_number += 3; $function->checks_csrf(true); } else if (in_array($token[1], array("Input", "Forge")) && self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1)) { $token_number++; $function->uses_input(true); } } else if ($token[0] == T_VARIABLE) { if ($token[1] == '$this' && self::_token_matches(array(T_OBJECT_OPERATOR), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING, "input"), $tokens, $token_number + 2)) { $token_number += 2; $function->uses_input(true); } } else if ($token[0] == T_OBJECT_OPERATOR) { if (self::_token_matches(array(T_STRING, "validate"), $tokens, $token_number + 1) && self::_token_matches("(", $tokens, $token_number + 2)) { $token_number += 2; $function->checks_csrf(true); } } } } } } // Generate the report $new = TMPPATH . "controller_auth_data.txt"; $fd = fopen($new, "wb"); ksort($found); foreach ($found as $controller => $functions) { $is_admin_controller = true; foreach ($functions as $function) { $is_admin_controller &= $function->is_admin_controller; $flags = array(); if ($function->uses_input() && !$function->checks_csrf()) { $flags[] = "DIRTY_CSRF"; } if (!$function->is_admin_controller && !$function->checks_authorization()) { $flags[] = "DIRTY_AUTH"; } if (!$flags) { // Don't print CLEAN instances continue; } fprintf($fd, "%-60s %-20s %s\n", $controller, $function->name, implode("|", $flags)); } if (strpos(basename($controller), "admin_") === 0 && !$is_admin_controller) { fprintf($fd, "%-60s %-20s %s\n", $controller, basename($controller), "NO_ADMIN_CONTROLLER"); } } fclose($fd); // Compare with the expected report from our golden file. $canonical = MODPATH . "gallery/tests/controller_auth_data.txt"; exec("diff $canonical $new", $output, $return_value); $this->assert_false( $return_value, "Controller auth golden file mismatch. Output:\n" . implode("\n", $output) ); } private static function _token_matches($expected_token, &$tokens, $token_number) { if (!isset($tokens[$token_number])) { return false; } $token = $tokens[$token_number]; if (is_array($expected_token)) { for ($i = 0; $i < count($expected_token); $i++) { if ($expected_token[$i] != $token[$i]) { return false; } } return true; } else { return $expected_token == $token; } } static function _function($name, $line, $is_admin_controller) { return new Controller_Auth_Test_Function($name, $line, $is_admin_controller); } } class Controller_Auth_Test_Function { public $name; public $line; public $is_admin_controller = false; private $_uses_input = false; private $_checks_authorization = false; private $_checks_csrf = false; function __construct($name, $line, $is_admin_controller) { $this->name = $name; $this->line = $line; $this->is_admin_controller = $is_admin_controller; } function uses_input($val=null) { if ($val !== null) { $this->_uses_input = (bool) $val; } return $this->_uses_input; } function checks_authorization($val=null) { if ($val !== null) { $this->_checks_authorization = (bool) $val; } return $this->_checks_authorization; } function checks_csrf($val=null) { if ($val !== null) { $this->_checks_csrf = $val; } return $this->_checks_csrf; } }