Skip to content

Commit

Permalink
Feature/strm 1259 (#4)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: authentication has changed
  • Loading branch information
bobvandenhoogen authored Jul 12, 2022
1 parent e876e91 commit 19212c0
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 65 deletions.
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
"require": {
"php": ">=7.2",
"guzzlehttp/guzzle": "^6.3 || ^7.3",
"wikimedia/avro": "^1.9"
"wikimedia/avro": "^1.9",
"ext-curl": "*",
"curl/curl": "^2.3",
"ext-json": "*"
}
}
20 changes: 10 additions & 10 deletions src/AuthProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,31 @@ class AuthProvider
{
protected const EXPIRATION_SLACK_SECONDS = 60;

/** @var string $idToken */
protected $idToken;
/** @var string $accessToken */
protected $accessToken;

/** @var string $refreshToken */
protected $refreshToken;

/** @var int $expiresAt */
protected $expiresAt;
public $expiresAt;

public function __construct(string $json)
{
$authData = json_decode($json);

if (!isset($authData->idToken, $authData->refreshToken, $authData->expiresAt)) {
if (!isset($authData->access_token, $authData->refresh_token)) {
throw new AuthenticationException('Invalid response from authenticate/refresh request');
}

$this->idToken = (string)$authData->idToken;
$this->refreshToken = (string)$authData->refreshToken;
$this->expiresAt = (int)$authData->expiresAt;
$this->accessToken = (string)$authData->access_token;
$this->refreshToken = (string)$authData->refresh_token;

$this->expiresAt = (int)$authData->expires_in + time();
}

public function getIdToken(): string
public function getAccessToken(): string
{
return $this->idToken;
return $this->accessToken;
}

public function getRefreshToken(): string
Expand Down
42 changes: 19 additions & 23 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Exception\RequestException;
use PhpParser\Node\Scalar\String_;
use StrmPrivacy\Driver\Exceptions\AuthenticationException;
use StrmPrivacy\Driver\Exceptions\RefreshException;
use Curl\Curl;

class Client
{
Expand All @@ -15,9 +17,6 @@ class Client
/** @var \GuzzleHttp\Client $httpClient */
protected $httpClient;

/** @var string $billingId */
protected $billingId;

/** @var string $clientId */
protected $clientId;

Expand All @@ -28,16 +27,14 @@ class Client
protected $config;

public function __construct(
string $billingId,
string $clientId,
string $clientSecret,
array $customConfig = [],
array $httpConfig = []
) {
$this->billingId = $billingId;
array $customConfig = [],
array $httpConfig = []
)
{
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;

$this->config = new Config($customConfig);
$this->httpClient = new HttpClient($httpConfig);
}
Expand All @@ -49,19 +46,15 @@ public function authenticate(): void
'POST',
$this->config->getAuthUri(),
[
'json' => [
'billingId' => $this->billingId,
'clientId' => $this->clientId,
'clientSecret' => $this->clientSecret,
],
'headers' => ['content-type' => 'application/x-www-form-urlencoded'],
'body' => sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", $this->clientId, $this->clientSecret)
]
);
} catch (RequestException $e) {
throw new AuthenticationException(
sprintf(
'Error authenticating to %s for billingId %s and clientId %s, status code: %d, message: %s',
'Error authenticating to %s for clientId %s, status code: %d, message: %s',
$this->config->getAuthUri(),
$this->billingId,
$this->clientId,
$e->getCode(),
$e->getMessage()
Expand All @@ -82,19 +75,18 @@ public function refresh(): void
try {
$response = $this->httpClient->request(
'POST',
$this->config->getRefreshUri(),
$this->config->getAuthUri(),
[
'json' => [
'refreshToken' => $this->authProvider->getRefreshToken(),
],
'headers' => ['content-type' => 'application/x-www-form-urlencoded'],
'body' => sprintf("grant_type=refresh_token&client_id=%s&client_secret=%s&refresh_token=%s",
$this->clientId, $this->clientSecret, $this->authProvider->getRefreshToken())
]
);
} catch (RequestException $e) {
throw new RefreshException(
sprintf(
'Error refreshing auth token to %s for billingId %s and clientId %s, status code: %d, message: %s',
'Error refreshing auth token to %s for clientId %s, status code: %d, message: %s',
$this->config->getRefreshUri(),
$this->billingId,
$this->clientId,
$e->getCode(),
$e->getMessage()
Expand Down Expand Up @@ -123,7 +115,11 @@ public function authIsExpired(): bool
if (!isset($this->authProvider)) {
return true;
}

return $this->authProvider->isExpired();
}

public function getAccessToken(): string
{
return $this->authProvider->getAccessToken();
}
}
20 changes: 10 additions & 10 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ class Config
/** @var string $gatewayEndpoint */
protected $gatewayEndpoint = '/event';

/** @var string $stsProtocol */
protected $stsProtocol = 'https';
/** @var string $authProtocol */
protected $authProtocol = 'https';

/** @var string $stsHost */
protected $stsHost = 'sts.strmprivacy.io';
/** @var string $authHost */
public $authHost = 'accounts.strmprivacy.io';

/** @var string $stsAuthEndpoint */
protected $stsAuthEndpoint = '/auth';
/** @var string $authAuthEndpoint */
protected $authAuthEndpoint = '/auth/realms/streams/protocol/openid-connect/token';

/** @var string $stsRefreshEndpoint */
protected $stsRefreshEndpoint = '/refresh';
/** @var string $authRefreshEndpoint */
protected $authRefreshEndpoint = '/auth/realms/streams/protocol/openid-connect/token';

/** @var int $stsRefreshInterval */
protected $stsRefreshInterval = 3300;
Expand All @@ -44,11 +44,11 @@ public function getGatewayUri(): string

public function getAuthUri(): string
{
return sprintf('%s://%s/%s', $this->stsProtocol, $this->stsHost, ltrim($this->stsAuthEndpoint, '/'));
return sprintf('%s://%s/%s', $this->authProtocol, $this->authHost, ltrim($this->authAuthEndpoint, '/'));
}

public function getRefreshUri(): string
{
return sprintf('%s://%s/%s', $this->stsProtocol, $this->stsHost, ltrim($this->stsRefreshEndpoint, '/'));
return sprintf('%s://%s/%s', $this->authProtocol, $this->authHost, ltrim($this->authRefreshEndpoint, '/'));
}
}
5 changes: 2 additions & 3 deletions src/Sender.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function send(Event $event, string $serializationType): void
$this->config->getGatewayUri(),
[
'headers' => [
'Authorization' => 'Bearer ' . $this->authProvider->getIdToken(),
'Authorization' => 'Bearer ' . $this->authProvider->getAccessToken(),
'Strm-Serialization-Type' => $serializer->getContentType(),
'Strm-Schema-Ref' => $event->getStrmSchemaRef(),
'Content-type' => $serializer->getContentType(),
Expand All @@ -35,9 +35,8 @@ public function send(Event $event, string $serializationType): void
} catch (RequestException $e) {
throw new SendingException(
sprintf(
'Error sending event to %s for billingId %s and clientId %s, status code: %d, message: %s',
'Error sending event to %s for clientId %s, status code: %d, message: %s',
$this->config->getGatewayUri(),
$this->billingId,
$this->clientId,
$e->getCode(),
$e->getMessage()
Expand Down
51 changes: 37 additions & 14 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,86 @@
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;
use StrmPrivacy\Driver\Client;
use StrmPrivacy\Driver\Config;

class ClientTest extends TestCase
{
public function testClientCanBeInstantiated(): void
{
$this->assertInstanceOf(
Client::class,
new Client('billingId', 'clientId', 'clientSecret')
new Client('clientId', 'clientSecret')
);
}

public function testClientCanAuthenticate(): void
{
$validResponse = $this->getMockResponse();
static::markTestSkipped('When enabling this test, enter client credentials');

$config = new Config(['authHost' => 'accounts.dev.strmprivacy.io']);
$client = new Client('clientId', 'clientSecret', (array)$config);
$client->authenticate();
$this->assertNotTrue($client->getAccessToken() == '', 'Access Token is empty');
}

public function testClientCanRefresh(): void
{
static::markTestSkipped('When enabling this test, enter client credentials');

$config = new Config(['authHost' => 'accounts.dev.strmprivacy.io']);
$client = new Client('clientId', 'clientSecret', (array)$config);
$client->authenticate();
$oldToken = $client->getAccessToken();
$client->refresh();
$this->assertTrue($client->getAccessToken() != '', 'Access Token is empty');
$this->assertTrue($client->getAccessToken() != $oldToken, 'Access Token has not changed');
}


public function testClientCanAuthenticateWithExpirationTime(): void
{
$validResponse = $this->getMockResponse(61);
$mockHandler = new MockHandler([$validResponse]);
$handlerStack = HandlerStack::create($mockHandler);
$client = new Client('billingId', 'clientId', 'clientSecret', [], ['handler' => $handlerStack]);
$client = new Client('clientId', 'clientSecret', [], ['handler' => $handlerStack]);

$client->authenticate();
$this->assertTrue(!$client->authIsExpired());
}

public function testClientShouldBeExpiredOnTime(): void
{
$almostExpiredResponse = $this->getMockResponse(time() + 59);
$almostExpiredResponse = $this->getMockResponse(59);
$mockHandler = new MockHandler([$almostExpiredResponse]);
$handlerStack = HandlerStack::create($mockHandler);
$client = new Client('billingId', 'clientId', 'clientSecret', [], ['handler' => $handlerStack]);
$client = new Client('clientId', 'clientSecret', [], ['handler' => $handlerStack]);

$client->authenticate();
$this->assertTrue($client->authIsExpired());
}

public function testExpiredAuthShouldRefresh(): void
{
$expiredResponse = $this->getMockResponse(time() - 100);
$validResponse = $this->getMockResponse();
$expiredResponse = $this->getMockResponse();
$validResponse = $this->getMockResponse(100);
$mockHandler = new MockHandler([$expiredResponse, $validResponse]);
$handlerStack = HandlerStack::create($mockHandler);
$client = new Client('billingId', 'clientId', 'clientSecret', [], ['handler' => $handlerStack]);
$client = new Client('clientId', 'clientSecret', [], ['handler' => $handlerStack]);

$client->authenticate();
$client->refresh();
$this->assertTrue(!$client->authIsExpired());
}

protected function getMockResponse(int $expiresAt = null): Response
protected function getMockResponse(int $expiresIn = null): Response
{
$expiresAt = is_null($expiresAt) ? time() + 3600 : $expiresAt;

return new Response(
200,
[],
json_encode([
'idToken' => 'dummy idToken',
'refreshToken' => 'dummy refreshToken',
'expiresAt' => $expiresAt,
'access_token' => 'dummy idToken',
'refresh_token' => 'dummy refreshToken',
'expires_in' => $expiresIn,
])
);
}
Expand Down
8 changes: 4 additions & 4 deletions tests/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public function testCustomGatewayUriIsCorrect(): void
public function testCustomAuthUriIsCorrect(): void
{
$config = new Config([
'stsHost' => 'customhost',
'stsAuthEndpoint' => 'customendpoint',
'authHost' => 'customhost',
'authAuthEndpoint' => 'customendpoint',
]);

$this->assertEquals(
Expand All @@ -41,8 +41,8 @@ public function testCustomAuthUriIsCorrect(): void
public function testCustomRefreshUriIsCorrect(): void
{
$config = new Config([
'stsHost' => 'customhost',
'stsRefreshEndpoint' => 'customendpoint',
'authHost' => 'customhost',
'authRefreshEndpoint' => 'customendpoint',
]);

$this->assertEquals(
Expand Down

0 comments on commit 19212c0

Please sign in to comment.