From deaee50dbd335bcb82121955837aae5c19895dd0 Mon Sep 17 00:00:00 2001 From: pookmish Date: Tue, 25 Feb 2025 10:56:48 -0800 Subject: [PATCH] D8CORE-7715: Add constraint plugin and field validation plugin to support sunet validation on fields (#24) * D8CORE-7715: Add constraint plugin and field validation plugin to support sunet validation on fields * Added tests * added service in config form * revert drush refactor --- composer.json | 15 +++- src/Form/RoleMappingSettingsForm.php | 8 ++- src/Form/SamlAuthCreateUserForm.php | 4 +- .../ValidSunetIDFieldValidationRule.php | 71 +++++++++++++++++++ .../Constraint/ValidSunetIDConstraint.php | 22 ++++++ .../ValidSunetIDConstraintValidator.php | 39 ++++++++++ src/Service/WorkgroupApiInterface.php | 2 +- stanford_samlauth.install | 2 +- ...t.php => StanfordSamlAuthCommandsTest.php} | 11 ++- .../ValidSunetIDFieldValidationRuleTest.php | 51 +++++++++++++ .../ValidSunetIDConstraintValidatorTest.php | 39 ++++++++++ 11 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 src/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRule.php create mode 100644 src/Plugin/Validation/Constraint/ValidSunetIDConstraint.php create mode 100644 src/Plugin/Validation/Constraint/ValidSunetIDConstraintValidator.php rename tests/src/Kernel/Drush/Commands/{StanfordSspCommandsTest.php => StanfordSamlAuthCommandsTest.php} (90%) create mode 100644 tests/src/Unit/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRuleTest.php create mode 100644 tests/src/Unit/Plugin/Validation/Constraint/ValidSunetIDConstraintValidatorTest.php diff --git a/composer.json b/composer.json index e7a2883..b1b9941 100644 --- a/composer.json +++ b/composer.json @@ -12,12 +12,25 @@ "require": { "php": ">=8.1", "drupal/autologout": "^1 || ^2", - "drupal/core": "^10 || ^11", + "drupal/core": "^10.3 || ^11", "drupal/r4032login": "^2", "drupal/samlauth": "^3" }, + "require-dev": { + "drupal/field_validation": "^3.0" + }, "prefer-stable": true, "config": { "sort-packages": true + }, + "autoload": { + "psr-4": { + "Drupal\\stanford_samlauth\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Drupal\\Tests\\stanford_samlauth\\": "tests/src" + } } } diff --git a/src/Form/RoleMappingSettingsForm.php b/src/Form/RoleMappingSettingsForm.php index 2b26313..28ac572 100644 --- a/src/Form/RoleMappingSettingsForm.php +++ b/src/Form/RoleMappingSettingsForm.php @@ -4,6 +4,7 @@ use Drupal\Component\Utility\Html; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Form\FormStateInterface; @@ -21,15 +22,16 @@ class RoleMappingSettingsForm extends ConfigFormBase { public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), - $container->get('entity_type.manager') + $container->get('entity_type.manager'), + $container->get('config.typed') ); } /** * {@inheritDoc} */ - public function __construct(ConfigFactoryInterface $config_factory, protected EntityTypeManagerInterface $entityTypeManager) { - parent::__construct($config_factory); + public function __construct(ConfigFactoryInterface $config_factory, protected EntityTypeManagerInterface $entityTypeManager, TypedConfigManagerInterface $typedConfigManager) { + parent::__construct($config_factory, $typedConfigManager); } /** diff --git a/src/Form/SamlAuthCreateUserForm.php b/src/Form/SamlAuthCreateUserForm.php index a324d3a..e4375f6 100644 --- a/src/Form/SamlAuthCreateUserForm.php +++ b/src/Form/SamlAuthCreateUserForm.php @@ -106,7 +106,7 @@ public static function validateSunetId(array &$element, FormStateInterface $form } // Use the workgroup api to check for valid sunet. - /** @var \Drupal\stanford_ssp\Service\StanfordSSPWorkgroupApiInterface $workgroup_api */ + /** @var \Drupal\stanford_samlauth\Service\WorkgroupApiInterface $workgroup_api */ $workgroup_api = \Drupal::service('stanford_samlauth.workgroup_api'); if ($workgroup_api->connectionSuccessful() && !$workgroup_api->isSunetValid($value)) { $form_state->setError($element, t('Invalid SunetID')); @@ -186,7 +186,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $this->authmap->save($new_user, 'samlauth', $form_state->getValue('sunetid')); $this->messenger() ->addStatus($this->t('Successfully created SSO account for %user', ['%user' => $new_user->getAccountName()])); - $this->logger('stanford_ssp') + $this->logger('stanford_samlauth') ->info('Created User %name', ['%name' => $new_user->getAccountName()]); // Was the "notify" checkbox checked? diff --git a/src/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRule.php b/src/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRule.php new file mode 100644 index 0000000..6ad98de --- /dev/null +++ b/src/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRule.php @@ -0,0 +1,71 @@ + 'This is not a valid SunetID.'] + parent::defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() { + return $this->configuration + parent::getConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + + $form['message'] = [ + '#type' => 'textfield', + '#title' => $this->t('Message'), + '#default_value' => $this->configuration['message'], + '#maxlength' => 255, + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::submitConfigurationForm($form, $form_state); + $this->configuration['message'] = $form_state->getValue('message'); + } + +} diff --git a/src/Plugin/Validation/Constraint/ValidSunetIDConstraint.php b/src/Plugin/Validation/Constraint/ValidSunetIDConstraint.php new file mode 100644 index 0000000..9e37dcd --- /dev/null +++ b/src/Plugin/Validation/Constraint/ValidSunetIDConstraint.php @@ -0,0 +1,22 @@ + 'Validation']), +)] +final class ValidSunetIDConstraint extends SymfonyConstraint { + + public string $message = '@sunetid is not a valid SunetID.'; + +} diff --git a/src/Plugin/Validation/Constraint/ValidSunetIDConstraintValidator.php b/src/Plugin/Validation/Constraint/ValidSunetIDConstraintValidator.php new file mode 100644 index 0000000..db06fe0 --- /dev/null +++ b/src/Plugin/Validation/Constraint/ValidSunetIDConstraintValidator.php @@ -0,0 +1,39 @@ +get('stanford_samlauth.workgroup_api')); + } + + /** + * {@inheritdoc} + */ + public function validate(mixed $item, Constraint $constraint): void { + if ($this->workgroupApi->connectionSuccessful() && !$this->workgroupApi->isSunetValid($item)) { + $this->context->addViolation($constraint->message); + } + } + +} diff --git a/src/Service/WorkgroupApiInterface.php b/src/Service/WorkgroupApiInterface.php index 5d988b2..1e11775 100644 --- a/src/Service/WorkgroupApiInterface.php +++ b/src/Service/WorkgroupApiInterface.php @@ -5,7 +5,7 @@ /** * Interface StanfordSSPWorkgroupApiInterface. * - * @package Drupal\stanford_ssp\Service + * @package Drupal\stanford_samlauth\Service */ interface WorkgroupApiInterface { diff --git a/stanford_samlauth.install b/stanford_samlauth.install index 83d5dab..1edbeb5 100644 --- a/stanford_samlauth.install +++ b/stanford_samlauth.install @@ -2,7 +2,7 @@ /** * @file - * Migrate data from stanford_ssp module. + * Migrate data from stanford_samlauth module. */ use Drupal\user\Entity\Role; diff --git a/tests/src/Kernel/Drush/Commands/StanfordSspCommandsTest.php b/tests/src/Kernel/Drush/Commands/StanfordSamlAuthCommandsTest.php similarity index 90% rename from tests/src/Kernel/Drush/Commands/StanfordSspCommandsTest.php rename to tests/src/Kernel/Drush/Commands/StanfordSamlAuthCommandsTest.php index f8ad478..a1d6367 100644 --- a/tests/src/Kernel/Drush/Commands/StanfordSspCommandsTest.php +++ b/tests/src/Kernel/Drush/Commands/StanfordSamlAuthCommandsTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\stanford_samlauth\Kernel\Drush\Commands; +use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\stanford_samlauth\Drush\Commands\StanfordSamlAuthCommands; use Drupal\stanford_samlauth\Service\WorkgroupApiInterface; use Drupal\Tests\stanford_samlauth\Kernel\StanfordSamlAuthTestBase; @@ -13,7 +14,7 @@ * @package Drupal\Tests\stanford_samlauth\Kernel\Commands * @coversDefaultClass \Drupal\stanford_samlauth\Drush\Commands\StanfordSamlAuthCommands */ -class StanfordSspCommandsTest extends StanfordSamlAuthTestBase { +class StanfordSamlAuthCommandsTest extends StanfordSamlAuthTestBase { /** * Drush command service. @@ -40,7 +41,13 @@ public function setup(): void { $config_factory = \Drupal::configFactory(); $entity_type_manager = \Drupal::entityTypeManager(); - $this->commandObject = new StanfordSamlAuthCommands($authmap, $form_builder, $config_factory, $entity_type_manager); + $container = new ContainerBuilder(); + $container->set('externalauth.authmap', $authmap); + $container->set('form_builder', $form_builder); + $container->set('config.factory', $config_factory); + $container->set('entity_type.manager', $entity_type_manager); + + $this->commandObject = StanfordSamlAuthCommands::create($container); $this->commandObject->setLogger(\Drupal::logger('stanford_samlauth')); $this->commandObject->setOutput($this->createMock(OutputInterface::class)); diff --git a/tests/src/Unit/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRuleTest.php b/tests/src/Unit/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRuleTest.php new file mode 100644 index 0000000..0c6393c --- /dev/null +++ b/tests/src/Unit/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRuleTest.php @@ -0,0 +1,51 @@ +createMock(LoggerChannelInterface::class); + + $logger = $this->createMock(LoggerChannelFactoryInterface::class); + $logger->method('get')->willReturn($logger_channel); + + $container = new ContainerBuilder(); + $container->set('logger.factory', $logger); + $container->set('token', $this->createMock(Token::class)); + $container->set('string_translation', $this->getStringTranslationStub()); + \Drupal::setContainer($container); + + $this->validationRule = ValidSunetIDFieldValidationRule::create($container, [], 'foo', []); + } + + public function testFieldValidation() { + $this->assertEquals('ValidSunetID', $this->validationRule->getConstraintName()); + $this->assertTrue($this->validationRule->isPropertyConstraint()); + + $form = []; + $form_state = new FormState(); + $this->assertArrayHasKey('message', $this->validationRule->buildConfigurationForm($form, $form_state)); + + $form_state->setValue('message', 'foobarbaz'); + $this->validationRule->submitConfigurationForm($form, $form_state); + + $this->assertEquals('foobarbaz', $this->validationRule->getConfiguration()['message']); + } + +} diff --git a/tests/src/Unit/Plugin/Validation/Constraint/ValidSunetIDConstraintValidatorTest.php b/tests/src/Unit/Plugin/Validation/Constraint/ValidSunetIDConstraintValidatorTest.php new file mode 100644 index 0000000..a30abed --- /dev/null +++ b/tests/src/Unit/Plugin/Validation/Constraint/ValidSunetIDConstraintValidatorTest.php @@ -0,0 +1,39 @@ +createMock(WorkgroupApiInterface::class); + $workgroup_api->method('connectionSuccessful')->willReturn(TRUE); + $workgroup_api->method('isSunetValid')->willReturn(FALSE); + + $container = new ContainerBuilder(); + $container->set('stanford_samlauth.workgroup_api', $workgroup_api); + $this->plugin = ValidSunetIDConstraintValidator::create($container); + + $context = $this->createMock(ExecutionContextInterface::class); + $this->plugin->initialize($context); + } + + public function testValidation() { + $constraint = new ValidSunetIDConstraint(); + $this->assertNull($this->plugin->validate('foobar', $constraint)); + } + +}