diff --git a/etc/config/.env.example b/etc/config/.env.example index cc82ae447..f091688f5 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -32,7 +32,6 @@ BROWSER=chrome #*** Uncomment and set vault base url and access token if you want to use vault to manage _CREDS secrets ***# #CREDENTIAL_VAULT_BASE_URL= -#CREDENTIAL_VAULT_TOKEN= #*** Uncomment these properties to set up a dev environment with symlinked projects ***# #TESTS_BP= diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 016360752..75707b941 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -59,13 +59,9 @@ private function __construct() // Initialize vault storage $csBaseUrl = getenv('CREDENTIAL_VAULT_BASE_URL'); - $csToken = getenv('CREDENTIAL_VAULT_TOKEN'); - if ($csBaseUrl !== false && $csToken !== false) { + if ($csBaseUrl !== false) { try { - $this->credStorage[self::ARRAY_KEY_FOR_VAULT] = new VaultStorage( - rtrim($csBaseUrl, '/'), - $csToken - ); + $this->credStorage[self::ARRAY_KEY_FOR_VAULT] = new VaultStorage(rtrim($csBaseUrl, '/')); } catch (TestFrameworkException $e) { } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php index de80b83e3..785db036b 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php @@ -21,6 +21,25 @@ class VaultStorage extends BaseStorage const BASE_PATH = '/dx_magento_qe'; const KV_DATA = 'data'; + /** + * Default vault token file + */ + const TOKEN_FILE = '.vault-token'; + /** + * Default vault config file + */ + const CONFIG_FILE = '.vault'; + /** + * Environment variable name for vault config path + */ + const CONFIG_PATH_ENV_VAR = 'VAULT_CONFIG_PATH'; + + /** + * Regex to grab token helper script + */ + const TOKEN_HELPER_REGEX_GROUP_NAME = 'GROUP_NAME'; + const TOKEN_HELPER_REGEX = "~\s*token_helper\s*=(?<" . self::TOKEN_HELPER_REGEX_GROUP_NAME . ">.+)$~"; + /** * Vault client * @@ -33,23 +52,22 @@ class VaultStorage extends BaseStorage * * @var string */ - private $token; + private $token = null; /** * CredentialVault constructor * * @param string $baseUrl - * @param string $token * @throws TestFrameworkException */ - public function __construct($baseUrl, $token) + public function __construct($baseUrl) { parent::__construct(); if (null === $this->client) { // Creating the client using Guzzle6 Transport and passing a custom url $this->client = new Client(new Guzzle6Transport(['base_uri' => $baseUrl])); } - $this->token = $token; + $this->readVaultTokenFromFileSystem(); if (!$this->authenticated()) { throw new TestFrameworkException("Credential vault is not used: cannot authenticate"); } @@ -120,4 +138,87 @@ private function authenticated() } return false; } + + /** + * Read vault token from file system + * + * @return void + * @throws TestFrameworkException + */ + private function readVaultTokenFromFileSystem() + { + // Find user home directory + $homeDir = getenv('HOME'); + if ($homeDir === false) { + throw new TestFrameworkException( + "HOME environment variable is not set. It's required when using vault." + ); + } + $homeDir = realpath($homeDir) . DIRECTORY_SEPARATOR; + + // Read .vault-token file if it is found in default location + $vaultTokenFile = $homeDir . self::TOKEN_FILE; + if (file_exists($vaultTokenFile)) { + $token = file_get_contents($vaultTokenFile); + if ($token !== false) { + $this->token = $token; + return; + } + } + + // Otherwise search vault config file for custom token helper script + $vaultConfigPath = getenv(self::CONFIG_PATH_ENV_VAR); + if ($vaultConfigPath === false) { + $vaultConfigFile = $homeDir . self::CONFIG_FILE; + } else { + $vaultConfigFile = realpath($vaultConfigPath) . DIRECTORY_SEPARATOR . self::CONFIG_FILE; + } + // Get custom token helper script file from .vault config file + if (file_exists($vaultConfigFile)) { + $cmd = $this->getTokenHelperScript(file($vaultConfigFile, FILE_IGNORE_NEW_LINES)); + if (!empty($cmd)) { + $this->token = $this->execVaultTokenHelper($cmd . ' get'); + return; + } + } + throw new TestFrameworkException( + 'Unable to read .vault-token file. Please authenticate to vault through vault CLI first.' + ); + } + + /** + * Get vault token helper script by parsing lines in vault config file + * + * @param array $lines + * @return string + */ + private function getTokenHelperScript($lines) + { + $tokenHelper = ''; + foreach ($lines as $line) { + preg_match(self::TOKEN_HELPER_REGEX, $line, $matches); + if (isset($matches[self::TOKEN_HELPER_REGEX_GROUP_NAME])) { + $tokenHelper = trim(trim(trim($matches[self::TOKEN_HELPER_REGEX_GROUP_NAME]), '"')); + } + } + return $tokenHelper; + } + + /** + * Execute vault token helper script and return the token it contains + * + * @param string $cmd + * @return string + * @throws TestFrameworkException + */ + private function execVaultTokenHelper($cmd) + { + exec($cmd, $out, $status); + if ($status === 0 && isset($out[0]) && !empty($out[0])) { + return $out[0]; + } + throw new TestFrameworkException( + 'Error running custom vault token helper script. Please make sure vault CLI works in your environment.' + ); + } }