diff --git a/README.md b/README.md index dfa57b3..23b072e 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Please check the [Laravel support policy](https://laravel.com/docs/master/releas 'handler' => env('STACKKIT_CLOUD_TASKS_HANDLER', ''), 'queue' => env('STACKKIT_CLOUD_TASKS_QUEUE', 'default'), 'service_account_email' => env('STACKKIT_CLOUD_TASKS_SERVICE_EMAIL', ''), + 'signed_audience' => env('STACKKIT_CLOUD_TASKS_SIGNED_AUDIENCE', true), // Optional: The deadline in seconds for requests sent to the worker. If the worker // does not respond by this deadline then the request is cancelled and the attempt // is marked as a DEADLINE_EXCEEDED failure. @@ -70,6 +71,7 @@ Please check the table below on what the values mean and what their value should | `STACKKIT_CLOUD_TASKS_QUEUE` | The default queue a job will be added to |`emails` | `STACKKIT_CLOUD_TASKS_SERVICE_EMAIL` | The email address of the service account. Important, it should have the correct roles. See the section below which roles. |`my-service-account@appspot.gserviceaccount.com` | `STACKKIT_CLOUD_TASKS_HANDLER` (optional) | The URL that Cloud Tasks will call to process a job. This should be the URL to your Laravel app. By default we will use the URL that dispatched the job. |`https://.com` +| `STACKKIT_CLOUD_TASKS_SIGNED_AUDIENCE` (optional) | True or false depending if you want extra security by signing the audience of your tasks. May misbehave in certain Cloud Run setups. Defaults to true. | `true`
diff --git a/src/CloudTasksQueue.php b/src/CloudTasksQueue.php index dcb9e51..d552461 100644 --- a/src/CloudTasksQueue.php +++ b/src/CloudTasksQueue.php @@ -167,14 +167,16 @@ protected function pushToCloudTasks($queue, $payload, $delay = 0) $token = new OidcToken; $token->setServiceAccountEmail($this->config['service_account_email']); - $token->setAudience(hash_hmac('sha256', $this->getHandler(), config('app.key'))); + if ($audience = $this->getAudience()) { + $token->setAudience($audience); + } $httpRequest->setOidcToken($token); if ($availableAt > time()) { $task->setScheduleTime(new Timestamp(['seconds' => $availableAt])); } - $createdTask = CloudTasksApi::createTask($queueName, $task); + CloudTasksApi::createTask($queueName, $task); event((new TaskCreated)->queue($queue)->task($task)); @@ -192,7 +194,7 @@ private function withUuid(array $payload): array private function taskName(string $queueName, array $payload): string { - $displayName = str_replace("\\", '-', $payload['displayName']); + $displayName = $this->sanitizeTaskName($payload['displayName']); return CloudTasksClient::taskName( $this->config['project'], @@ -202,6 +204,17 @@ private function taskName(string $queueName, array $payload): string ); } + private function sanitizeTaskName(string $taskName) + { + // Remove all characters that are not -, letters, numbers, or whitespace + $sanitizedName = preg_replace('![^-\pL\pN\s]+!u', '-', $taskName); + + // Replace all separator characters and whitespace by a - + $sanitizedName = preg_replace('![-\s]+!u', '-', $sanitizedName); + + return trim($sanitizedName, '-'); + } + private function withAttempts(array $payload): array { if (!isset($payload['internal']['attempts'])) { @@ -268,4 +281,9 @@ public function getHandler(): string { return Config::getHandler($this->config['handler']); } + + public function getAudience(): ?string + { + return Config::getAudience($this->config); + } } diff --git a/src/Config.php b/src/Config.php index c1183eb..9ffd34b 100644 --- a/src/Config.php +++ b/src/Config.php @@ -82,4 +82,15 @@ public static function getHandler($handler): string ); } } + + /** + * @param array $config + * @return string|null The audience as an hash or null if not needed + */ + public static function getAudience(array $config): ?string + { + return $config['signed_audience'] ?? true + ? hash_hmac('sha256', self::getHandler($config['handler']), config('app.key')) + : null; + } } diff --git a/src/OpenIdVerificatorConcrete.php b/src/OpenIdVerificatorConcrete.php index fa46175..a3c1c4a 100644 --- a/src/OpenIdVerificatorConcrete.php +++ b/src/OpenIdVerificatorConcrete.php @@ -18,7 +18,7 @@ public function verify(?string $token, array $config): void (new AccessToken())->verify( $token, [ - 'audience' => hash_hmac('sha256', app('queue')->getHandler(), config('app.key')), + 'audience' => Config::getAudience($config), 'throwException' => true, ] ); diff --git a/src/OpenIdVerificatorFake.php b/src/OpenIdVerificatorFake.php index 077f917..79cedb6 100644 --- a/src/OpenIdVerificatorFake.php +++ b/src/OpenIdVerificatorFake.php @@ -17,7 +17,7 @@ public function verify(?string $token, array $config): void (new AccessToken())->verify( $token, [ - 'audience' => hash_hmac('sha256', app('queue')->getHandler(), config('app.key')), + 'audience' => Config::getAudience($config), 'throwException' => true, 'certsLocation' => __DIR__ . '/../tests/Support/self-signed-public-key-as-jwk.json', ] diff --git a/tests/TestCase.php b/tests/TestCase.php index 587e802..bbdd1e1 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -103,6 +103,7 @@ protected function getEnvironmentSetUp($app) 'location' => 'europe-west6', 'handler' => env('CLOUD_TASKS_HANDLER', 'https://docker.for.mac.localhost:8080'), 'service_account_email' => 'info@stackkit.io', + 'signed_audience' => true, ]); $app['config']->set('queue.failed.driver', 'database-uuids'); $app['config']->set('queue.failed.database', 'testbench');