Skip to content

Commit 911dc5b

Browse files
committed
Fix bug #55639: Digest autentication dont work
RFC 2617 and 7616 describe that for the "Authorization" header we should not put the qop nor nc value inside quotes. This differs from the WWW-Authenticate header, which may have been the source of the confusion in the implementation. While the version with quotes seems to work fine in some cases, clearly not all servers accept the non-standard form. To fix the issue, simply removing the quotes of those two header fields of the client request to be in line with the RFC suffices. I refer further to example 3.5 in RFC 2617 and example 3.9.1 in RFC 7616. RFC 2617: https://datatracker.ietf.org/doc/html/rfc2617 RFC 7616: https://datatracker.ietf.org/doc/html/rfc7616 Closes GH-14328.
1 parent b368db2 commit 911dc5b

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.2.23
44

5+
- Soap:
6+
. Fixed bug #55639 (Digest autentication dont work). (nielsdos)
7+
58
01 Aug 2024, PHP 8.2.22
69

710
- Core:

ext/soap/php_http.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ int make_http_soap_request(zval *this_ptr,
745745
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
746746
PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
747747
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
748-
/* TODO: Support for qop="auth-int" */
748+
/* TODO: Support for qop=auth-int */
749749
PHP_MD5Update(&md5ctx, (unsigned char*)"auth", sizeof("auth")-1);
750750
PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
751751
}
@@ -781,11 +781,11 @@ int make_http_soap_request(zval *this_ptr,
781781
}
782782
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "qop", sizeof("qop")-1)) != NULL &&
783783
Z_TYPE_P(tmp) == IS_STRING) {
784-
/* TODO: Support for qop="auth-int" */
785-
smart_str_append_const(&soap_headers, "\", qop=\"auth");
786-
smart_str_append_const(&soap_headers, "\", nc=\"");
784+
/* TODO: Support for qop=auth-int */
785+
smart_str_append_const(&soap_headers, "\", qop=auth");
786+
smart_str_append_const(&soap_headers, ", nc=");
787787
smart_str_appendl(&soap_headers, nc, 8);
788-
smart_str_append_const(&soap_headers, "\", cnonce=\"");
788+
smart_str_append_const(&soap_headers, ", cnonce=\"");
789789
smart_str_appendl(&soap_headers, cnonce, 8);
790790
}
791791
smart_str_append_const(&soap_headers, "\", response=\"");

ext/soap/tests/bugs/bug55639.phpt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
Bug #55639 (Digest authentication dont work)
3+
--INI--
4+
soap.wsdl_cache_enabled=0
5+
--EXTENSIONS--
6+
soap
7+
--SKIPIF--
8+
<?php
9+
if (!file_exists(__DIR__ . "/../../../../sapi/cli/tests/php_cli_server.inc")) {
10+
echo "skip sapi/cli/tests/php_cli_server.inc required but not found";
11+
}
12+
?>
13+
--FILE--
14+
<?php
15+
16+
include __DIR__ . "/../../../../sapi/cli/tests/php_cli_server.inc";
17+
18+
$args = ["-d", "extension_dir=" . ini_get("extension_dir"), "-d", "extension=" . (substr(PHP_OS, 0, 3) == "WIN" ? "php_" : "") . "soap." . PHP_SHLIB_SUFFIX];
19+
if (php_ini_loaded_file()) {
20+
// Necessary such that it works from a development directory in which case extension_dir might not be the real extension dir
21+
$args[] = "-c";
22+
$args[] = php_ini_loaded_file();
23+
}
24+
25+
$code = <<<'PHP'
26+
/* Receive */
27+
header('HTTP/1.0 401 Unauthorized');
28+
header('WWW-Authenticate: Digest realm="realm", qop="auth,auth-int", nonce="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", opaque="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"');
29+
file_get_contents("php://input");
30+
PHP;
31+
32+
php_cli_server_start($code, null, $args);
33+
34+
$client = new soapclient(NULL, [
35+
'location' => 'http://' . PHP_CLI_SERVER_ADDRESS,
36+
'uri' => 'misc-uri',
37+
'authentication' => SOAP_AUTHENTICATION_DIGEST,
38+
'realm' => 'myrealm',
39+
'login' => 'user',
40+
'password' => 'pass',
41+
'trace' => true,
42+
]);
43+
44+
try {
45+
$client->__soapCall("foo", []);
46+
} catch (Throwable $e) {
47+
echo $e->getMessage(), "\n";
48+
}
49+
50+
$headers = $client->__getLastRequestHeaders();
51+
var_dump($headers);
52+
53+
?>
54+
--EXPECTF--
55+
Unauthorized
56+
string(424) "POST / HTTP/1.1
57+
Host: %s
58+
Connection: Keep-Alive
59+
User-Agent: %s
60+
Content-Type: text/xml; charset=utf-8
61+
SOAPAction: "misc-uri#foo"
62+
Content-Length: %d
63+
Authorization: Digest username="user", realm="realm", nonce="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", uri="/", qop=auth, nc=00000001, cnonce="%s", response="%s", opaque="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
64+
65+
"

0 commit comments

Comments
 (0)