diff --git a/composer.json b/composer.json index 0080381774855b085e46df496eebe50beb778cf1..ac022d80da954158d29ca69c2e46b12ea0e1186e 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "source": "https://git.drupalcode.org/project/login_gov" }, "require": { + "drupal/key_asymmetric": "^1.1", "drupal/openid_connect": "^2.0", "firebase/php-jwt": "^6.3" } diff --git a/config/schema/login_gov.schema.yml b/config/schema/login_gov.schema.yml index cc6e2cdf5859b9bcf091badde07f578679066208..cdf883a56f7e54e31a3775ea018be87533643cf5 100644 --- a/config/schema/login_gov.schema.yml +++ b/config/schema/login_gov.schema.yml @@ -30,7 +30,7 @@ openid_connect.client.plugin.login_gov: force_reauth: type: boolean label: 'Force reauthorization' - private_key: - type: text - label: 'Private key in PEM format' + key_private_key: + type: string + label: 'Key ID from Key Module' diff --git a/login_gov.info.yml b/login_gov.info.yml index 6e236b7db236600a180acacf58839a866353f3e8..c8bc6f8a5409523f55378a363d11c72c6509a300 100644 --- a/login_gov.info.yml +++ b/login_gov.info.yml @@ -5,3 +5,4 @@ core_version_requirement: ^8.8 || ^9 package: 'User authentication' dependencies: - openid_connect:openid_connect (>=2.0) + - key_asymmetric:key_asymmetric diff --git a/login_gov.install b/login_gov.install new file mode 100644 index 0000000000000000000000000000000000000000..78b55a9ecc662b6488151db5e9b5d8f6206f7fd1 --- /dev/null +++ b/login_gov.install @@ -0,0 +1,45 @@ +<?php + +/** + * @file + * Contains update functions for the login_gov module. + */ + +use Drupal\key\Entity\Key; + +/** + * Implements hook_update_N(). + * + * Convert old private keys to Key entities. + */ +function login_gov_update_9001(&$sandbox) { + $clients = \Drupal::entityTypeManager()->getStorage('openid_connect_client')->loadByProperties(['plugin' => 'login_gov']); + foreach ($clients as $id => $client) { + $settings = $client->get('settings'); + // Skip entries without a private key. + if (empty($settings['private_key'])) { + continue; + } + // Choose a new unique key id. + $key_id = $id . '_private_key'; + $index = 1; + while (Key::load($key_id)) { + $key_id = $id . '_private_key_' . $index++; + } + // Generate a new Private key object. + Key::create([ + 'id' => $key_id, + 'label' => $client->label() . ' private key', + 'description' => 'Automatically converted from Login.gov config.', + 'key_type' => 'asymmetric_private', + 'key_type_settings' => key_asymmetric_get_key_properties($settings['private_key']), + 'key_provider_settings' => ['key_value' => $settings['private_key']], + ])->save(); + // Update the client to use the new key. + $client->set('settings', [ + 'key_private_key' => $key_id, + 'private_key' => NULL, + ]); + $client->save(); + } +} diff --git a/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php b/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php index 9733f0e7dcdc2f8e56489d22c78c6babbce2cc7d..0d2b0d0b20e9465954a41b55d7936ddc8edf7225 100644 --- a/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php +++ b/src/Plugin/OpenIDConnectClient/OpenIDConnectLoginGovClient.php @@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\GeneratedUrl; use Drupal\Core\Link; use Drupal\Core\Url; +use Drupal\key\Entity\Key; use Drupal\openid_connect\Plugin\OpenIDConnectClientBase; use Firebase\JWT\JWK; use Firebase\JWT\JWT; @@ -94,7 +95,7 @@ class OpenIDConnectLoginGovClient extends OpenIDConnectClientBase { 'count' => 1, 'units' => 'y', ], - 'private_key' => '', + 'key_private_key' => NULL, ]; } @@ -178,11 +179,12 @@ class OpenIDConnectLoginGovClient extends OpenIDConnectClientBase { '#description' => $this->t('Require the user to login again to Login.gov. <em>Requires login.gov administrator approval.</em>'), ]; - $form['private_key'] = [ - '#title' => $this->t('Private key in PEM format'), - '#type' => 'textarea', - '#default_value' => $this->configuration['private_key'], - '#description' => $this->t('Need to put this someplace more secure.'), + $form['key_private_key'] = [ + '#title' => $this->t('Key from Key'), + '#type' => 'key_select', + '#default_value' => $this->configuration['key_private_key'], + '#key_filters' => ['type' => ['asymmetric_private']], + '#description' => ' ' . $this->t('A Private key managed by the @key_module.', ['@key_module' => Link::fromTextAndUrl($this->t('Key module'), Url::fromRoute('entity.key.collection'))->toString()]), ]; // Add some custom CSS. @@ -261,7 +263,10 @@ class OpenIDConnectLoginGovClient extends OpenIDConnectClientBase { * The private key in PEM format. */ protected function getPrivateKey(): ?string { - return $this->configuration['private_key']; + $key = Key::load($this->configuration['key_private_key']); + // Return the key's KeyValue, or fall back to the old configuration if there + // is no Key. + return $key ? $key->getKeyValue() : $this->configuration['private_key']; } /**