<?php /** * Check authorization in the http request header and age of timestamp * On a failed check the request will be terminated; on suceess it returns * the hash * @param string $sMySecret server api key (from config file) * @param int $iMaxAge max allowed age in [sec] * @return string */ function _checkAuth($sMySecret, $iMaxAge=60){ $aReqHeaders=apache_request_headers(); _wd('request headers: <pre>'.print_r($aReqHeaders, 1).'</pre>'); if(!isset($aReqHeaders['Authorization'])){ _quit('Access denied. Missing authorization.', 403); } if(!isset($aReqHeaders['Date'])){ _quit('Access denied. Missing field "Date:" in the request header.', 403); } $sGotHash= preg_replace('/^.*\:/', '', $aReqHeaders['Authorization']); $sGotDate= $aReqHeaders['Date']; $sGotMethod=$_SERVER['REQUEST_METHOD']; $sGotReq=$_SERVER['REQUEST_URI']; $sMyData="{$sGotMethod}\n{$sGotReq}\n{$sGotDate}\n"; $sMyHash= base64_encode(hash_hmac("sha1", $sMyData, $sMySecret)); _wd('Hash: '.$sGotHash.' -- from header'); _wd('Hash: '.$sMyHash.' -- rebuilt'); if($sGotHash!==$sMyHash){ _quit('Access denied. Invalid hash.', 403); } $iAge=date('U')-date('U', strtotime($sGotDate)); _wd('Date: '.$sGotDate.' - age: '.$iAge.' sec'); if($iAge>$iMaxAge){ _quit('Access denied. Hash is out of date: '.$iAge. ' sec is older '.$iMaxAge.' sec. Maybe client or server time is out of sync.', 403); } if($iAge<-$iMaxAge){ _quit('Access denied. Hash is '.$iAge. ' sec in future but only '.$iMaxAge.' sec are allowed. Maybe client or server is out of sync.', 403); } return $sMyHash; } /** * check if a given secret was used already. * It is for hardening - allow one time usage of a hash * @param string $lockfile filename of lockfile with stored hashes * @param string $sMyHash hash to verify * @return boolean */ function _checkIfHashWasUsedAlready($lockfile, $sMyHash){ $bFound=false; $handle = @fopen($lockfile, "r"); if ($handle){ while (!feof($handle)) { $buffer = fgets($handle); if(strstr($buffer, $sMyHash)){ $bFound = true; } } fclose($handle); } return $bFound; } /** * helper function for enabled one time secret: start cleanup of storage with * used keys if a given filesize was reached. It keeps entries younger a given * max age (same max age like in _checkAuth() * @param string $lockfile filename of lockfile with stored hashes * @param integer $iMaxLockfilesize size in byte when to start garbage collection * @param integer $iMaxAge max allowed age in [sec] * @return boolean */ function _cleanupLockdata($lockfile, $iMaxLockfilesize, $iMaxAge){ if (filesize($lockfile)<$iMaxLockfilesize){ return false; } $sLockdata=''; $handle = @fopen($lockfile, "r"); if ($handle){ while (!feof($handle)) { $buffer = fgets($handle); $iTimestamp=(int)preg_replace('/\-.*$/', '', $buffer); if ($iTimestamp && date('U') - $iTimestamp < $iMaxAge){ $sLockdata.=$buffer; } } fclose($handle); file_put_contents($lockfile, $sLockdata); } return true; } /** * end with OK output * @param type $Data */ function _done($Data){ echo is_array($Data) ? json_encode($Data, JSON_PRETTY_PRINT) : $Data ; die(); } /** * abort execution with error * @param string $s message * @param integer $iStatus http status code to send */ function _quit($s, $iStatus=400){ $aStatus=array( 400=>'HTTP/1.0 400 Bad Request', 403=>'HTTP/1.0 403 Access denied', 404=>'HTTP/1.0 404 Not found', ); header($aStatus[$iStatus]); _sendHtml($aStatus[$iStatus], $s); die(); } /** * send html page * @param type $sTitle * @param type $sContent */ function _sendHtml($sTitle, $sContent){ echo '<!doctype html> <html> <head> <title>'.$sTitle.'</title> <link rel="stylesheet" type="text/css" href="/main.css" media="screen" /> </head> <body> <h1><span class="imllogo"></span> CI <span class="subdomain"> packages</span></h1> <h2>'.$sTitle.'</h2> <p> '.$sContent.' </p> <footer> <a href="https://www.iml.unibe.ch/">www.iml.unibe.ch</a> </footer> </body> </html> ' ; } /** * write debug text (if enabled) * @global boolean $bDebug * @param string $s message * @param string $sLevel level; one of info| * @return boolean */ function _wd($s, $sLevel='info'){ global $bDebug; if ($bDebug){ // echo '<div class="debug debug-'.$sLevel.'">DEBUG: '.$s.'</div>'; echo "DEBUG[$sLevel]: $s<br>\n"; } return true; }