Skip to content

Commit

Permalink
Moved authentication logic to individual handlers (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
dragonmantank authored Apr 16, 2021
1 parent 6d85bd2 commit 5360821
Show file tree
Hide file tree
Showing 12 changed files with 324 additions and 78 deletions.
98 changes: 28 additions & 70 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
use Vonage\Client\Credentials\Basic;
use Vonage\Client\Credentials\Container;
use Vonage\Client\Credentials\CredentialsInterface;
use Vonage\Client\Credentials\Handler\BasicHandler;
use Vonage\Client\Credentials\Handler\KeypairHandler;
use Vonage\Client\Credentials\Handler\SignatureBodyFormHandler;
use Vonage\Client\Credentials\Handler\SignatureBodyHandler;
use Vonage\Client\Credentials\Handler\SignatureQueryHandler;
use Vonage\Client\Credentials\Handler\TokenBodyFormHandler;
use Vonage\Client\Credentials\Handler\TokenBodyHandler;
use Vonage\Client\Credentials\Handler\TokenQueryHandler;
use Vonage\Client\Credentials\Keypair;
use Vonage\Client\Credentials\OAuth;
use Vonage\Client\Credentials\SignatureSecret;
Expand Down Expand Up @@ -297,97 +305,44 @@ public static function signRequest(RequestInterface $request, SignatureSecret $c
{
switch ($request->getHeaderLine('content-type')) {
case 'application/json':
$body = $request->getBody();
$body->rewind();
$content = $body->getContents();
$params = json_decode($content, true);
$params['api_key'] = $credentials['api_key'];
$signature = new Signature($params, $credentials['signature_secret'], $credentials['signature_method']);
$body->rewind();
$body->write(json_encode($signature->getSignedParams()));
$handler = new SignatureBodyHandler();
break;
case 'application/x-www-form-urlencoded':
$body = $request->getBody();
$body->rewind();
$content = $body->getContents();
$params = [];
parse_str($content, $params);
$params['api_key'] = $credentials['api_key'];
$signature = new Signature($params, $credentials['signature_secret'], $credentials['signature_method']);
$params = $signature->getSignedParams();
$body->rewind();
$body->write(http_build_query($params, '', '&'));
$handler = new SignatureBodyFormHandler();
break;
default:
$query = [];
parse_str($request->getUri()->getQuery(), $query);
$query['api_key'] = $credentials['api_key'];
$signature = new Signature($query, $credentials['signature_secret'], $credentials['signature_method']);
$request = $request->withUri(
$request->getUri()->withQuery(http_build_query($signature->getSignedParams()))
);
$handler = new SignatureQueryHandler();
break;
}

return $request;
return $handler($request, $credentials);
}

public static function authRequest(RequestInterface $request, Basic $credentials): RequestInterface
{
switch ($request->getHeaderLine('content-type')) {
case 'application/json':
if (static::requiresBasicAuth($request)) {
$c = $credentials->asArray();
$cx = base64_encode($c['api_key'] . ':' . $c['api_secret']);

$request = $request->withHeader('Authorization', 'Basic ' . $cx);
$handler = new BasicHandler();
} elseif (static::requiresAuthInUrlNotBody($request)) {
$query = [];
parse_str($request->getUri()->getQuery(), $query);
$query = array_merge($query, $credentials->asArray());

$request = $request->withUri($request->getUri()->withQuery(http_build_query($query)));
$handler = new TokenQueryHandler();
} else {
$body = $request->getBody();
$body->rewind();
$content = $body->getContents();
$params = json_decode($content, true);

if (!$params) {
$params = [];
}

$params = array_merge($params, $credentials->asArray());
$body->rewind();
$body->write(json_encode($params));
$handler = new TokenBodyHandler();
}
break;
case 'application/x-www-form-urlencoded':
$body = $request->getBody();
$body->rewind();
$content = $body->getContents();
$params = [];
parse_str($content, $params);
$params = array_merge($params, $credentials->asArray());
$body->rewind();
$body->write(http_build_query($params, '', '&'));
$handler = new TokenBodyFormHandler();
break;
default:
if (static::requiresBasicAuth($request)) {
$c = $credentials->asArray();
$cx = base64_encode($c['api_key'] . ':' . $c['api_secret']);

$request = $request->withHeader('Authorization', 'Basic ' . $cx);
$handler = new BasicHandler();
} else {
$query = [];
parse_str($request->getUri()->getQuery(), $query);
$query = array_merge($query, $credentials->asArray());
$request = $request->withUri($request->getUri()->withQuery(http_build_query($query)));
$handler = new TokenQueryHandler();
}
break;
}

return $request;
return $handler($request, $credentials);
}

/**
Expand Down Expand Up @@ -504,16 +459,14 @@ public function send(RequestInterface $request): ResponseInterface
{
if ($this->credentials instanceof Container) {
if ($this->needsKeypairAuthentication($request)) {
$token = $this->credentials->get(Keypair::class)->generateJwt();

$request = $request->withHeader('Authorization', 'Bearer ' . $token->toString());
$handler = new KeypairHandler();
$request = $handler($request, $this->getCredentials());
} else {
$request = self::authRequest($request, $this->credentials->get(Basic::class));
}
} elseif ($this->credentials instanceof Keypair) {
$token = $this->credentials->generateJwt();

$request = $request->withHeader('Authorization', 'Bearer ' . $token->toString());
$handler = new KeypairHandler();
$request = $handler($request, $this->getCredentials());
} elseif ($this->credentials instanceof SignatureSecret) {
$request = self::signRequest($request, $this->credentials);
} elseif ($this->credentials instanceof Basic) {
Expand Down Expand Up @@ -696,4 +649,9 @@ public function getLogger(): ?LoggerInterface

return $this->logger;
}

public function getCredentials(): CredentialsInterface
{
return $this->credentials;
}
}
63 changes: 55 additions & 8 deletions src/Client/APIResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,28 @@

namespace Vonage\Client;

use function is_null;
use function json_decode;
use function json_encode;
use function http_build_query;
use Laminas\Diactoros\Request;
use Psr\Http\Client\ClientExceptionInterface;
use Vonage\Entity\Filter\EmptyFilter;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Vonage\Entity\Filter\EmptyFilter;
use Vonage\Entity\Filter\FilterInterface;
use Vonage\Entity\IterableAPICollection;

use function http_build_query;
use function is_null;
use function json_decode;
use function json_encode;
use Vonage\Entity\Filter\FilterInterface;
use Psr\Http\Client\ClientExceptionInterface;
use Vonage\Client\Credentials\Handler\HandlerInterface;

class APIResource implements ClientAwareInterface
{
use ClientAwareTrait;

/**
* @var HandlerInterface
*/
protected $authHandler;

/**
* Base URL that we will hit. This can be overridden from the underlying
* client or directly on this class.
Expand Down Expand Up @@ -80,6 +85,16 @@ class APIResource implements ClientAwareInterface
*/
protected $lastResponse;

/**
* Adds authentication to a request
* @todo Use this method when Vonage\Client no longer adds authentication
*/
public function addAuth(RequestInterface $request)
{
$creds = $this->getClient()->getCredentials();
return $this->getAuthHandler()($request, $creds);
}

/**
* @throws ClientExceptionInterface
* @throws Exception\Exception
Expand All @@ -97,6 +112,10 @@ public function create(array $body, string $uri = '', array $headers = []): ?arr
$headers
);

if ($this->getAuthHandler()) {
$request = $this->addAuth($request);
}

$request->getBody()->write(json_encode($body));
$this->lastRequest = $request;

Expand Down Expand Up @@ -142,6 +161,10 @@ public function delete(string $id, array $headers = []): ?array
$headers
);

if ($this->getAuthHandler()) {
$request = $this->addAuth($request);
}

$response = $this->getClient()->send($request);
$status = (int)$response->getStatusCode();

Expand Down Expand Up @@ -186,6 +209,10 @@ public function get($id, array $query = [], array $headers = [])
$headers
);

if ($this->getAuthHandler()) {
$request = $this->addAuth($request);
}

$response = $this->getClient()->send($request);
$status = (int)$response->getStatusCode();

Expand All @@ -202,6 +229,11 @@ public function get($id, array $query = [], array $headers = [])
return json_decode($response->getBody()->getContents(), true);
}

public function getAuthHandler(): ?HandlerInterface
{
return $this->authHandler;
}

public function getBaseUrl(): ?string
{
if (!$this->baseUrl && $this->client) {
Expand Down Expand Up @@ -294,6 +326,13 @@ public function search(?FilterInterface $filter = null, string $uri = ''): Itera
return $collection;
}

public function setAuthHandler($handler): self
{
$this->authHandler = $handler;

return $this;
}

public function setBaseUrl(string $url): self
{
$this->baseUrl = $url;
Expand Down Expand Up @@ -362,6 +401,10 @@ public function submit(array $formData = [], string $uri = '', array $headers =
$headers
);

if ($this->getAuthHandler()) {
$request = $this->addAuth($request);
}

$request->getBody()->write(http_build_query($formData));
$response = $this->getClient()->send($request);
$status = $response->getStatusCode();
Expand Down Expand Up @@ -396,6 +439,10 @@ public function update(string $id, array $body, array $headers = []): ?array
$headers
);

if ($this->getAuthHandler()) {
$request = $this->addAuth($request);
}

$request->getBody()->write(json_encode($body));
$response = $this->getClient()->send($request);

Expand Down
28 changes: 28 additions & 0 deletions src/Client/Credentials/Handler/AbstractHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Vonage\Client\Credentials\Handler;

use Psr\Http\Message\RequestInterface;
use Vonage\Client\Credentials\Container;
use Vonage\Client\Credentials\CredentialsInterface;

abstract class AbstractHandler
{
abstract function __invoke(RequestInterface $request, CredentialsInterface $credentials);

protected function extract(string $class, CredentialsInterface $credentials): CredentialsInterface
{
if ($credentials instanceof $class) {
return $credentials;
}

if ($credentials instanceof Container) {
$creds = $credentials->get($class);
if (!is_null($creds)) {
return $creds;
}
}

throw new \RuntimeException('Requested auth type not found');
}
}
22 changes: 22 additions & 0 deletions src/Client/Credentials/Handler/BasicHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Vonage\Client\Credentials\Handler;

use Psr\Http\Message\RequestInterface;
use Vonage\Client\Credentials\Basic;
use Vonage\Client\Credentials\CredentialsInterface;

class BasicHandler extends AbstractHandler
{
public function __invoke(RequestInterface $request, CredentialsInterface $credentials)
{
$credentials = $this->extract(Basic::class, $credentials);

$c = $credentials->asArray();
$cx = base64_encode($c['api_key'] . ':' . $c['api_secret']);

$request = $request->withHeader('Authorization', 'Basic ' . $cx);

return $request;
}
}
14 changes: 14 additions & 0 deletions src/Client/Credentials/Handler/HandlerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Vonage\Client\Credentials\Handler;

use Psr\Http\Message\RequestInterface;
use Vonage\Client\Credentials\CredentialsInterface;

interface HandlerInterface
{
/**
* Add authentication to a request
*/
function __invoke(RequestInterface $request, CredentialsInterface $credentials): RequestInterface;
}
19 changes: 19 additions & 0 deletions src/Client/Credentials/Handler/KeypairHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Vonage\Client\Credentials\Handler;

use Psr\Http\Message\RequestInterface;
use Vonage\Client\Credentials\CredentialsInterface;
use Vonage\Client\Credentials\Keypair;

class KeypairHandler extends AbstractHandler
{
public function __invoke(RequestInterface $request, CredentialsInterface $credentials)
{
/** @var Keypair $credentials */
$credentials = $this->extract(Keypair::class, $credentials);
$token = $credentials->generateJwt();

return $request->withHeader('Authorization', 'Bearer ' . $token->toString());
}
}
Loading

0 comments on commit 5360821

Please sign in to comment.