-
Tomasz Wolniewicz authoredTomasz Wolniewicz authored
validatorClass.php 16.67 KiB
<?php
class Validator {
public $params;
private $validatordir;
private $edugain;
private $logger;
public function __construct($params = array()) {
$this->validatordir = VALIDATOR_SCRIPTS;
if (empty($params)) {
$this->params = array(
'url' => '',
'auto' => 0,
'validate' => 0,
'xmlout' => 0,
'gobetween' => 0,
'edugain' => 0,
'regauth' => '',
'filename' => '',
'fedname' => '',
'lang' => '',
'langsetting' => '',
'weakkeys' => 0,
'entities' => 0,
'onlyone' => 0,
'lang' => array(),
'langs' => array(
"",
"be", "bg", "cs", "da", "de",
"el", "en", "es", "et",
"fi", "fr", "hr", "hu",
"it", "lv", "lb", "mk", "nl",
"no", "pl", "pt", "ro", "ru",
"sk", "sl", "sr", "sv", "tr",
"uk",
),
);
$this->params['url'] = '';
$isurl = true;
if (isset($_REQUEST['from'])) {
if (!isset($_REQUEST['url']))
$_REQUEST['url'] = $_REQUEST['from'];
unset($_REQUEST['from']);
}
if (isset($_REQUEST['url']))
$this->params['url'] = trim($_REQUEST['url']);
if ($this->params['url'] != '' && !$this->check_url()) {
$_SERVER['QUERY_STRING'] = '';
$_SERVER['REQUEST_URI'] = preg_replace("/\?(.*)/", "". $_SERVER['REQUEST_URI']);
$_REQUEST = $_GET = $_POST = array();
$this->params['url'] = '';
$this->params['urlerror'] = 1;
}
if ($this->params['url'] &&
!preg_match("/^http:\/\//", $this->params['url']) &&
!preg_match("/^https:\/\//", $this->params['url']) &&
!preg_match("/^file:\/\//", $this->params['url']))
$this->params['url'] = "http://".$this->params['url'];
$this->params['filename'] = VALIDATOR_TMP.'/'.$this->generate_string(32);
if (isset($_REQUEST['edugain']) || isset($_REQUEST['fed_id'])) {
require_once(eduGAIN_config."database_ro.php");
require_once('../lib/eduGAIN_core.php');
$this->edugain = new eduGAIN_core();
$fed_id = strtoupper(isset($_REQUEST['edugain'])?$_REQUEST['edugain']:$_REQUEST['fed_id']);
$fed_id = $this->edugain->getCode($fed_id);
$this->edugain->load_federations(0,$fed_id);
$this->edugain->load_federation_basic_details('all');
$certdb = 0;
if (empty($this->edugain->FEDS[$fed_id])) {
$this->params['federror'] = 'No such federation in the eduGAIN database: '.$fed_id;
} else {
$this->params['url'] = $this->edugain->FEDS[$fed_id]['metadata_url'];
if ($this->params['url'] == '') {
$this->params['federror'] = "No metadata URL registered in the eduGAIN database for federation ".$this->edugain->FEDS[$fed_id]['fed_id'].' - '.$this->edugain->FEDS[$fed_id]['name'];
} else {
$this->params['fedname'] = $this->edugain->FEDS[$fed_id]['name'];
$this->params['regauth'] = $this->edugain->FEDS[$fed_id]['reg_auth'];
for ($n=0; $n<count($this->edugain->FEDS[$fed_id]['certificate']); $n++) {
$certificate = $this->edugain->FEDS[$fed_id]['certificate'][$n]['data'];
$certificate = trim($certificate, "\n");
$fnamesuffix = '';
if ($n > 0) {
$fnamesuffix = "_$n";
}
$certfilename = $this->params['filename'].$fnamesuffix."-fromdb.crt";
if (strlen($certificate)) {
$ff = fopen($certfilename, 'w');
fputs($ff, "-----BEGIN CERTIFICATE-----\n");
for ($i=0; ; $i=$i+64) {
if (substr($certificate, $i, 64) == '') break;
fputs($ff, substr($certificate, $i, 64)."\n");
}
fputs($ff, "-----END CERTIFICATE-----\n");
fclose($ff);
$this->edugain->FEDS[$fed_id]['certificate'][$n]['certfile'] = $certfilename;
}
}
$certdb = $n;
$ff = fopen($this->params['filename'].'-certinfo.json', 'w');
fputs($ff, json_encode($this->edugain->FEDS[$fed_id]['certificate']));
}
}
$this->params['auto'] = $this->params['validate'] = $this->params['edugain'] = 1;
if (isset($_REQUEST['xmlout']) || (!empty($_REQUEST['format']) && $_REQUEST['format'] == 'xml') )
$this->params['xmlout'] = 1;
if (isset($_REQUEST['gobetween']))
$this->params['gobetween'] = 1;
} else {
if ($this->params['url']) {
if (isset($_REQUEST['regauth']))
$this->params['regauth'] = trim($_REQUEST['regauth']);
else
$this->params['regauth'] = "";
$validate=0;
if (isset($_REQUEST['validate']))
$this->params['validate'] = 1;
if (isset($_REQUEST['auto'])) {
$this->params['auto'] = 1;
$this->params['validate'] = 1;
}
if (isset($_REQUEST['gobetween']))
$this->params['gobetween'] = 1;
if ($this->params['auto']) {
if (!isset($_REQUEST['entities']))
$this->params['validate'] = 1;
}
if (isset($_REQUEST['xmlout']))
$this->params['xmlout'] = $this->params['auto'] = $this->params['validate'] = 1;
if (!isset($_REQUEST['oneentity']))
$this->params['entities'] = 1;
}
}
if (isset($_REQUEST['nolang']))
$this->params['langsetting'] = "XXXX";
else {
if (isset($_REQUEST['lang'])) {
if (empty($_REQUEST['lang']))
$this->params['lang'] = array("");
if (gettype($_REQUEST['lang']) == 'array') {
$this->params['lang'] = $_REQUEST['lang'];
} else {
if (gettype($_REQUEST['lang']) == 'string') {
$this->params['lang'] = explode(',', $_REQUEST['lang']);
}
}
$this->params['lang'] = array_unique($this->params['lang']);
$this->params['lang'] = array_filter($this->params['lang']);
$this->params['langsetting'] = implode(' ', $this->params['lang']);
} else {
$this->params['langsetting'] = "";
$this->params['lang'] = array("");
}
}
if ($this->params['langsetting'] == "")
$this->params['langsetting'] = "--";
if (isset($_REQUEST['oneentity']))
$this->params['onlyone'] = 1;
else
$this->params['onlyone'] = 0;
if (isset($_REQUEST['weakkeys']))
$this->params['weakkeys'] = 1;
else
$this->params['weakkeys'] = 0;
if (isset($_REQUEST['entities']))
$this->params['entities'] = 1;
else
$this->params['entities'] = 0;
} else
$this->params = $params;
}
private function generate_string($strength = 16) {
$permitted_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$input_length = strlen($permitted_chars);
$random_string = '';
for($i = 0; $i < $strength; $i++) {
$random_character = $permitted_chars[mt_rand(0, $input_length - 1)];
$random_string .= $random_character;
}
return $random_string;
}
private function check_url() {
$ok = 0;
$url = $this->params['url'];
if (preg_match( '/ /', $url)) return false;
$parsed = parse_url($url);
$path = $parsed['path'];
if (preg_match("/%3Cscript3E/i", $path) ||
preg_match("/%3C.*%3E/i", $path) ||
preg_match("/\<.*\>/i", $path) ||
preg_match("/\<script\>/i", $path))
return false;
if (preg_match( '/^[a-z0-9_]+([\\-\\.]{1}[a-z_0-9]+)*\\.[_a-z]{2,6}'.'((:[0-9]{1,5})?\\/.*)?$/i' ,$parsed['host']))
return true;
else
return false;
}
private function get_data() {
$url = $this->params['url'];
$ch = curl_init();
$timeout = 20;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_ENCODING , "");
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
$response = curl_exec($ch);
if ($response === false) {
if (preg_match("/Unknown error/", curl_error($ch)) ||
preg_match("/Permission denied/", curl_error($ch))) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_ENCODING , "");
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
$response = curl_exec($ch);
}
}
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$data = substr($response, $header_size);
if (gettype($ch) == 'resource') curl_close($ch);
if ($code == 304) return array(304, '');
if (empty($data)) {
// np. connection refused
if ($code == 0)
return array(2, "Can't connect");
return array(3, 'Empty document');
}
if ($code >= 200 && $code <= 301) {
return array(0, $data);
}
switch($code) {
case 401:
$error_status="401: Login failure. Try logging out and back in.";
break;
case 400:
$error_status="400: Invalid request. You may have exceeded your rate limit.";
break;
case 403:
$error_status="403: Forbidden.";
break;
case 404:
$error_status="404: Not found.";
break;
case 405:
$error_status="405: Method not allowed.";
break;
case 406:
$error_status="406: Not acceptable.";
break;
case 500:
$error_status="500: Internal error.";
break;
case 502:
$error_status="502: Bad gateway.";
case 503:
$error_status="503: Service Unavailable.";
break;
default:
$error_status="Undocumented error: " . $status_code;
break;
}
return array(1, $error_status);
}
public function checkmetadata() {
$params = $this->params;
$schres = 0;
$certidx = -1;
if ( ($params['validate'] || $params['entities']) && ($params['url'] != "") ) {
$ret = $this->get_data();
if ($ret[0] == 304) {
$result = array();
$result['global']['required']['passed'] = array();
$result['global']['required']['failed'] = array();
$result['global']['required']['code'][] = 304;
$result['global']['recommended']['passed'] = array();
$result['global']['recommended']['failed'] = array();
$result['entities'] = array();
$result['sources'] = $params['url'];
$f = fopen($this->params['filename'], 'w');
fputs($f, json_encode($result));
fclose($f);
$res = $schres = 304;
} elseif ($ret[0] > 0) {
$result = array();
$result['global']['required']['passed'] = array();
$result['global']['required']['failed'][] = $ret[1];
$result['global']['required']['code'][] = 14;
$result['global']['recommended']['passed'] = array();
$result['global']['recommended']['failed'] = array();
$result['entities'] = array();
$result['sources'] = $url;
$f = fopen($params['filename'], 'w');
fputs($f, json_encode($result));
fclose($f);
$res = $schres = 14;
$aggres = 0;
$pyffres = 0;
} elseif ($ret[0] == 0) {
$f = fopen($params['filename'].'-metadata.xml', 'w');
fputs($f, $ret[1]);
fclose($f);
$aggres = 0;
$pyffres = 0;
$args = "\"".$params['url']."\" \"".$params['regauth']."\" ".$params['filename']." \"".$params['langsetting']."\" ".$params['validate']." ".$params['onlyone']." ".$params['weakkeys']." ".$params['xmlout']." ".$params['edugain']." ".base64_encode($params['fedname']);
system($this->validatordir."/schemas.py $args",$schres);
if ($params['onlyone'] && !$schres) {
$params['onlyone'] = 0;
unset($_REQUEST['oneentity']);
}
#if ($params['validate'] && !$params['onlyone'] && ($schres<2)) {
if ($params['validate'] && !$params['onlyone']) {
if ($params['edugain'] || $params['gobetween']) $fromdb = 1;
else $fromdb = 0;
system($this->validatordir."/aggregator.py ".$params['filename']." $schres $fromdb >".$params['filename']."-aggregator.log 2>&1",$aggres);
$certidx = trim(file_get_contents($params['filename']."-aggregator.log"));
error_log("certidx=$certidx");
if ($certidx == '') {
$certidx = 0;
}
system($this->validatordir."/mda.sh --verbose ".$params['filename'].".xml main > ".$params['filename']."-mda.log 2>&1", $res);
$searchfor = "Unable to validate signature";
$matches = array();
$handle = @fopen($params['filename']."-mda.log", "r");
if ($handle) {
while (!feof($handle)) {
$buffer = fgets($handle);
if (strpos($buffer, $searchfor) !== FALSE) {
$matches[] = $buffer;
break;
}
}
fclose($handle);
}
if (count($matches) && $certdb > 1) {
system($this->validatordir."/aggregator.py ".$params['filename']." $schres $fromdb 1 >".$params['filename']."-aggregator2.log 2>&1",$aggres);
system($this->validatordir."/mda.sh --verbose ".$params['filename']."_1.xml main > ".$params['filename']."-mda.log 2>&1", $res);
$certidx = trim(file_get_contents($params['filename']."-aggregator2.log"));
if ($certidx == '') {
$certidx = 1;
}
}
system($this->validatordir."/pyff.sh ".$params['filename'].'>'.$params['filename']."-pyff.log 2>&1", $pyffres);
} else $res = $schres;
}
$args = $params['filename']." \"".$params['langsetting']."\" ".$params['validate']." ".$params['onlyone']." ".$params['xmlout']." ".$params['gobetween']." ".$params['edugain'];
$printres = shell_exec($this->validatordir."/printresults.py $args $res $schres $aggres $pyffres $certidx");
} else
$printres = "<span class='noticeerr'>URL fetching failed ".$ret[1]."</span>";
if (!$params['gobetween']) {
system('rm '.$params['filename']."*");
}
return array($schres, $printres);
}
}