From f79ef214583f9646a73dfb29ea42c0217be511c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 13 Mar 2019 14:50:36 +0100 Subject: [PATCH] [HttpClient] Add new bearer option --- .../Component/HttpClient/HttpClientTrait.php | 22 ++++++++++++---- .../Component/HttpClient/HttpOptions.php | 12 ++++++++- .../HttpClient/Tests/HttpClientTraitTest.php | 26 +++++++++++++++++++ .../HttpClient/HttpClientInterface.php | 3 ++- .../HttpClient/Test/HttpClientTestCase.php | 4 +-- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 3b81f4ba9e27..4804118449da 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -71,18 +71,30 @@ private static function prepareRequest(?string $method, ?string $url, array $opt throw new InvalidArgumentException(sprintf('Option "on_progress" must be callable, %s given.', \is_object($onProgress) ? \get_class($onProgress) : \gettype($onProgress))); } - if (!\is_string($options['auth'] ?? '')) { - throw new InvalidArgumentException(sprintf('Option "auth" must be string, %s given.', \gettype($options['auth']))); + if (!\is_string($options['auth_basic'] ?? '')) { + throw new InvalidArgumentException(sprintf('Option "auth_basic" must be string, %s given.', \gettype($options['auth_basic']))); + } + + if (!\is_string($options['auth_bearer'] ?? '')) { + throw new InvalidArgumentException(sprintf('Option "auth_bearer" must be string, %s given.', \gettype($options['auth_bearer']))); + } + + if (isset($options['auth_basic'], $options['auth_bearer'])) { + throw new InvalidArgumentException('Define either the "auth_basic" or the "auth_bearer" option, setting both is not supported.'); } if (null !== $url) { // Merge auth with headers - if (($options['auth'] ?? false) && !($headers['authorization'] ?? false)) { - $rawHeaders[] = 'authorization: '.$headers['authorization'][] = 'Basic '.base64_encode($options['auth']); + if (($options['auth_basic'] ?? false) && !($headers['authorization'] ?? false)) { + $rawHeaders[] = 'authorization: '.$headers['authorization'][] = 'Basic '.base64_encode($options['auth_basic']); + } + // Merge bearer with headers + if (($options['auth_bearer'] ?? false) && !($headers['authorization'] ?? false)) { + $rawHeaders[] = 'authorization: '.$headers['authorization'][] = 'Bearer '.$options['auth_bearer']; } $options['raw_headers'] = $rawHeaders; - unset($options['auth']); + unset($options['auth_basic'], $options['auth_bearer']); // Parse base URI if (\is_string($options['base_uri'])) { diff --git a/src/Symfony/Component/HttpClient/HttpOptions.php b/src/Symfony/Component/HttpClient/HttpOptions.php index ce85eaf274d5..f723229a05ff 100644 --- a/src/Symfony/Component/HttpClient/HttpOptions.php +++ b/src/Symfony/Component/HttpClient/HttpOptions.php @@ -34,13 +34,23 @@ public function toArray(): array /** * @return $this */ - public function setAuth(string $userinfo) + public function setAuthBasic(string $userinfo) { $this->options['auth'] = $userinfo; return $this; } + /** + * @return $this + */ + public function setAuthBearer(string $token) + { + $this->options['bearer'] = $token; + + return $this; + } + /** * @return $this */ diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php index 815a1ab617d0..022e1de229e1 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpClient\HttpClientTrait; +use Symfony\Contracts\HttpClient\HttpClientInterface; class HttpClientTraitTest extends TestCase { @@ -163,4 +164,29 @@ public function provideRemoveDotSegments() yield ['/a/', '/a/b/..']; yield ['/a///b', '/a///b']; } + + public function testAuthBearerOption() + { + [, $options] = self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foobar'], HttpClientInterface::OPTIONS_DEFAULTS); + $this->assertSame('Bearer foobar', $options['headers']['authorization'][0]); + $this->assertSame('authorization: Bearer foobar', $options['raw_headers'][0]); + } + + /** + * @expectedException \Symfony\Component\HttpClient\Exception\InvalidArgumentException + * @expectedExceptionMessage Option "auth_bearer" must be string, object given. + */ + public function testInvalidAuthBearerOption() + { + self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => new \stdClass()], HttpClientInterface::OPTIONS_DEFAULTS); + } + + /** + * @expectedException \Symfony\Component\HttpClient\Exception\InvalidArgumentException + * @expectedExceptionMessage Define either the "auth_basic" or the "auth_bearer" option, setting both is not supported. + */ + public function testSetBasicAndBearerOption() + { + self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foo', 'auth_basic' => 'foo:bar'], HttpClientInterface::OPTIONS_DEFAULTS); + } } diff --git a/src/Symfony/Contracts/HttpClient/HttpClientInterface.php b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php index 8d58e813e812..2609ba4bbf48 100644 --- a/src/Symfony/Contracts/HttpClient/HttpClientInterface.php +++ b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php @@ -26,7 +26,8 @@ interface HttpClientInterface { public const OPTIONS_DEFAULTS = [ - 'auth' => null, // string - a username:password enabling HTTP Basic authentication + 'auth_basic' => null, // string - a username:password enabling HTTP Basic authentication (RFC 7617) + 'auth_bearer' => null, // string - a token enabling HTTP Bearer authorization (RFC 6750) 'query' => [], // string[] - associative array of query string values to merge with the request's URL 'headers' => [], // iterable|string[]|string[][] - headers names provided as keys or as part of values 'body' => '', // array|string|resource|\Traversable|\Closure - the callback SHOULD yield a string diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 44ee92bfa593..9c98d5bb32f3 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -214,7 +214,7 @@ public function testRedirects() { $client = $this->getHttpClient(); $response = $client->request('POST', 'http://localhost:8057/301', [ - 'auth' => 'foo:bar', + 'auth_basic' => 'foo:bar', 'body' => function () { yield 'foo=bar'; }, @@ -291,7 +291,7 @@ public function testMaxRedirects() $client = $this->getHttpClient(); $response = $client->request('GET', 'http://localhost:8057/301', [ 'max_redirects' => 1, - 'auth' => 'foo:bar', + 'auth_basic' => 'foo:bar', ]); try {