Key types and providers for OS2Web built on the Key module.
The OS2Web key module provides two key types, Certificate and OpenID Connect (OIDC). It also comes with two key providers, Azure Key Vault and HashiCorp Vault.
See the Key Developer Guide for details in how to use keys in Drupal.
composer require os2web/os2web_key
drush pm:install os2web_key
Keys are managed on /admin/config/system/keys
.
This key type handles PKCS 12 or Privacy-Enhanced Mail (PEM) certificate with an optional password (passphrase).
Managing the key:
Use in a form:
$form['key'] => [
'#type' => 'key_select',
'#key_filters' => [
'type' => 'os2web_key_certificate',
],
];
The KeyHelper
can be used to get
the actual certificates (parts):
<?php
use Drupal\os2web_key\KeyHelper;
use Drupal\key\KeyRepositoryInterface;
// Use dependency injection for this.
/** @var KeyRepositoryInterface $repository */
$repository = \Drupal::service('key.repository');
/** @var KeyHelper $helper */
$helper = \Drupal::service(KeyHelper::class);
// Use `drush key:list` to list your keys.
$key = $repository->getKey('my_key');
[
// Passwordless certificate.
CertificateKeyType::CERT => $certificate,
CertificateKeyType::PKEY => $privateKey,
] = $helper->getCertificates($key);
Note: The parsed certificate has no password.
Managing the key:
Example use in a form:
$form['key'] => [
'#type' => 'key_select',
'#key_filters' => [
'type' => 'os2web_key_oidc,
],
];
Get the OIDC config:
<?php
use Drupal\key\KeyRepositoryInterface;
use Drupal\os2web_key\Plugin\KeyType\OidcKeyType;
// Use dependency injection for this.
/** @var KeyRepositoryInterface $repository */
$repository = \Drupal::service('key.repository');
$key = $repository->getKey('openid_connect_ad');
[
OidcKeyType::DISCOVERY_URL => $discoveryUrl,
OidcKeyType::CLIENT_ID => $clientId,
OidcKeyType::CLIENT_SECRET => $clientSecret,
] = $helper->getOidcValues($key);
The module comes with two key providers.
Used for fetching certificate from Azure Key vault.
Used to fetch any sort of secret string from HashiCorp vault. Note that this can only provide string values, i.e. no binary files.
To use this provider you must configure the following in settings.local.php
:
$settings['os2web_vault_role_id'] = '{ROLE_ID}';
$settings['os2web_vault_secret_id'] = '{SECRET_ID}';
$settings['os2web_vault_url'] = '{VAULT_URL}';
Our coding are checked by GitHub Actions (cf. .github/workflows/pr.yml). Use the commands below to run the checks locally.
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm composer install
# Fix (some) coding standards issues
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm composer coding-standards-apply
# Check that code adheres to the coding standards
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm composer coding-standards-check
docker run --rm --volume $PWD:/md peterdavehello/markdownlint markdownlint --ignore vendor --ignore LICENSE.md '**/*.md' --fix
docker run --rm --volume $PWD:/md peterdavehello/markdownlint markdownlint --ignore vendor --ignore LICENSE.md '**/*.md'
We use PHPStan for static code analysis.
Running static code analysis on a standalone Drupal module is a bit tricky, so we use a helper script to run the analysis:
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm ./scripts/code-analysis
We use PHPUnit for unit testing.
Testing mostly centers around the conversion and parsing of certificates. For this purpose a bunch of test certificates has been generated. See Test certificates for how this is done.
Running PHPUnit tests in a standalone Drupal module is a bit tricky, so we use a helper script to run the analysis:
docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.3-fpm ./scripts/unit-tests
Certificates have been generated in the follow way
# p12 with password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:test -keyout test.key -out test.crt
openssl pkcs12 -export -out test_with_passphrase.p12 -passin pass:test -passout pass:test -inkey test.key -in test.crt
openssl pkcs12 -in test_with_passphrase.p12 -passin pass:test -noenc
# p12 without password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:'' -keyout test_without_passphrase.key -out test_without_passphrase.crt
openssl pkcs12 -export -out test_without_passphrase.p12 -passin pass:'' -passout pass:'' -inkey test_without_passphrase.key -in test_without_passphrase.crt
openssl pkcs12 -in test_without_passphrase.p12 -passin pass:'' -noenc
# PEM with password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:test -keyout test.key -out test.crt
cat test.crt test.key > test_with_passphrase.pem
openssl x509 -in test_with_passphrase.pem
# PEM without password
openssl req -x509 -newkey rsa:4096 -days 365 -subj "/CN=example.com" -passout pass:'' -keyout test_without_passphrase.key -out test_without_passphrase.crt -noenc
cat test_without_passphrase.crt test_without_passphrase.key > test_without_passphrase.pem
openssl x509 -in test_without_passphrase.pem
Extraction of certificate and private key parts in the following way
# P12 with passphrase
openssl pkcs12 -in test_with_passphrase.p12 -passin pass:test -clcerts -nokeys | sed -ne '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > p12_with_passphrase_cert.txt
openssl pkcs12 -in test_with_passphrase.p12 -passin pass:test -nocerts -nodes | sed -ne '/-----BEGIN PRIVATE KEY-----/,/-----END PRIVATE KEY-----/p' > p12_with_passphrase_pkey.txt
# P12 without passphrase
openssl pkcs12 -in test_without_passphrase.p12 -passin pass: -clcerts -nokeys | sed -ne '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > p12_without_passphrase_cert.txt
openssl pkcs12 -in test_without_passphrase.p12 -passin pass: -nocerts -nodes | sed -ne '/-----BEGIN PRIVATE KEY-----/,/-----END PRIVATE KEY-----/p' > p12_without_passphrase_pkey.txt
# PEM with passphrase
openssl x509 -in test_with_passphrase.pem -passin pass:test -out pem_with_passphrase_cert.txt
openssl pkey -in test_with_passphrase.pem -passin pass:test -out pem_with_passphrase_pkey.txt
# PEM without passphrase
openssl x509 -in test_without_passphrase.pem -passin pass: -out pem_without_passphrase_cert.txt
openssl pkey -in test_without_passphrase.pem -passin pass: -out pem_without_passphrase_pkey.txt