Skip to content

Commit

Permalink
D8CORE-7715: Add constraint plugin and field validation plugin to sup…
Browse files Browse the repository at this point in the history
…port 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
  • Loading branch information
pookmish authored Feb 25, 2025
1 parent 0496539 commit deaee50
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 10 deletions.
15 changes: 14 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
}
8 changes: 5 additions & 3 deletions src/Form/RoleMappingSettingsForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Form/SamlAuthCreateUserForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
Expand Down Expand Up @@ -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?
Expand Down
71 changes: 71 additions & 0 deletions src/Plugin/FieldValidationRule/ValidSunetIDFieldValidationRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace Drupal\stanford_samlauth\Plugin\FieldValidationRule;

use Drupal\Core\Form\FormStateInterface;
use Drupal\field_validation\ConstraintFieldValidationRuleBase;

/**
* Provides functionality for ValidSunetIDValidation.
*
* @FieldValidationRule(
* id = "valid_sunetid_constraint_rule",
* label = @Translation("Valid SunetID"),
* description = @Translation("Validate string is valid sunet.")
* )
*/
class ValidSunetIDFieldValidationRule extends ConstraintFieldValidationRuleBase {

/**
* {@inheritdoc}
*/
public function getConstraintName(): string {
return "ValidSunetID";
}

/**
* {@inheritdoc}
*/
public function isPropertyConstraint(): bool {
return TRUE;
}

/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return ['message' => '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');
}

}
22 changes: 22 additions & 0 deletions src/Plugin/Validation/Constraint/ValidSunetIDConstraint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Drupal\stanford_samlauth\Plugin\Validation\Constraint;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Symfony\Component\Validator\Constraint as SymfonyConstraint;
use Drupal\Core\Validation\Attribute\Constraint;

/**
* Provides a Valid SunetID constraint.
*/
#[Constraint(
id: 'ValidSunetID',
label: new TranslatableMarkup('Valid SunetID', [], ['context' => 'Validation']),
)]
final class ValidSunetIDConstraint extends SymfonyConstraint {

public string $message = '@sunetid is not a valid SunetID.';

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Drupal\stanford_samlauth\Plugin\Validation\Constraint;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\stanford_samlauth\Service\WorkgroupApiInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
* Validates the Valid SunetID constraint.
*/
final class ValidSunetIDConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {

/**
* Constructs the object.
*/
public function __construct(private readonly WorkgroupApiInterface $workgroupApi) {}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): self {
return new self($container->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);
}
}

}
2 changes: 1 addition & 1 deletion src/Service/WorkgroupApiInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/**
* Interface StanfordSSPWorkgroupApiInterface.
*
* @package Drupal\stanford_ssp\Service
* @package Drupal\stanford_samlauth\Service
*/
interface WorkgroupApiInterface {

Expand Down
2 changes: 1 addition & 1 deletion stanford_samlauth.install
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

/**
* @file
* Migrate data from stanford_ssp module.
* Migrate data from stanford_samlauth module.
*/

use Drupal\user\Entity\Role;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -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));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Drupal\Tests\stanford_samlauth\Unit\Plugin\Validation\Constraint;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Form\FormState;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Utility\Token;
use Drupal\stanford_samlauth\Plugin\FieldValidationRule\ValidSunetIDFieldValidationRule;
use Drupal\Tests\UnitTestCase;

/**
* @coversDefaultClass \Drupal\stanford_samlauth\Plugin\FieldValidationRule\ValidSunetIDFieldValidationRule
*/
class ValidSunetIDFieldValidationRuleTest extends UnitTestCase {

protected $validationRule;

protected function setUp(): void {
parent::setUp();

$logger_channel = $this->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']);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Drupal\Tests\stanford_samlauth\Unit\Plugin\Validation\Constraint;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\stanford_samlauth\Plugin\Validation\Constraint\ValidSunetIDConstraint;
use Drupal\stanford_samlauth\Plugin\Validation\Constraint\ValidSunetIDConstraintValidator;
use Drupal\stanford_samlauth\Service\WorkgroupApiInterface;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

/**
* @coversDefaultClass \Drupal\stanford_samlauth\Plugin\Validation\Constraint\ValidSunetIDConstraintValidator
*/
class ValidSunetIDConstraintValidatorTest extends UnitTestCase {

protected $plugin;

protected function setUp(): void {
parent::setUp();

$workgroup_api = $this->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));
}

}

0 comments on commit deaee50

Please sign in to comment.