feature #30547 [HttpClient] Add new bearer option (dunglas)
This PR was squashed before being merged into the 4.3-dev branch (closes #30547).
Discussion
----------
[HttpClient] Add new bearer option
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes<!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks? | no <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass? | yes <!-- please add some, will be required by reviewers -->
| Fixed tickets | n/a <!-- #-prefixed issue number(s), if any -->
| License | MIT
| Doc PR | n/a
Add a new "auth_bearer" option to set the corresponding flavor of the `Authorization` header as defined in RFC 6750 and used in OAuth (and others).
Also rename "auth" to "auth_basic" for consistency as discussed with @nicolas-grekas.
Commits
-------
f79ef21458
[HttpClient] Add new bearer option
This commit is contained in:
commit
535c482a4d
@ -71,18 +71,30 @@ trait HttpClientTrait
|
|||||||
throw new InvalidArgumentException(sprintf('Option "on_progress" must be callable, %s given.', \is_object($onProgress) ? \get_class($onProgress) : \gettype($onProgress)));
|
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'] ?? '')) {
|
if (!\is_string($options['auth_basic'] ?? '')) {
|
||||||
throw new InvalidArgumentException(sprintf('Option "auth" must be string, %s given.', \gettype($options['auth'])));
|
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) {
|
if (null !== $url) {
|
||||||
// Merge auth with headers
|
// Merge auth with headers
|
||||||
if (($options['auth'] ?? false) && !($headers['authorization'] ?? false)) {
|
if (($options['auth_basic'] ?? false) && !($headers['authorization'] ?? false)) {
|
||||||
$rawHeaders[] = 'authorization: '.$headers['authorization'][] = 'Basic '.base64_encode($options['auth']);
|
$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;
|
$options['raw_headers'] = $rawHeaders;
|
||||||
unset($options['auth']);
|
unset($options['auth_basic'], $options['auth_bearer']);
|
||||||
|
|
||||||
// Parse base URI
|
// Parse base URI
|
||||||
if (\is_string($options['base_uri'])) {
|
if (\is_string($options['base_uri'])) {
|
||||||
|
@ -34,13 +34,23 @@ class HttpOptions
|
|||||||
/**
|
/**
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAuth(string $userinfo)
|
public function setAuthBasic(string $userinfo)
|
||||||
{
|
{
|
||||||
$this->options['auth'] = $userinfo;
|
$this->options['auth'] = $userinfo;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setAuthBearer(string $token)
|
||||||
|
{
|
||||||
|
$this->options['bearer'] = $token;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\HttpClient\Tests;
|
|||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\HttpClient\HttpClientTrait;
|
use Symfony\Component\HttpClient\HttpClientTrait;
|
||||||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
class HttpClientTraitTest extends TestCase
|
class HttpClientTraitTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -163,4 +164,29 @@ class HttpClientTraitTest extends TestCase
|
|||||||
yield ['/a/', '/a/b/..'];
|
yield ['/a/', '/a/b/..'];
|
||||||
yield ['/a///b', '/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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ use Symfony\Contracts\HttpClient\Test\HttpClientTestCase;
|
|||||||
interface HttpClientInterface
|
interface HttpClientInterface
|
||||||
{
|
{
|
||||||
public const OPTIONS_DEFAULTS = [
|
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
|
'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
|
'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
|
'body' => '', // array|string|resource|\Traversable|\Closure - the callback SHOULD yield a string
|
||||||
|
@ -214,7 +214,7 @@ abstract class HttpClientTestCase extends TestCase
|
|||||||
{
|
{
|
||||||
$client = $this->getHttpClient();
|
$client = $this->getHttpClient();
|
||||||
$response = $client->request('POST', 'http://localhost:8057/301', [
|
$response = $client->request('POST', 'http://localhost:8057/301', [
|
||||||
'auth' => 'foo:bar',
|
'auth_basic' => 'foo:bar',
|
||||||
'body' => function () {
|
'body' => function () {
|
||||||
yield 'foo=bar';
|
yield 'foo=bar';
|
||||||
},
|
},
|
||||||
@ -291,7 +291,7 @@ abstract class HttpClientTestCase extends TestCase
|
|||||||
$client = $this->getHttpClient();
|
$client = $this->getHttpClient();
|
||||||
$response = $client->request('GET', 'http://localhost:8057/301', [
|
$response = $client->request('GET', 'http://localhost:8057/301', [
|
||||||
'max_redirects' => 1,
|
'max_redirects' => 1,
|
||||||
'auth' => 'foo:bar',
|
'auth_basic' => 'foo:bar',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Reference in New Issue
Block a user