Skip to content
This repository has been archived by the owner on Feb 7, 2024. It is now read-only.

Commit

Permalink
Fix signature validation (#38)
Browse files Browse the repository at this point in the history
* Add failing test

* Fix signature validation

* Fix tests to generate correct signatures

*  StyleCI fix

* Ignore route params when validating the signature

* Fix tests to add route params next to signature

* StyleCI fixes
  • Loading branch information
stayallive authored and mpociot committed Jan 2, 2019
1 parent c1f6ffa commit 83dec0b
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 137 deletions.
20 changes: 12 additions & 8 deletions src/HttpApi/Controllers/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace BeyondCode\LaravelWebSockets\HttpApi\Controllers;

use Exception;
use Pusher\Pusher;
use Illuminate\Http\Request;
use GuzzleHttp\Psr7\Response;
use Ratchet\ConnectionInterface;
Expand Down Expand Up @@ -84,18 +85,21 @@ public function ensureValidAppId(string $appId)

protected function ensureValidSignature(Request $request)
{
$signature =
"{$request->getMethod()}\n/{$request->path()}\n".
"auth_key={$request->get('auth_key')}".
"&auth_timestamp={$request->get('auth_timestamp')}".
"&auth_version={$request->get('auth_version')}";
/*
* The `auth_signature` & `body_md5` parameters are not included when calculating the `auth_signature` value.
*
* The `appId`, `appKey` & `channelName` parameters are actually route paramaters and are never supplied by the client.
*/
$params = array_except($request->query(), ['auth_signature', 'body_md5', 'appId', 'appKey', 'channelName']);

if ($request->getContent() !== '') {
$bodyMd5 = md5($request->getContent());

$signature .= "&body_md5={$bodyMd5}";
$params['body_md5'] = md5($request->getContent());
}

ksort($params);

$signature = "{$request->getMethod()}\n/{$request->path()}\n".Pusher::array_implode('=', '&', $params);

$authSignature = hash_hmac('sha256', $signature, App::findById($request->get('appId'))->secret);

if ($authSignature !== $request->get('auth_signature')) {
Expand Down
61 changes: 22 additions & 39 deletions tests/HttpApi/FetchChannelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace BeyondCode\LaravelWebSockets\Tests\HttpApi;

use Pusher\Pusher;
use GuzzleHttp\Psr7\Request;
use Illuminate\Http\JsonResponse;
use BeyondCode\LaravelWebSockets\Tests\TestCase;
Expand All @@ -19,21 +20,15 @@ public function invalid_signatures_can_not_access_the_api()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';
$requestPath = '/apps/1234/channel/my-channel';
$routeParams = [
'appId' => '1234',
'channelName' => 'my-channel',
];

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));
$queryString = Pusher::build_auth_query_string('TestKey', 'InvalidSecret', 'GET', $requestPath);

$signature =
"GET\n/apps/1234/channels\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";

$auth_signature = hash_hmac('sha256', $signature, 'InvalidSecret');

$request = new Request('GET', "/apps/1234/channel/my-channel?appId=1234&channelName=my-channel&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchChannelController::class);

Expand All @@ -48,21 +43,15 @@ public function it_returns_the_channel_information()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));
$requestPath = '/apps/1234/channel/my-channel';
$routeParams = [
'appId' => '1234',
'channelName' => 'my-channel',
];

$signature =
"GET\n/apps/1234/channel/my-channel\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";
$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath);

$auth_signature = hash_hmac('sha256', $signature, 'TestSecret');

$request = new Request('GET', "/apps/1234/channel/my-channel?appId=1234&channelName=my-channel&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchChannelController::class);

Expand All @@ -87,21 +76,15 @@ public function it_returns_404_for_invalid_channels()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));

$signature =
"GET\n/apps/1234/channel/my-channel\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";
$requestPath = '/apps/1234/channel/invalid-channel';
$routeParams = [
'appId' => '1234',
'channelName' => 'invalid-channel',
];

$auth_signature = hash_hmac('sha256', $signature, 'TestSecret');
$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath);

$request = new Request('GET', "/apps/1234/channel/my-channel?appId=1234&channelName=invalid-channel&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchChannelController::class);

Expand Down
96 changes: 58 additions & 38 deletions tests/HttpApi/FetchChannelsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace BeyondCode\LaravelWebSockets\Tests\HttpApi;

use Pusher\Pusher;
use GuzzleHttp\Psr7\Request;
use Illuminate\Http\JsonResponse;
use BeyondCode\LaravelWebSockets\Tests\TestCase;
Expand All @@ -19,21 +20,14 @@ public function invalid_signatures_can_not_access_the_api()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';
$requestPath = '/apps/1234/channels';
$routeParams = [
'appId' => '1234',
];

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));
$queryString = Pusher::build_auth_query_string('TestKey', 'InvalidSecret', 'GET', $requestPath);

$signature =
"GET\n/apps/1234/channels\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";

$auth_signature = hash_hmac('sha256', $signature, 'InvalidSecret');

$request = new Request('GET', "/apps/1234/channels?appId=1234&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchChannelsController::class);

Expand All @@ -49,21 +43,14 @@ public function it_returns_the_channel_information()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));

$signature =
"GET\n/apps/1234/channels\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";
$requestPath = '/apps/1234/channels';
$routeParams = [
'appId' => '1234',
];

$auth_signature = hash_hmac('sha256', $signature, 'TestSecret');
$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath);

$request = new Request('GET', "/apps/1234/channels?appId=1234&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchChannelsController::class);

Expand All @@ -82,25 +69,58 @@ public function it_returns_the_channel_information()
}

/** @test */
public function it_returns_empty_object_for_no_channels_found()
public function it_returns_the_channel_information_for_prefix()
{
$this->joinPresenceChannel('presence-global.1');
$this->joinPresenceChannel('presence-global.1');
$this->joinPresenceChannel('presence-global.2');
$this->joinPresenceChannel('presence-notglobal.2');

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';
$requestPath = '/apps/1234/channels';
$routeParams = [
'appId' => '1234',
];

$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath, [
'filter_by_prefix' => 'presence-global',
]);

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchChannelsController::class);

$controller->onOpen($connection, $request);

/** @var JsonResponse $response */
$response = array_pop($connection->sentRawData);

$this->assertSame([
'channels' => [
'presence-global.1' => [
'user_count' => 2,
],
'presence-global.2' => [
'user_count' => 1,
],
],
], json_decode($response->getContent(), true));
}

/** @test */
public function it_returns_empty_object_for_no_channels_found()
{
$connection = new Connection();

$signature =
"GET\n/apps/1234/channels\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";
$requestPath = '/apps/1234/channels';
$routeParams = [
'appId' => '1234',
];

$auth_signature = hash_hmac('sha256', $signature, 'TestSecret');
$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath);

$request = new Request('GET', "/apps/1234/channels?appId=1234&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchChannelsController::class);

Expand Down
81 changes: 29 additions & 52 deletions tests/HttpApi/FetchUsersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace BeyondCode\LaravelWebSockets\Tests\HttpApi;

use Pusher\Pusher;
use GuzzleHttp\Psr7\Request;
use BeyondCode\LaravelWebSockets\Tests\TestCase;
use BeyondCode\LaravelWebSockets\Tests\Mocks\Connection;
Expand All @@ -18,21 +19,15 @@ public function invalid_signatures_can_not_access_the_api()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';
$requestPath = '/apps/1234/channel/my-channel';
$routeParams = [
'appId' => '1234',
'channelName' => 'my-channel',
];

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));
$queryString = Pusher::build_auth_query_string('TestKey', 'InvalidSecret', 'GET', $requestPath);

$signature =
"GET\n/apps/1234/channels\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";

$auth_signature = hash_hmac('sha256', $signature, 'InvalidSecret');

$request = new Request('GET', "/apps/1234/channel/my-channel?appId=1234&channelName=my-channel&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchUsersController::class);

Expand All @@ -49,21 +44,15 @@ public function it_only_returns_data_for_presence_channels()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));

$signature =
"GET\n/apps/1234/channel/my-channel/users\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";
$requestPath = '/apps/1234/channel/my-channel/users';
$routeParams = [
'appId' => '1234',
'channelName' => 'my-channel',
];

$auth_signature = hash_hmac('sha256', $signature, 'TestSecret');
$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath);

$request = new Request('GET', "/apps/1234/channel/my-channel/users?appId=1234&channelName=my-channel&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchUsersController::class);

Expand All @@ -80,21 +69,15 @@ public function it_returns_404_for_invalid_channels()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';
$requestPath = '/apps/1234/channel/invalid-channel/users';
$routeParams = [
'appId' => '1234',
'channelName' => 'invalid-channel',
];

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));
$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath);

$signature =
"GET\n/apps/1234/channel/my-channel/users\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";

$auth_signature = hash_hmac('sha256', $signature, 'TestSecret');

$request = new Request('GET', "/apps/1234/channel/my-channel/users?appId=1234&channelName=invalid-channel&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchUsersController::class);

Expand All @@ -108,21 +91,15 @@ public function it_returns_connected_user_information()

$connection = new Connection();

$auth_key = 'TestKey';
$auth_timestamp = time();
$auth_version = '1.0';

$queryParameters = http_build_query(compact('auth_key', 'auth_timestamp', 'auth_version'));

$signature =
"GET\n/apps/1234/channel/my-channel/users\n".
"auth_key={$auth_key}".
"&auth_timestamp={$auth_timestamp}".
"&auth_version={$auth_version}";
$requestPath = '/apps/1234/channel/presence-channel/users';
$routeParams = [
'appId' => '1234',
'channelName' => 'presence-channel',
];

$auth_signature = hash_hmac('sha256', $signature, 'TestSecret');
$queryString = Pusher::build_auth_query_string('TestKey', 'TestSecret', 'GET', $requestPath);

$request = new Request('GET', "/apps/1234/channel/my-channel/users?appId=1234&channelName=presence-channel&auth_signature={$auth_signature}&{$queryParameters}");
$request = new Request('GET', "{$requestPath}?{$queryString}&".http_build_query($routeParams));

$controller = app(FetchUsersController::class);

Expand Down

0 comments on commit 83dec0b

Please sign in to comment.