Skip to content

Commit

Permalink
feature #30547 [HttpClient] Add new bearer option (dunglas)
Browse files Browse the repository at this point in the history
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
-------

f79ef21 [HttpClient] Add new bearer option
  • Loading branch information
fabpot committed Mar 14, 2019
2 parents 50ff35f + f79ef21 commit 535c482
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 9 deletions.
22 changes: 17 additions & 5 deletions src/Symfony/Component/HttpClient/HttpClientTrait.php
Expand Up @@ -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'])) {
Expand Down
12 changes: 11 additions & 1 deletion src/Symfony/Component/HttpClient/HttpOptions.php
Expand Up @@ -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
*/
Expand Down
26 changes: 26 additions & 0 deletions src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php
Expand Up @@ -13,6 +13,7 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\HttpClientTrait;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class HttpClientTraitTest extends TestCase
{
Expand Down Expand Up @@ -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);
}
}
3 changes: 2 additions & 1 deletion src/Symfony/Contracts/HttpClient/HttpClientInterface.php
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php
Expand Up @@ -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';
},
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 535c482

Please sign in to comment.