diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dcae0a..34a662d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +* [PR-3](https://github.com/OS2web/os2web_key/pull/3) + Added Azure Key Vault certificate provider * [PR-2](https://github.com/OS2web/os2web_key/pull/2) Updated documentation * [PR-1](https://github.com/OS2web/os2web_key/pull/1) diff --git a/composer.json b/composer.json index cb11b37..09a1519 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "php": "^8.1", "ext-openssl": "*", "drupal/core": "^9 || ^10", - "drupal/key": "^1.17" + "drupal/key": "^1.17", + "itk-dev/serviceplatformen": "dev-feature/guzzle6-adapter" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", diff --git a/src/Plugin/KeyProvider/AzureKeyVaultKeyProvider.php b/src/Plugin/KeyProvider/AzureKeyVaultKeyProvider.php new file mode 100644 index 0000000..ef9e464 --- /dev/null +++ b/src/Plugin/KeyProvider/AzureKeyVaultKeyProvider.php @@ -0,0 +1,204 @@ +get('logger.channel.os2web_key'); + + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $logger + ); + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration(): array { + return [ + self::TENANT_ID => '', + self::APPLICATION_ID => '', + self::CLIENT_SECRET => '', + self::NAME => '', + self::SECRET => '', + self::VERSION => '', + ]; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { + $configuration = $this->getConfiguration(); + + $settings = [ + self::TENANT_ID => ['title' => $this->t('Tenant id')], + self::APPLICATION_ID => ['title' => $this->t('Application id')], + self::CLIENT_SECRET => ['title' => $this->t('Client secret')], + self::NAME => ['title' => $this->t('Name')], + self::SECRET => ['title' => $this->t('Secret')], + self::VERSION => ['title' => $this->t('Version')], + ]; + + foreach ($settings as $key => $info) { + $form[$key] = [ + '#type' => 'textfield', + '#title' => $info['title'], + '#default_value' => $configuration[$key] ?? NULL, + '#required' => TRUE, + ]; + } + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state): void { + try { + $this->getCertificate(); + } + catch (\Throwable $throwable) { + $form_state->setError($form, $this->t('Error getting certificate: %message', ['%message' => $throwable->getMessage()])); + } + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void { + $this->setConfiguration($form_state->getValues()); + } + + /** + * {@inheritdoc} + */ + public function getKeyValue(KeyInterface $key): ?string { + try { + return $this->getCertificate(); + } + catch (\Throwable $throwable) { + } + + return NULL; + } + + /** + * Get certificate. + * + * @return string + * The certificate. + * + * @throws \ItkDev\AzureKeyVault\Exception\TokenException + * @throws \ItkDev\Serviceplatformen\Certificate\Exception\AzureKeyVaultCertificateLocatorException + */ + private function getCertificate(): string { + try { + $httpClient = new GuzzleAdapter(new Client()); + $requestFactory = new RequestFactory(); + + $vaultToken = new VaultToken($httpClient, $requestFactory); + + $options = $this->getConfiguration(); + + $token = $vaultToken->getToken( + $options[self::TENANT_ID], + $options[self::APPLICATION_ID], + $options[self::CLIENT_SECRET], + ); + + $vault = new VaultSecret( + $httpClient, + $requestFactory, + $options[self::NAME], + $token->getAccessToken() + ); + + $locator = new AzureKeyVaultCertificateLocator( + $vault, + $options[self::SECRET], + $options[self::VERSION], + ); + + return $locator->getCertificate(); + } + catch (\Exception $exception) { + // Log the exception and re-throw it. + $this->logger->error('Error getting certificate: @message', [ + '@message' => $exception->getMessage(), + 'throwable' => $exception, + ]); + throw $exception; + } + } + +}