Bonjour, Vous trouvrez le script correspondant à la fonction qui gère le Header Digest pour une communication de type HTTP/HTTPS Authorization Digest. D'autres fonctions ont été ajoutées, elle peuvent être utiles dans le script principal mais pas nécessaires dans le gestion du Header Digest. Vos commentaires sont la bienvenue pour améliorer cette boîte à outils. Bon weekend de Pâques. dommarion
- Code : Tout sélectionner
<?php //------------------------------------------------------------------------------------------------------------------------------------------------------ // Version 1.0 dommarion - PHP developped function for Handelling an HTTP/HTTPS with the Digest Authorization protocol based on RFC 7616 specification // Reference at this adress: https://httpwg.org/specs/rfc7616.html // Specific for eedomus box - less than de 50Ko and limited PHP instructions // // Global variables (to be definced and managed into the main script) // $debug : set by default to 0 and set to 1 to get debuggging trace by echo and var_dump functions // $ncvalue : the counting of successful Digest communications to be handled after a successful httpQuery by checking the header value "HTTP/1.1 200 OK" // $uniqId : a unique id to identify the saved variable if the Plugin is used on more than one instance (usually the // // Input data // Mandatory input data: // $username : username for the Digest authentication // $password : password for the Digest authentication // // Optional or set by default input data // $method='GET' : values can be 'GET" or 'POST' // $request_uri=null : URI to address during the 'POST' query // $payload=null : Body message to send during the 'POST' query, needed only if qop='auth-int' and 'POST' query // $first_server_header=null : first header received when requesting an authentication, this header should at least contain realm and nonce values //------------------------------------------------------------------------------------------------------------------------------------------------------ //--------------------------------------------------------------------------------------- // Toolbox functions - not used in this specific function, but useful in the main script //---------------------------------------------------------------------------------------
// Specific eedomus function to replace the PHP json_encode() function sdk_json_encode($value){ if (is_string($value)) return '"'.addslashes($value).'"'; if (is_numeric($value)) return $value; if ($value === null) return 'null'; if ($value === true) return 'true'; if ($value === false) return 'false';
$assoc = false; $i = 0; foreach ($value as $k=>$v){ if ($k !== $i++){ $assoc = true; break; } } $res = array(); foreach ($value as $k=>$v){ $v = sdk_json_encode($v); if ($assoc){ $k = '"'.addslashes($k).'"'; $v = $k.':'.$v; } $res[] = $v; } $res = implode(',', $res); if ($assoc) {return '{'.$res.'}';} else {return '['.$res.']';} }
// Random character to generate a String function sdk_generateRandomString($length = 16) { global $debug; if (is_int($length)) { if ($length >0) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } } else {$randomString='';} } else {$randomString='';} return $randomString; }
// Specific eedomus function to replace the PHP strstr() function sdk_strstr($string,$needle,$before=false) { $found=strpos($string,$needle); if (is_int($found)) { if ($before) {$reply=substr($string,0,$found);} else {$reply=substr($string,$found,strlen($string)-$found);} } else {$reply= false;} return $reply; }
// Specific eedomus function to replace the PHP array_search() function sdk_array_search($element,$array) { global $debug; $length=count($array); $i=0; $key=null; for ($i;$i<$length;$i++) { if ($element == $array[$i]) {$key=$i;} } return $key; }
// Specific eedomus function to replace the PHP base64_decode() function sdk_base64_decode($encode64_string) { global $debug; $base=array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'); $array_string=str_split($encode64_string, 1); $rank=array(); $i=0; $binary=""; foreach ($array_string as $id=>$letter) {if ($letter!="=") {$rank[$i]=sdk_array_search($letter,$base); $binary=$binary.str_pad(decbin($rank[$i]), 6, '0', STR_PAD_LEFT); $i=$i+1; } } $length=strlen($binary); $integer=intval($length/8); $eightbit=array(); $j=0; $decode64=''; for ($j=0; $j<$integer; $j++) {$eightbit[$j]=substr($binary, $j*8, 8); $decode64.= chr(intval($eightbit[$j], 2)); } return $decode64; }
// Function to generate a sha1 coding signature using hmac based on RFC 2104 function sdk_create_signature($the_key, $to_sign) { global $debug; $signature = hash_hmac("sha1", utf8_encode($to_sign), $the_key); $signature = base64_encode(utf8_encode($signature)); return $signature; } // //--------------------------------------------------------------------------------------- // Functions used in this part //---------------------------------------------------------------------------------------
// Function to hash using md5 or sha1 or sha256 or sha512 or haval160 or ... function sdk_H($algorithmm,$parameter) { return hash($algorithmm,$parameter,false); }
// Function to hash a merged result of a:b function sdk_KD($algorithmm,$a,$b) { return sdk_H($algorithmm,"$a:$b"); }
// Function to transform an Header in an Array function sdk_getHeaders($respHeaders) { global $debug; // If missing line end then add it before processing it if (!strpos($respHeaders, "\r\n\r\n")) {$respHeaders .= "\r\n\r\n";} $headers = array(); $headerText = substr($respHeaders, 0, strpos($respHeaders, "\r\n\r\n")); foreach (explode("\r\n", $headerText) as $i => $line) { if ($i === 0) { $headers['http_code'] = $line; } else { list ($key, $value) = explode(': ', $line); $headers[$key] = $value; } } return $headers; }
// Function to parse the WWW-Authenticate: Digest part of the Header function sdk_parsehttpdigest($digest) { global $debug; $data = array(); $parts = explode(", ", $digest); $i=0; foreach ($parts as $element) { $length=strlen($element); $bits=array(); for ($j=0; $j<$length; $j++) { $char=substr($element, $j, 1); if ($char == '=') {$bits[0] = substr($element,0,$j); $bits[1] = substr($element,$j+1,$length-($j+1)); $j=$length;} } if (isset($bits[1])) {$data[$bits[0]] = str_replace('"','', $bits[1]);} else {$data[$bits[0]] = str_replace('"','', "");} $i=$i+1; } return $data; }
// Function to decode, calculate and prepare the Header Digest to be sent to the server function sdk_httpdigestauth($username, $password, $method='GET', $request_uri=null, $payload=null, $first_server_header=null) { global $debug,$ncvalue,$uniqId; if ($first_server_header !== null) { $headers=sdk_getHeaders($first_server_header); list($dummy_digest,$value) = explode('Digest ', $headers['WWW-Authenticate'], 2); // Parsing the Digest Header part to allocate the needed parameters $x = sdk_parsehttpdigest($value); // if the parameter: "realm" has not been found into the first_header - MANDATORY if (!isset($x['realm'])) {$realm=null;} else {$realm = $x['realm'];} // if the parameter: "domain" has not been found into the first_header - IGNORED if (!isset($x['domain'])) {$domain=null;} else {$domain=$x['domain'];} // if the parameter: "nonce" has not been found into the first_header - MANDATORY if (!isset($x['nonce'])) {$nonce=null;} else {$nonce=$x['nonce'];} // if the parameter: "opaque" has not been found into the first_header - OPTIONAL if (!isset($x['opaque'])) {$opaque=null;} else {$opaque = $x['opaque'];} // if the parameter: "stale" has not been found into the first_header - OPTIONAL if (!isset($x['stale'])) {$stale=null;} else {$stale = $x['stale'];} // if the parameter: "algorithm" has not been found into the first_header - OPTIONAL by default = MD5 if (!isset($x['algorithm'])) {$algorithm="MD5";} else {$algorithm=$x['algorithm'];} // if the parameter: "qop" has not been found into the first_header - MANDATORY by default = auth if (!isset($x['qop'])) {$qop="auth";} else {$qop=$x['qop'];} // if the parameter: "charset" has not been found into the first_header - OPTIONAL if (!isset($x['charset'])) {$charset=null;} else {$charset=$x['charset'];} // if the parameter: "userhash" has not been found into the first_header - OPTIONAL if (!isset($x['userhash'])) {$userhash=null;} else {$userhash = $x['userhash'];} // if the parameter: "nc" has not been found into the first_header - OPTIONAL if (!isset($x['nc'])) {$ncvalue=null;} else {$ncvalue=$x['nc'];} } else { // In case no more first_header, mandatory parameters are retreived from saved data for further communication $realm = loadVariable('realm'.$uniqId); $nonce = loadVariable('nonce'.$uniqId); $qop = loadVariable('qop'.$uniqId); $ncvalue = loadVariable('ncvalue'.$uniqId); // if the parameter: "qop" has not been restored from saved data - MANDATORY by default = auth if (!isset($qop)) {$qop="auth";} $algorithm = loadVariable('algorithm'.$uniqId); // if the parameter: "algorithm" has not been restored from saved data - OPTIONAL by default = MD5 if (!isset($algorithm)) {$qop="MD5";} } // nc: nouce count is starting with 1 and increased by 1 at each successful communication between client and servor nc=string(8) "00000001" if (isset($ncvalue)) {$ncvalue=dechex(hexdec($ncvalue)+1);} else {$ncvalue=1;} if (hexdec($ncvalue) >= hexdec('100000000')) {$ncvalue=1; } // Formattage du nc avec plusieurs 0 avant le nombre entier $nc = str_pad($ncvalue, 8, '0', STR_PAD_LEFT); // If userhash=true then username is encryped using KD function with $realm based on the specified algorithm if (isset($userhash)&&$userhash) {$username=sdk_KD($algorithm,$username,$realm);} // Computation of A1, A2, cnonce according to RFC 7616 specification $A1 = $username.":".$realm.":".$password; $A2 = $method.":".$request_uri; $cnonce = time(); if ($qop == 'auth-int') { // In case of 'auth-int' -> the Body message will be included into the A2 parameter according to RFC 7616 specification $A2 = $method.":".$request_uri.":".sdk_H($algorithm,$payload); } $noncebit = $nonce.":".$nc.":".$cnonce.":".$qop.":".sdk_H($algorithm,$A2); // Computation of the Digest response parameter according to RFC 7616 specification $respdig = sdk_KD($algorithm,sdk_H($algorithm,$A1), $noncebit); //The value of the header field can include parameters list: username, realm, nonce, uri, qop, nc, cnonce, response, opaque, userhash and algorithm $header_Digest = 'username="'.$username.'", realm="'.$realm.'", nonce="'.$nonce.'", uri="'.$request_uri.'", qop="'.$qop.'", nc="'.$nc.'", cnonce="'.$cnonce.'", response="'.$respdig.'"'; if (isset($opaque)) {$header_Digest .= ', opaque="'.$opaque.'"';} if (isset($userhash)) {$header_Digest .= ', userhash='.$userhash;} $header_Digest .= ', algorithm='.$algorithm; // Debug Mode to trace and display if ($debug == 1) {echo "Parameters:\n"; echo "pass=".$password."\n"; echo "method=".$method."\n"; echo "A1=".$A1."\n"; echo "A2=".$A2."\n"; echo "noncebit=".$noncebit."\n"; echo $header_Digest; } // Saving Parameters for further use: realm, nonce, qop, algorithm - ncvalue will be backed-up only when the Digest communication will be acepted by the server with the HTTP/1.1 200 OK saveVariable('realm'.$uniqId,$realm); saveVariable('nonce'.$uniqId,$nonce); saveVariable('qop'.$uniqId,$qop); saveVariable('algorithm'.$uniqId,$algorithm); return $header_Digest; }
//--------------------------------------------------------------------------------------- /* example of a function GET with httpQuery // Function httpQuery 'GET' with authentification Digest - parameter $url=string,$user=string,$pass=string,$uri=string, return $state=array() function sdk_GETDigest($url,$user,$pass,$uri){ global $debug, $host, $port, $ncvalue, $uniqId; $method='GET'; $ignore_errors = true; $payload=""; $header_received=array(); $headerDigest=sdk_httpdigestauth($user, $pass, $method, $uri, $payload=null, $server_header=null); $header=array("Host: ".$host.":".$port,"Accept: application/json;charset=utf-8","Authorization: Digest ".$headerDigest,"Content-Length:".strlen($payload),"Content-Type:application/x-www-form-urlencoded;charset=utf-8"); $reply=httpQuery($url, $method, null, null, $header, false, $ignore_errors,&$header_received,null); if (sdk_strstr($header_received['header'],"HTTP/1.1 200 OK")) {saveVariable('ncvalue'.$uniqId,$ncvalue);} // Debug Mode to trace and display if ($debug == 1) {echo "Header response:";var_dump($header_received['header']);} return $reply; } */ /* example of a function POST with httpQuery // Function httpQuery 'POST' with authentification Digest - parameter $url=string,$payload=string,$user=string,$pass=string,$uri=string return $state=array() function sdk_POSTDigest($url,$payload,$user,$pass,$uri) { global $debug, $host, $port, $ncvalue, $uniqId; $method='POST'; $ignore_errors=true; $header_received=array(); $headerDigest=sdk_httpdigestauth($user, $pass, $method, $uri, $payload=null, $server_header=null); $header=array("Host: ".$host.":".$port,"Accept: application/json;charset=utf-8","Authorization: Digest ".$headerDigest,"Content-Length:".strlen($payload),"Content-Type:application/x-www-form-urlencoded;charset=utf-8"); $reply=httpQuery($url,$method, $payload, null, $header,false,$ignore_errors,&$header_received,null); // Debug Mode to trace and display if ($debug == 1) {echo "Header response:";var_dump($header_received['header']);} if (sdk_strstr($header_received['header'],"HTTP/1.1 200 OK")) {saveVariable('ncvalue'.$uniqId,$ncvalue);} return $reply; } */
?>
|