diff --git a/lib/REST.php b/lib/REST.php index d7d64857..40b4e589 100644 --- a/lib/REST.php +++ b/lib/REST.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace JKingWeb\Arsse; use JKingWeb\Arsse\Arsse; +use JKingWeb\Arsse\Misc\ValueInfo; use JKingWeb\Arsse\Misc\URL; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; @@ -159,7 +160,10 @@ class REST { public function challenge(ResponseInterface $res, string $realm = null): ResponseInterface { $realm = $realm ?? Arsse::$conf->httpRealm; - return $res->withAddedHeader("WWW-Authenticate", 'Basic realm="'.$realm.'"'); + if (!ValueInfo::normalize($res->getHeaderLine("X-Arsse-Suppress-General-Auth"), ValueInfo::T_BOOL)) { + $res = $res->withAddedHeader("WWW-Authenticate", 'Basic realm="'.$realm.'", charset="UTF-8"'); + } + return $res->withoutHeader("X-Arsse-Suppress-General-Auth"); } public function normalizeResponse(ResponseInterface $res, RequestInterface $req = null): ResponseInterface { diff --git a/lib/REST/Microsub/Auth.php b/lib/REST/Microsub/Auth.php index ed2ecfaf..9cf96135 100644 --- a/lib/REST/Microsub/Auth.php +++ b/lib/REST/Microsub/Auth.php @@ -325,7 +325,10 @@ class Auth extends \JKingWeb\Arsse\REST\AbstractHandler { 'invalid_request' => 400, 'invalid_token' => 401, ][$errCode] ?? 500; - return new EmptyResponse($httpCode, ['WWW-Authenticate' => "Bearer error=\"$errCode\""]); + return new EmptyResponse($httpCode, [ + 'WWW-Authenticate' => "Bearer error=\"$errCode\"", + 'X-Arsse-Suppress-General-Auth' => "1" + ]); } return new JsonResponse([ 'me' => $data['me'] ?? "", diff --git a/tests/cases/REST/TestREST.php b/tests/cases/REST/TestREST.php index 994d6ac5..99864348 100644 --- a/tests/cases/REST/TestREST.php +++ b/tests/cases/REST/TestREST.php @@ -92,19 +92,26 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { [[], []], ]; } - - public function testSendAuthenticationChallenges() { + /** @dataProvider provideAuthenticationChallenges */ + public function testSendAuthenticationChallenges(ResponseInterface $in, ResponseInterface $exp, string $realm = null) { self::setConf(); - $r = new REST(); - $in = new EmptyResponse(401); - $exp = $in->withHeader("WWW-Authenticate", 'Basic realm="OOK"'); - $act = $r->challenge($in, "OOK"); - $this->assertMessage($exp, $act); - $exp = $in->withHeader("WWW-Authenticate", 'Basic realm="'.Arsse::$conf->httpRealm.'"'); - $act = $r->challenge($in); + $act = (new REST)->challenge($in, $realm); $this->assertMessage($exp, $act); } + public function provideAuthenticationChallenges() { + self::setConf(); + $default = 'Basic realm="'.Arsse::$conf->httpRealm.'", charset="UTF-8"'; + return [ + [new EmptyResponse(401), new EmptyResponse(401, ['WWW-Authenticate' => $default])], + [new EmptyResponse(401), new EmptyResponse(401, ['WWW-Authenticate' => 'Basic realm="OOK", charset="UTF-8"']), "OOK"], + [new EmptyResponse(401, ['WWW-Authenticate' => "Bearer"]), new EmptyResponse(401, ['WWW-Authenticate' => ['Bearer', $default]])], + [new EmptyResponse(401, ['X-Arsse-Suppress-General-Auth' => "false"]), new EmptyResponse(401, ['WWW-Authenticate' => $default])], + [new EmptyResponse(401, ['WWW-Authenticate' => "Bearer", 'X-Arsse-Suppress-General-Auth' => "false"]), new EmptyResponse(401, ['WWW-Authenticate' => ['Bearer', $default]])], + [new EmptyResponse(401, ['WWW-Authenticate' => "Bearer", 'X-Arsse-Suppress-General-Auth' => "1"]), new EmptyResponse(401, ['WWW-Authenticate' => "Bearer"])], + ]; + } + /** @dataProvider provideUnnormalizedOrigins */ public function testNormalizeOrigins(string $origin, string $exp, array $ports = null) { $r = new REST();