phphashdigest-authentication

Why does digest query in fopen return a response only 1 out of 50 times?


Authorization via digest happens in 2 steps. At the beginning I get a 401 error and in the header I get the data I need. Then I use this data to calculate the response.

# first query
$resource = fopen($url, 'r');
p($http_response_header);

# get nonce
preg_match('/nonce="([^"]+)"/', $http_response_header[1], $matches);
$nonce = $matches[1];

# calculate request for digest
$digest = calculateDigest($username, $password, $realm, $nonce, $uri, $method, $qop, $nc, $cnonce);

// HTTP header settings
$options = [
    'http' => [
        'method' => 'GET',
        'header' => "Authorization: Digest username=\"{$username}\", realm=\"{$realm}\", nonce=\"{$nonce}\", uri=\"{$uri}\", response=\"{$digest}\", opaque=\"{$opaque}\", qop={$qop}, nc={$nc}, cnonce=\"{$cnonce}\""",
    ],
];

# second request
$resource = fopen($url, 'r', false, stream_context_create($options));
p($http_response_header);

// Read data from the file (URL)
while (!feof($resource)) {
    $response = fgets($resource);
}

// Closing the resource
fclose($resource);

p($response);

I run it in a browser and see the following picture:

Warning: fopen(http://myip/cgi-bin/mediaFileFind.cgi?action=factory.create): Failed to open stream: HTTP request failed! HTTP/1.1 401 Unauthorized in C:\OSPanel\domains\cam.local\uploader.php on line 54
Array
(
    [0] => HTTP/1.1 401 Unauthorized
    [1] => WWW-Authenticate: Digest realm="Login to bd72fbb2e0734a3cb18d4cb40504cdf0", qop="auth", nonce="2142598378", opaque="1a067f2162e6693bed2d111d38af7bee229a316f"
    [2] => Connection: close
    [3] => CONTENT-LENGTH: 0
)
Array
(
    [0] => HTTP/1.1 200 OK
    [1] => X-XSS-Protection: 1;mode=block
    [2] => X-Frame-Options: SAMEORIGIN
    [3] => Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval'
    [4] => Strict-Transport-Security: max-age=604800; includeSubDomains
    [5] => Content-type: text/plain;charset=utf-8
    [6] => CONNECTION: close
    [7] => CONTENT-LENGTH: 19
)

But if I refresh the page several times, I see this picture:

...
    [5] => Content-type: text/plain;charset=utf-8
    [6] => CONNECTION: close
    [7] => CONTENT-LENGTH: 19
)
result=2134173032

result is exactly the output of $response. So for some reason result is not displayed. How can I figure out what the reason is and fix it? If I do the usual file_get_contents(), everything will work, but I am interested in fopen().


Solution

  • // Read data from the file (URL)
    while (!feof($resource)) {
        $response = fgets($resource);
    }
    

    You overwriting $response here, instead of appending to it. This way, you will only ever get the last "line" of the result.

    result=2134173032 is 17 bytes long in UTF-8, but the Content-Length gets reported as 19. The two additional characters might be a line break? Depending on whether that occurs before or after the actual content you are looking for here, you might get that actual content - or, nothing. (We can't know if your endpoint always returns the same data, or same structure at least, or if that might vary.)