Skip to content
Snippets Groups Projects
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);
    }

}