Skip to content

Commit

Permalink
add executable handler
Browse files Browse the repository at this point in the history
  • Loading branch information
bshaffer committed Feb 1, 2024
1 parent e3f8ec3 commit a8768b6
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 29 deletions.
45 changes: 18 additions & 27 deletions src/CredentialSource/ExecutableSource.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/*
* Copyright 2023 Google Inc.
* Copyright 2024 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@

namespace Google\Auth\CredentialSource;

use Google\Auth\ExecutableHandler\ExecutableHandler;
use Google\Auth\ExternalAccountCredentialSourceInterface;
use RuntimeException;

Expand All @@ -33,38 +34,39 @@ class ExecutableSource implements ExternalAccountCredentialSourceInterface
/**
* The default executable timeout when none is provided, in milliseconds.
*/
private const DEFAULT_EXECUTABLE_TIMEOUT_MILLIS = 30 * 1000;
private const GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES = 'GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES';

private string $executable;
private int $timeoutMillis;
private string $command;

Check failure on line 39 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Property Google\Auth\CredentialSource\ExecutableSource::$command is unused.
private ExecutableHandler $executableHandler;
private ?string $outputFile;
private array $environmentVariables;

Check failure on line 42 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Property Google\Auth\CredentialSource\ExecutableSource::$environmentVariables is unused.

Check failure on line 42 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Property Google\Auth\CredentialSource\ExecutableSource::$environmentVariables type has no value type specified in iterable type array.

/**
* @param string $executable The string executable to run to get the subject token.
* @param string $timeoutMillis
* @param int $timeoutMillis
* @param string $outputFile
* @param array<string, string> $environmentVariables
*/
public function __construct(

Check failure on line 50 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Constructor of class Google\Auth\CredentialSource\ExecutableSource has an unused parameter $command.

Check failure on line 50 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

PHPDoc tag @param references unknown parameter: $environmentVariables

Check failure on line 50 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

PHPDoc tag @param references unknown parameter: $executable

Check failure on line 50 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

PHPDoc tag @param references unknown parameter: $timeoutMillis
string $executable,
?int $timeoutMillis,
string $command,
?string $outputFile,
array $environmentVariables = [],
ExecutableHandler $executableHandler = null,
) {
$this->executable = $executable;

Check failure on line 55 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Access to an undefined property Google\Auth\CredentialSource\ExecutableSource::$executable.

Check failure on line 55 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Undefined variable: $executable
$this->timeoutMillis = $timeoutMillis ?: self::DEFAULT_EXECUTABLE_TIMEOUT_MILLIS;
$this->outputFile = $outputFile;
$this->environmentVariables = $environmentVariables;
$this->executableHandler = $executableHandler ?: new ExecutableHandler();
}

/**
* @param callable $httpHandler unused.
* @param callable $executableHandler A function which returns the output of the command with
* the following function signature:
* function (string $command, array $envVars, int &$returnVar): string
* function (string $command, array $envVars, int &$returnVar = null): string
*/
public function fetchSubjectToken(callable $httpHandler = null, callable $executableHandler = null): string
{
public function fetchSubjectToken(
callable $httpHandler = null,
callable $executableHandler = null
): string {
// Check if the executable is allowed to run.
if (getenv(self::GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES) !== '1') {
throw new RuntimeException(
Expand All @@ -75,27 +77,16 @@ public function fetchSubjectToken(callable $httpHandler = null, callable $execut
}

if ($this->outputFile && file_exists($this->outputFile)) {
$cachedToken = json_decode(file_get_contents($this->outputFile), true);
$outputFileContents = file_get_contents($this->outputFile) ?: '';
$cachedToken = json_decode($outputFileContents, true);
if (time() < ($cachedToken['expiration_time'] ?? 0)) {
return $cachedToken;
}
}

$executableHandler ??= function (string $command, array $envVars, &$returnVar): string {
$envVarString = implode(' ', array_map(
fn ($key, $value) => "$key=$value",
array_keys($envVars),
$envVars
));
$command = escapeshellcmd($envVarString . ' ' . $command);
exec($command, $output, $returnVar);

return implode("\n", $output);
};

// Run the executable.
$returnVar = null;
$cmdOutput = $executableHandler($this->executable, $this->environmentVariables, $returnVar);
$cmdOutput = ($this->executableHandler)($this->executable, $returnVar);

Check failure on line 89 in src/CredentialSource/ExecutableSource.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Access to an undefined property Google\Auth\CredentialSource\ExecutableSource::$executable.

// If the exit code is not 0, throw an exception with the output as the error details
if ($returnVar !== 0) {
Expand Down
50 changes: 50 additions & 0 deletions src/ExecutableHandler/ExecutableHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Google\Auth\ExecutableHandler;

class ExecutableHandler
{
private const DEFAULT_EXECUTABLE_TIMEOUT_MILLIS = 30 * 1000;

private int $timeout;
private array $envVars;

public function __construct(
int $timeout = self::DEFAULT_EXECUTABLE_TIMEOUT_MILLIS,
array $envVars = []
) {
$this->timeout = $timeout;
$this->envVars = $envVars;
}

/**
* @param string $command
* @param int|null $returnVar
*/
public function __invoke(string $command, ?int &$returnVar): string
{
$envVarString = implode(' ', array_map(
fn ($key, $value) => "$key=$value",
array_keys($this->envVars),
$this->envVars
));
$command = escapeshellcmd($envVarString . ' ' . $command);
exec($command, $output, $returnVar);

return implode("\n", $output);
}
}
4 changes: 2 additions & 2 deletions tests/CredentialSource/ExecutableSourceTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/*
* Copyright 2023 Google Inc.
* Copyright 2024 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -93,7 +93,7 @@ public function testFetchSubjectTokenWithError(string $returnCode, string $outpu
function (string $command, array $envVars, &$returnCode) use ($expectedCommand) {
$this->assertEquals($expectedCommand, $command);
$this->assertEquals([], $envVars);
$returnCode = 0;
$returnCode = 1;
return '{"access_token": "abc"}';
}
);
Expand Down

0 comments on commit a8768b6

Please sign in to comment.