diff --git a/composer.json b/composer.json index d7ad8e5963984d10a73a4734516816f4076bfe96..e75fa765964c5f3fe07588cf84ff6360a5679fa5 100644 --- a/composer.json +++ b/composer.json @@ -171,7 +171,7 @@ "drupal/token": "1.7", "drupal/twig_tweak": "2.6", "drupal/twitter_block": "3.0-alpha0", - "drupal/userprotect": "1.0", + "drupal/userprotect": "1.1", "drupal/video_embed_field": "2.4", "drupal/view_unpublished": "1.0-rc1", "drupal/views_accordion": "1.1", diff --git a/composer.lock b/composer.lock index b4fa092ecd8a0ed198805514a09f715f17a97ca3..2b05c44f242f32b70ae07286b99c4860b379d094 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b9be0e811209c12590dacc555ae9d6b5", + "content-hash": "7330c5a1f65d3610e46131939e58c151", "packages": [ { "name": "alchemy/zippy", @@ -7824,29 +7824,29 @@ }, { "name": "drupal/userprotect", - "version": "1.0.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/userprotect.git", - "reference": "8.x-1.0" + "reference": "8.x-1.1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.0.zip", - "reference": "8.x-1.0", - "shasum": "addff8ed82e8cdb77073e2a8b023a7e9809f856b" + "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.1.zip", + "reference": "8.x-1.1", + "shasum": "485e240317a7fc1c0523b082f333c983ea3ca639" }, "require": { - "drupal/core": "*" + "drupal/core": "^8 || ^9" + }, + "require-dev": { + "drupal/role_delegation": "^1.0" }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - }, "drupal": { - "version": "8.x-1.0", - "datestamp": "1477741139", + "version": "8.x-1.1", + "datestamp": "1578341583", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 1665601de5f3e1f49199f7cde891a7e6eba01cfa..46983c31e787604d098edec4cbe89bc3fe14e7f7 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -8066,30 +8066,30 @@ }, { "name": "drupal/userprotect", - "version": "1.0.0", - "version_normalized": "1.0.0.0", + "version": "1.1.0", + "version_normalized": "1.1.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/userprotect.git", - "reference": "8.x-1.0" + "reference": "8.x-1.1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.0.zip", - "reference": "8.x-1.0", - "shasum": "addff8ed82e8cdb77073e2a8b023a7e9809f856b" + "url": "https://ftp.drupal.org/files/projects/userprotect-8.x-1.1.zip", + "reference": "8.x-1.1", + "shasum": "485e240317a7fc1c0523b082f333c983ea3ca639" }, "require": { - "drupal/core": "*" + "drupal/core": "^8 || ^9" + }, + "require-dev": { + "drupal/role_delegation": "^1.0" }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - }, "drupal": { - "version": "8.x-1.0", - "datestamp": "1477741139", + "version": "8.x-1.1", + "datestamp": "1578341583", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/web/modules/userprotect/README.txt b/web/modules/userprotect/README.txt index 541d6f1da3d86cbf28f868c040d9434185b924de..08624242eba609c7018fd36ebad72a5d85da924c 100644 --- a/web/modules/userprotect/README.txt +++ b/web/modules/userprotect/README.txt @@ -1,6 +1,88 @@ -User protect +User Protect +============ + +CONTENTS OF THIS FILE +--------------------- + + * Introduction + * Requirements + * Installation + * Configuration + * Maintainers + + +INTRODUCTION +------------ + +The User Protect module allows fine-grained access control of user +administrators, by providing various editing protection for users. The +protections can be specific to a user, or applied to all users in a role. + +The following protections are supported: + + * Username + * E-mail address + * Password + * Status + * Roles + * Edit operation (user/X/edit) + * Delete operation (user/X/cancel) + + * For a full description of the module visit: + https://www.drupal.org/project/userprotect + + * To submit bug reports and feature suggestions, or to track changes visit: + https://www.drupal.org/project/issues/userprotect + + +REQUIREMENTS +------------ + +This module requires no modules outside of Drupal core. + + +INSTALLATION ------------ -by MegaChriz -Previously (Drupal 7 and before) written by Chad Philips. -This module provides various editing protection for users. + * Install the User Protect module as you would normally install a contributed + Drupal module. Visit https://www.drupal.org/node/1897420 for further + information. + + +CONFIGURATION +------------- + + 1. Navigate to Administration > Extend and enable the module. + 2. Navigate to Administration > Configuration > People > User protect for + configurations. + +There are two types of protection rules: + + * User based protection rules: + This user will be protected for all users except: "User 1" (admin), the + protected user itself, and users with the permissions to "Bypass all user + protections". + * Role based protection rules: + This role will be protected for all users except: "User 1" (admin), and users + with the permissions to "Bypass all user protections". + +A protection rule prevents any user to perform the selected editing operations +(such as changing password or changing mail address) on the specified user. +There are two exceptions in which a configured protection rule does not apply: + + * The logged in user has permission to bypass the protection rule. + + * The specified user is the current logged in user. + Protection rules don't count for the user itself. Instead, there are + permissions available to prevent an user from editing its own account, + username, e-mail address, or password. + +Protected fields will be disabled or hidden on the form at user/X/edit. The edit +and delete operations are protected by controlling entity access for the +operations 'update' and 'delete'. + + +MAINTAINERS +----------- + + * Youri van Koppen (MegaChriz) - https://www.drupal.org/user/654114 diff --git a/web/modules/userprotect/composer.json b/web/modules/userprotect/composer.json index 8a6b1edfbc89dbf251c8532fc257f5ec7cbf4b74..834032db32c2ab54173ac2f555987e63f5133d27 100644 --- a/web/modules/userprotect/composer.json +++ b/web/modules/userprotect/composer.json @@ -8,5 +8,8 @@ "support": { "issues": "https://www.drupal.org/project/issues/userprotect", "source": "http://cgit.drupalcode.org/userprotect" + }, + "require-dev": { + "drupal/role_delegation": "^1.0" } } diff --git a/web/modules/userprotect/src/Access/UserProtectRoleAccessCheck.php b/web/modules/userprotect/src/Access/UserProtectRoleAccessCheck.php new file mode 100644 index 0000000000000000000000000000000000000000..a127d27cdc306f1d52b6f81681abf528260ad0ef --- /dev/null +++ b/web/modules/userprotect/src/Access/UserProtectRoleAccessCheck.php @@ -0,0 +1,35 @@ +<?php + +namespace Drupal\userprotect\Access; + +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Routing\Access\AccessInterface; +use Drupal\Core\Session\AccountInterface; +use Drupal\user\UserInterface; + +/** + * Class UserProtectRoleAccessCheck. + * + * @package Drupal\userprotect\Access + */ +class UserProtectRoleAccessCheck implements AccessInterface { + + /** + * Custom access check for the /user/%/roles. + * + * This check will only occur when role_delegation is enabled. + * + * @param \Drupal\Core\Session\AccountInterface $account + * Run access checks for this account. + * @param \Drupal\user\UserInterface $user + * The user we are editing. + * + * @return \Drupal\Core\Access\AccessResultInterface + * The access result. + */ + public function access(AccountInterface $account, UserInterface $user) { + $access_result = $user->access('user_roles', $account) ? AccessResult::allowed() : AccessResult::forbidden(); + return $access_result->cachePerUser()->addCacheableDependency($user); + } + +} diff --git a/web/modules/userprotect/src/Annotation/UserProtection.php b/web/modules/userprotect/src/Annotation/UserProtection.php index 37e53237cbad2f462a0cce2f5de38dc5f05f8740..325b5e25c264c385306d26f4bc2c5db039b496bf 100644 --- a/web/modules/userprotect/src/Annotation/UserProtection.php +++ b/web/modules/userprotect/src/Annotation/UserProtection.php @@ -21,32 +21,33 @@ class UserProtection extends Plugin { /** * The human-readable name of the protection. * - * @ingroup plugin_translatable - * * @var \Drupal\Core\Annotation\Translation + * + * @ingroup plugin_translatable */ public $label; /** * A brief description of the protection. * - * @ingroup plugin_translatable + * @var \Drupal\Core\Annotation\Translation * - * @var \Drupal\Core\Annotation\Translation (optional) + * @ingroup plugin_translatable */ public $description = ''; /** * A default weight used for presentation in the user interface only. * - * @var int (optional) + * @var int */ public $weight = 0; /** * Whether this protection is enabled or disabled by default. * - * @var bool (optional) + * @var bool */ public $status = FALSE; + } diff --git a/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php b/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php index b637a158de7e2d90f8c22d32e31e99b7d71a983d..487918a56007fcd827386c78de55a8136c9d4fe8 100644 --- a/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php +++ b/web/modules/userprotect/src/Controller/ProtectionRuleListBuilder.php @@ -3,7 +3,7 @@ namespace Drupal\userprotect\Controller; use Drupal\userprotect\Entity\ProtectionRuleInterface; -use Drupal\Component\Utility\SafeMarkup; +use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Config\Entity\ConfigEntityListBuilder; use Drupal\Core\Entity\EntityInterface; @@ -11,6 +11,7 @@ * Provides a listing of protection rules. */ class ProtectionRuleListBuilder extends ConfigEntityListBuilder { + /** * {@inheritdoc} */ @@ -26,13 +27,13 @@ public function buildHeader() { * {@inheritdoc} */ public function buildRow(EntityInterface $entity) { - $row['label'] = $this->getLabel($entity); + $row['label'] = $entity->label(); $protected_entity = $entity->getProtectedEntity(); if ($protected_entity instanceof EntityInterface) { $row['entity'] = $protected_entity->label(); } else { - $row['entity'] = SafeMarkup::format('%missing', array('%missing' => $this->t('Missing'))); + $row['entity'] = new FormattableMarkup('%missing', ['%missing' => $this->t('Missing')]); } $row['type'] = $entity->getProtectedEntityTypeId(); $row['protection'] = $this->getProtections($entity); @@ -58,4 +59,5 @@ public function getProtections(ProtectionRuleInterface $entity) { return $item->label(); }, $enabled_protections)); } + } diff --git a/web/modules/userprotect/src/Entity/ProtectionRule.php b/web/modules/userprotect/src/Entity/ProtectionRule.php index daf756ecbb2ecef9b610e39bf7f07536a56ef5d7..0fcbaa34f3803a69b6e84cc509e31bc8661bc300 100644 --- a/web/modules/userprotect/src/Entity/ProtectionRule.php +++ b/web/modules/userprotect/src/Entity/ProtectionRule.php @@ -9,10 +9,8 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Session\AccountInterface; use Drupal\user\UserInterface; -use Drupal\userprotect\Entity\ProtectionRuleInterface; use Drupal\userprotect\UserProtect; use Drupal\userprotect\Plugin\UserProtection\UserProtectionPluginCollection; -use Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface; /** * Defines the Protection rule entity. @@ -36,6 +34,14 @@ * "label" = "label", * "uuid" = "uuid" * }, + * config_export = { + * "name", + * "label", + * "uuid", + * "protectedEntityTypeId", + * "protectedEntityId", + * "protections" + * }, * links = { * "edit-form" = "/admin/config/people/userprotect/manage/{userprotect_rule}", * "delete-form" = "/admin/config/people/userprotect/manage/{userprotect_rule}/delete" @@ -86,7 +92,7 @@ class ProtectionRule extends ConfigEntityBase implements ProtectionRuleInterface * * @var array */ - protected $protections = array(); + protected $protections = []; /** * Holds the collection of protections that are used by this protection rule. @@ -107,7 +113,7 @@ class ProtectionRule extends ConfigEntityBase implements ProtectionRuleInterface * * @var array */ - protected $bypassRoles = array(); + protected $bypassRoles = []; /** * Overrides Drupal\Core\Entity\Entity::id(). @@ -129,7 +135,7 @@ public function getProtectedEntityTypeId() { public function setProtectedEntityTypeId($entity_type_id) { // Check if given entity type exists. An InvalidArgumentException will be // thrown if not. - \Drupal::entityManager()->getDefinition($entity_type_id, TRUE); + \Drupal::entityTypeManager()->getDefinition($entity_type_id, TRUE); $this->protectedEntityTypeId = $entity_type_id; return $this; @@ -140,7 +146,7 @@ public function setProtectedEntityTypeId($entity_type_id) { */ public function getProtectedEntity() { if ($this->getProtectedEntityId()) { - return entity_load($this->getProtectedEntityTypeId(), $this->getProtectedEntityId()); + return \Drupal::entityTypeManager()->getStorage($this->getProtectedEntityTypeId())->load($this->getProtectedEntityId()); } } @@ -180,7 +186,7 @@ public function getProtections() { * {@inheritdoc} */ public function getPluginCollections() { - return array('protections' => $this->getProtections()); + return ['protections' => $this->getProtections()]; } /** @@ -199,7 +205,7 @@ public function setPluginConfig($instance_id, array $configuration) { * {@inheritdoc} */ public function enableProtection($instance_id) { - $this->setPluginConfig($instance_id, array('status' => TRUE)); + $this->setPluginConfig($instance_id, ['status' => TRUE]); return $this; } @@ -207,7 +213,7 @@ public function enableProtection($instance_id) { * {@inheritdoc} */ public function disableProtection($instance_id) { - $this->setPluginConfig($instance_id, array('status' => FALSE)); + $this->setPluginConfig($instance_id, ['status' => FALSE]); return $this; } @@ -216,11 +222,11 @@ public function disableProtection($instance_id) { */ public function toArray() { $properties = parent::toArray(); - $names = array( + $names = [ 'protections', 'protectedEntityTypeId', 'protectedEntityId', - ); + ]; foreach ($names as $name) { $properties[$name] = $this->get($name); } @@ -298,7 +304,7 @@ public function postSave(EntityStorageInterface $storage_controller, $update = T if ($roles && $permission) { foreach (user_roles() as $rid => $name) { $enabled = in_array($rid, $roles, TRUE); - user_role_change_permissions($rid, array($permission => $enabled)); + user_role_change_permissions($rid, [$permission => $enabled]); } } } @@ -364,4 +370,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account) // In all other cases, the operation is not protected by this rule. return FALSE; } + } diff --git a/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php b/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php index c73c305268c1fa30153946efb6c1f5af9cc47e38..90ab7da2bb8e2436d3c794d335a6d4b47c0b8c7f 100644 --- a/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php +++ b/web/modules/userprotect/src/Entity/ProtectionRuleInterface.php @@ -10,6 +10,7 @@ * Provides an interface defining a userprotect_rule entity. */ interface ProtectionRuleInterface extends ConfigEntityInterface { + /** * Gets the protected entity type id. * @@ -180,4 +181,5 @@ public function hasProtection($protection); * FALSE if the operation is not protected by this rule. */ public function isProtected(UserInterface $user, $op, AccountInterface $account); + } diff --git a/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php b/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php index 3381e1e2158e45c93fd94fe78d2445078f7aaa47..44a6fb3777363f68e6b5bbe48d714964a695b63b 100644 --- a/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php +++ b/web/modules/userprotect/src/Form/ProtectionRuleAddForm.php @@ -9,11 +9,16 @@ * Provides a form controller for adding a protection rule. */ class ProtectionRuleAddForm extends ProtectionRuleFormBase { + /** * Overrides EntityFormController::buildForm(). * * Sets protected entity type on protection rule entity. * + * @param array $form + * Nested array of form elements that comprise the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. * @param string $protected_entity_type_id * (optional) The entity type to protect. * Defaults to 'user_role'. @@ -39,7 +44,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $protecte */ public function save(array $form, FormStateInterface $form_state) { parent::save($form, $form_state); - drupal_set_message($this->t('Added protection rule %name.', array('%name' => $this->entity->label()))); + $this->messenger->addMessage($this->t('Added protection rule %name.', ['%name' => $this->entity->label()])); } } diff --git a/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php b/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php index 715360989d9b40769f834c610e6247b5af4bece9..4da60d6ca2bf8bf8b8d79b4807200c0c1335f59c 100644 --- a/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php +++ b/web/modules/userprotect/src/Form/ProtectionRuleDeleteForm.php @@ -15,7 +15,7 @@ class ProtectionRuleDeleteForm extends EntityConfirmFormBase { * {@inheritdoc} */ public function getQuestion() { - return $this->t('Are you sure you want to delete %name?', array('%name' => $this->entity->label())); + return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]); } /** @@ -37,7 +37,7 @@ public function getConfirmText() { */ public function submitForm(array &$form, FormStateInterface $form_state) { $this->entity->delete(); - drupal_set_message($this->t('Protection rule %label has been deleted.', array('%label' => $this->entity->label()))); + $this->messenger()->addMessage($this->t('Protection rule %label has been deleted.', ['%label' => $this->entity->label()])); $form_state->setRedirectUrl($this->getCancelUrl()); } diff --git a/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php b/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php index 8d682e0ab342cc290cd4baed0122f1c1f3f9d1bb..a4ebef263dcc9fb9184d34820c7ea76e3dc95f68 100644 --- a/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php +++ b/web/modules/userprotect/src/Form/ProtectionRuleEditForm.php @@ -13,7 +13,7 @@ class ProtectionRuleEditForm extends ProtectionRuleFormBase { * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { - $form['#title'] = $this->t('Edit protection rule %name', array('%name' => $this->entity->label())); + $form['#title'] = $this->t('Edit protection rule %name', ['%name' => $this->entity->label()]); $form = parent::form($form, $form_state); return $form; } @@ -23,7 +23,7 @@ public function form(array $form, FormStateInterface $form_state) { */ public function save(array $form, FormStateInterface $form_state) { parent::save($form, $form_state); - drupal_set_message(t('Updated protection rule %name.', array('%name' => $this->entity->label()))); + $this->messenger->addMessage($this->t('Updated protection rule %name.', ['%name' => $this->entity->label()])); return $this->entity; } diff --git a/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php b/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php index 15b480abb074996a775bb53db4325322422c4bd7..48498bd4cd0ad2d6cb9a71358528db7de55cf8d7 100644 --- a/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php +++ b/web/modules/userprotect/src/Form/ProtectionRuleFormBase.php @@ -2,10 +2,11 @@ namespace Drupal\userprotect\Form; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Entity\EntityForm; +use Drupal\user\UserStorageInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\MessengerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -20,14 +21,38 @@ abstract class ProtectionRuleFormBase extends EntityForm { */ protected $protectionRuleStorage; + /** + * The user storage. + * + * @var \Drupal\user\UserStorageInterface + */ + protected $userStorage; + + /** + * The messenger service. + * + * @var \Drupal\Core\Messenger\MessengerInterface + */ + protected $messenger; + /** * Constructs a base class for protection rule add and edit forms. * * @param \Drupal\Core\Entity\EntityStorageInterface $protection_rule_storage * The protection rule entity storage controller. + * @param \Drupal\user\UserStorageInterface $user_storage + * The user storage. + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * The messenger service. */ - public function __construct(EntityStorageInterface $protection_rule_storage) { + public function __construct( + EntityStorageInterface $protection_rule_storage, + UserStorageInterface $user_storage, + MessengerInterface $messenger + ) { $this->protectionRuleStorage = $protection_rule_storage; + $this->userStorage = $user_storage; + $this->messenger = $messenger; } /** @@ -35,7 +60,9 @@ public function __construct(EntityStorageInterface $protection_rule_storage) { */ public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager')->getStorage('userprotect_rule') + $container->get('entity_type.manager')->getStorage('userprotect_rule'), + $container->get('entity_type.manager')->getStorage('user'), + $container->get('messenger') ); } @@ -43,15 +70,15 @@ public static function create(ContainerInterface $container) { * Construct message for bypass permission. */ protected function getBypassMessage($permission, $permission_label) { - $message = $this->t('Users with the permission "%permission".', array('%permission' => $permission_label)); + $message = $this->t('Users with the permission "%permission".', ['%permission' => $permission_label]); $roles = user_role_names(FALSE, $permission); if (count($roles)) { - $message .= '<br /><div class="description">' . $this->t('Currently the following roles have this permission: %roles.', array('%roles' => implode(', ', $roles))) . '</div>'; + $message .= '<br /><div class="description">' . $this->t('Currently the following roles have this permission: %roles.', ['%roles' => implode(', ', $roles)]) . '</div>'; } else { $message .= '<br /><div class="description">' . $this->t('Currently no roles have this permission.') . '</div>'; } - return array('#markup' => $message); + return ['#markup' => $message]; } /** @@ -61,31 +88,31 @@ public function form(array $form, FormStateInterface $form_state) { $protected_entity_type = $this->entity->getProtectedEntityTypeId(); // Help text. - $items = array(); + $items = []; // User 1. - $account = entity_load('user', 1); + $account = $this->userStorage->load(1); if (!empty($account)) { - $items[] = array( - '#markup' => $this->t('User @id (@name)', array( + $items[] = [ + '#markup' => $this->t('User @id (@name)', [ '@id' => $account->id(), '@name' => $account->label(), - )), - ); + ]), + ]; } // User in question (if protected entity type is "user"). if ($protected_entity_type == 'user') { $account = $this->entity->getProtectedEntity(); if (!empty($account)) { - $items[] = array( - '#markup' => $this->t('The protected user itself (@name)', array( + $items[] = [ + '#markup' => $this->t('The protected user itself (@name)', [ '@name' => $account->label(), - )), - ); + ]), + ]; } else { - $items[] = array( + $items[] = [ '#markup' => $this->t('The protected user itself'), - ); + ]; } } // Bypass all protections. @@ -95,97 +122,97 @@ public function form(array $form, FormStateInterface $form_state) { // Bypass this protection. $permission = $this->entity->getPermissionName(); if ($permission && !$this->entity->isNew()) { - $permission_label = $this->t('Bypass user protection for @label', array('@label' => $this->entity->label())); + $permission_label = $this->t('Bypass user protection for @label', ['@label' => $this->entity->label()]); $items[] = $this->getBypassMessage($permission, $permission_label); } switch ($protected_entity_type) { case 'user': - $form['help'] = array( + $form['help'] = [ '#markup' => $this->t('This user will be protected for all users except:'), - ); + ]; break; case 'user_role': - $form['help'] = array( + $form['help'] = [ '#markup' => $this->t('This role will be protected for all users except:'), - ); + ]; break; } - $form['help']['list'] = array( + $form['help']['list'] = [ '#theme' => 'item_list', '#items' => $items, - ); + ]; - $form['label'] = array( + $form['label'] = [ '#type' => 'textfield', '#title' => $this->t('Name'), '#default_value' => $this->entity->label(), '#required' => TRUE, - ); - $form['name'] = array( + ]; + $form['name'] = [ '#type' => 'machine_name', - '#machine_name' => array( - 'exists' => array($this->protectionRuleStorage, 'load'), - ), + '#machine_name' => [ + 'exists' => [$this->protectionRuleStorage, 'load'], + ], '#default_value' => $this->entity->id(), '#required' => TRUE, - ); + ]; switch ($protected_entity_type) { case 'user': - $form['entity_id'] = array( + $form['entity_id'] = [ '#type' => 'entity_autocomplete', '#target_type' => 'user', '#title' => $this->t('User'), '#default_value' => $this->entity->getProtectedEntity(), '#required' => TRUE, - ); + ]; break; case 'user_role': - $entities = array_map('Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names(TRUE)); - $form['entity_id'] = array( + $entities = array_map('Drupal\Component\Utility\Html::escape', user_role_names(TRUE)); + $form['entity_id'] = [ '#type' => 'select', '#title' => $this->t('Role'), '#options' => $entities, '#default_value' => $this->entity->getProtectedEntityId(), '#required' => TRUE, - ); + ]; break; } - $protection_options = array(); - $enabled_protections = array(); + $protection_options = []; + $enabled_protections = []; foreach ($this->entity->getProtections()->getAll() as $name => $plugin) { - $protection_options[$name] = array( - 'protection' => array( - 'data' => array( + $protection_options[$name] = [ + 'protection' => [ + 'data' => [ '#type' => 'item', '#markup' => $plugin->label(), '#description' => $plugin->description(), - ), - ), - ); + ], + ], + ]; if ($plugin->status) { $enabled_protections[$name] = TRUE; } } - $form['protection'] = array( + $form['protection'] = [ '#type' => 'tableselect', - '#header' => array('protection' => $this->t('Protection')), + '#header' => ['protection' => $this->t('Protection')], '#options' => $protection_options, '#default_value' => $enabled_protections, - ); + ]; - $roles = array_map('Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names()); - $form['bypass_roles'] = array( + $roles = array_map('Drupal\Component\Utility\Html::escape', user_role_names()); + $form['bypass_roles'] = [ '#type' => 'checkboxes', '#title' => $this->t('Bypass for roles'), '#description' => $this->t('Note: this setting will be saved as user permissions.'), '#options' => $roles, '#default_value' => $this->entity->getBypassRoles(), - ); + ]; return parent::form($form, $form_state); } @@ -211,7 +238,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } // Set bypass roles. - $bypass_roles = array(); + $bypass_roles = []; foreach ($form_state->getValue('bypass_roles') as $rid => $status) { if (!empty($status)) { $bypass_roles[] = $rid; diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Delete.php b/web/modules/userprotect/src/Plugin/UserProtection/Delete.php index cbe0281338f6a3d2d3ade8b4edd496c957e2b95e..cae01a746a01ebd88543bebf34755f4f5e21eae5 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/Delete.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/Delete.php @@ -15,6 +15,7 @@ * ) */ class Delete extends UserProtectionBase { + /** * {@inheritdoc} */ @@ -24,4 +25,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account) } return parent::isProtected($user, $op, $account); } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Edit.php b/web/modules/userprotect/src/Plugin/UserProtection/Edit.php index 1a7995ff5689fb88138cce48fab0e75b6002ffcd..1856d95ad4b3ce70d00b62b8fa654bd799a20a80 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/Edit.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/Edit.php @@ -15,6 +15,7 @@ * ) */ class Edit extends UserProtectionBase { + /** * {@inheritdoc} */ @@ -24,4 +25,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account) } return parent::isProtected($user, $op, $account); } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Mail.php b/web/modules/userprotect/src/Plugin/UserProtection/Mail.php index 93202050f3e89d93fbe5f609bbde7effae9ad760..837346ead9aa5250013bd133f45089c52e210911 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/Mail.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/Mail.php @@ -14,6 +14,7 @@ * ) */ class Mail extends UserProtectionBase { + /** * {@inheritdoc} */ @@ -28,4 +29,5 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for } return FALSE; } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Password.php b/web/modules/userprotect/src/Plugin/UserProtection/Password.php index af07ec80776a4165d8130b3c4d1877920f9764ba..ad9eefddcb6a4f007a538912e9915775ba82d34e 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/Password.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/Password.php @@ -14,6 +14,7 @@ * ) */ class Password extends UserProtectionBase { + /** * {@inheritdoc} */ @@ -43,4 +44,5 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for return FALSE; } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Roles.php b/web/modules/userprotect/src/Plugin/UserProtection/Roles.php index 6056b13e53e652f713a203db52b5cc21572af5f0..240bed85faae9d21ac6b387a7fd8142bb561d537 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/Roles.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/Roles.php @@ -14,14 +14,24 @@ * ) */ class Roles extends UserProtectionBase { + /** * {@inheritdoc} */ public function applyAccountFormProtection(array &$form, FormStateInterface $form_state) { + // Make sure this module also works when role_delegation is enabled. + $applied = FALSE; + if (isset($form['role_change']['widget'])) { + $form['role_change']['widget']['#disabled'] = TRUE; + $applied = TRUE; + } + if (isset($form['account']['roles'])) { $form['account']['roles']['#disabled'] = TRUE; - return TRUE; + $applied = TRUE; } - return FALSE; + + return $applied; } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Status.php b/web/modules/userprotect/src/Plugin/UserProtection/Status.php index bcd7e5f9a2e4030713d7fed79fc9e7774806bb74..874d45cdadb185db0371e288b7dc4d60571d08f0 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/Status.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/Status.php @@ -14,6 +14,7 @@ * ) */ class Status extends UserProtectionBase { + /** * {@inheritdoc} */ @@ -27,4 +28,5 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for } return FALSE; } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php index 48c1d64b9b3cd98dbb2d0faee436ccc339ef4582..ddc1f7276504e58af14c4a756c27ef92662c59e9 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionBase.php @@ -60,11 +60,11 @@ public function getWeight() { * {@inheritdoc} */ public function getConfiguration() { - return array( + return [ 'id' => $this->getPluginId(), 'provider' => $this->pluginDefinition['provider'], 'status' => $this->status, - ); + ]; } /** @@ -81,14 +81,14 @@ public function setConfiguration(array $configuration) { * {@inheritdoc} */ public function defaultConfiguration() { - return array(); + return []; } /** * {@inheritdoc} */ public function calculateDependencies() { - return array(); + return []; } /** @@ -115,4 +115,5 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account) public function applyAccountFormProtection(array &$form, FormStateInterface $form_state) { return FALSE; } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php index 753901cd0a78981f01943339e776847bf3450731..8fa2e0992b577a391a458e11b3cff021778db69b 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionInterface.php @@ -3,7 +3,8 @@ namespace Drupal\userprotect\Plugin\UserProtection; use Drupal\Component\Plugin\PluginInspectionInterface; -use Drupal\Component\Plugin\ConfigurablePluginInterface; +use Drupal\Component\Plugin\ConfigurableInterface; +use Drupal\Component\Plugin\DependentPluginInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountInterface; use Drupal\user\UserInterface; @@ -11,7 +12,8 @@ /** * Defines the interface for user protection plugins. */ -interface UserProtectionInterface extends PluginInspectionInterface, ConfigurablePluginInterface { +interface UserProtectionInterface extends PluginInspectionInterface, ConfigurableInterface, DependentPluginInterface { + /** * Returns the user protection label. * @@ -66,12 +68,13 @@ public function isProtected(UserInterface $user, $op, AccountInterface $account) * * @param array $form * Nested array of form elements that comprise the form. - * @param array $form_state - * A keyed array containing the current state of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. * * @return bool * TRUE if the protection was applied. * FALSE otherwise. */ public function applyAccountFormProtection(array &$form, FormStateInterface $form_state); + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php index f4ddcfec0310ff740faf8eb28a7149d7c36bfde4..28fc150ac78390e3624ef07ad16052a890cb8562 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/UserProtectionPluginCollection.php @@ -17,16 +17,6 @@ class UserProtectionPluginCollection extends DefaultLazyPluginCollection { */ protected $definitions; - /** - * {@inheritdoc} - * - * @return \Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface - * An instance of UserProtectionInterface. - */ - public function &get($instance_id) { - return parent::get($instance_id); - } - /** * Retrieves all user protection plugin instances. * @@ -47,7 +37,7 @@ public function getAll() { } // Sort plugins. - uasort($this->pluginInstances, array($this, 'pluginInstancesSort')); + uasort($this->pluginInstances, [$this, 'pluginInstancesSort']); return $this->pluginInstances; } @@ -60,7 +50,7 @@ public function getAll() { */ public function getEnabledPlugins() { $instances = $this->getAll(); - $enabled = array(); + $enabled = []; foreach ($this->configurations as $instance_id => $configuration) { if ($configuration['status']) { $enabled[] = $instances[$instance_id]; @@ -68,7 +58,7 @@ public function getEnabledPlugins() { } // Sort plugins. - uasort($enabled, array($this, 'pluginInstancesSort')); + uasort($enabled, [$this, 'pluginInstancesSort']); return $enabled; } @@ -89,9 +79,9 @@ protected function initializePlugin($instance_id) { /** * Sorts plugin instances based on weight, label, provider or id. * - * @param Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $a + * @param \Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $a * The first plugin in the comparison. - * @param Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $b + * @param \Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface $b * The second plugin in the comparison. * * @return int @@ -99,7 +89,7 @@ protected function initializePlugin($instance_id) { * 1 if $b should go first. * 0 if it's unknown which should go first. */ - public function pluginInstancesSort($a, $b) { + public function pluginInstancesSort(UserProtectionInterface $a, UserProtectionInterface $b) { if ($a->getWeight() != $b->getWeight()) { return $a->getWeight() < $b->getWeight() ? -1 : 1; } @@ -125,4 +115,5 @@ public function getConfiguration() { } return $configuration; } + } diff --git a/web/modules/userprotect/src/Plugin/UserProtection/Username.php b/web/modules/userprotect/src/Plugin/UserProtection/Username.php index 8e2cfd18cd0836ded7be989a8a08464ee4737795..371fd0d1c86b185bff00cdd39bb721fa9289bf0d 100644 --- a/web/modules/userprotect/src/Plugin/UserProtection/Username.php +++ b/web/modules/userprotect/src/Plugin/UserProtection/Username.php @@ -14,6 +14,7 @@ * ) */ class Username extends UserProtectionBase { + /** * {@inheritdoc} */ @@ -21,11 +22,12 @@ public function applyAccountFormProtection(array &$form, FormStateInterface $for $build_info = $form_state->getBuildInfo(); $account = $build_info['callback_object']->getEntity(); // If for some reason the account has no username, then don't protect it. - if ($account->getUsername() && isset($form['account']['name'])) { + if ($account->getAccountName() && isset($form['account']['name'])) { $form['account']['name']['#disabled'] = TRUE; - $form['account']['name']['#value'] = $account->getUsername(); + $form['account']['name']['#value'] = $account->getAccountName(); return TRUE; } return FALSE; } + } diff --git a/web/modules/userprotect/src/Routing/RouteSubscriber.php b/web/modules/userprotect/src/Routing/RouteSubscriber.php new file mode 100644 index 0000000000000000000000000000000000000000..0d68e36c06eb1b89a0015c16b9153d2425cf5fd2 --- /dev/null +++ b/web/modules/userprotect/src/Routing/RouteSubscriber.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\userprotect\Routing; + +use Drupal\Core\Routing\RouteSubscriberBase; +use Symfony\Component\Routing\RouteCollection; + +/** + * Class RouteSubscriber. + * + * @package Drupal\userprotect\Routing + */ +class RouteSubscriber extends RouteSubscriberBase { + + /** + * {@inheritdoc} + */ + protected function alterRoutes(RouteCollection $collection) { + if ($route = $collection->get('role_delegation.edit_form')) { + $route->setRequirement('_userprotect_role_access_check', 'TRUE'); + } + } + +} diff --git a/web/modules/userprotect/src/Tests/ModuleInstallUninstallWebTest.php b/web/modules/userprotect/src/Tests/ModuleInstallUninstallWebTest.php deleted file mode 100644 index 66932976fc5cf581cfa500c85adfe02d53076edc..0000000000000000000000000000000000000000 --- a/web/modules/userprotect/src/Tests/ModuleInstallUninstallWebTest.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php - -namespace Drupal\userprotect\Tests; - -use Drupal\simpletest\WebTestBase; - -/** - * Tests module installation and uninstallation. - * - * @group userprotect - */ -class ModuleInstallUninstallWebTest extends WebTestBase { - - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); - - /** - * Test installation and uninstallation. - */ - protected function testInstallationAndUninstallation() { - /** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */ - $module_installer = \Drupal::service('module_installer'); - $module_handler = \Drupal::moduleHandler(); - $this->assertTrue($module_handler->moduleExists('userprotect')); - - // Test default configuration. - $account = $this->drupalCreateUser(); - $this->assertTrue($account->hasPermission('userprotect.mail.edit'), 'Authenticated user can edit own mail address.'); - $this->assertTrue($account->hasPermission('userprotect.pass.edit'), 'Authenticated user can edit own password.'); - $this->assertTrue($account->hasPermission('userprotect.account.edit'), 'Authenticated user can edit own account.'); - - // Ensure an authenticated user can edit its own account. - $this->drupalLogin($account); - $this->drupalGet('user/' . $account->id() . '/edit'); - $this->assertResponse(200, 'Authenticated user has access to edit page of own account.'); - - $module_installer->uninstall(array('userprotect')); - $this->assertFalse($module_handler->moduleExists('userprotect')); - } -} diff --git a/web/modules/userprotect/src/Tests/ProtectedEntityDeleteTest.php b/web/modules/userprotect/src/Tests/ProtectedEntityDeleteTest.php deleted file mode 100644 index ee81d7e863eb9eeb8df8f9e549e31e0d9fb6cec4..0000000000000000000000000000000000000000 --- a/web/modules/userprotect/src/Tests/ProtectedEntityDeleteTest.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -namespace Drupal\userprotect\Tests; - -/** - * Tests if protection rules are cleaned up upon entity deletion. - * - * @group userprotect - */ -class ProtectedEntityDeleteTest extends UserProtectWebTestBase { - - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); - - /** - * Tests reaction upon user deletion. - * - * Tests if an user based protection rule is cleaned up when the protected - * user is deleted. - */ - protected function testUserDelete() { - // Create a user. - $account = $this->drupalCreateUser(); - - // Protect this user. - $protection_rule = $this->createProtectionRule($account->id(), array(), 'user'); - $protection_rule->save(); - - // Assert that the rule was saved. - $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE); - $this->assertNotNull($protection_rule, 'The protection rule was saved.'); - - // Now delete the account. - $account->delete(); - - // Assert that the rule no longer exists. - $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE); - $this->assertNull($protection_rule, 'The protection rule was deleted.'); - } - - /** - * Tests reaction upon role deletion. - * - * Tests if a role based protection rule is cleaned up when the protected - * role is deleted. - */ - protected function testRoleDelete() { - // Create a role. - $rid = $this->drupalCreateRole(array()); - - // Protect this role. - $protection_rule = $this->createProtectionRule($rid, array(), 'user_role'); - $protection_rule->save(); - - // Assert that the rule was saved. - $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE); - $this->assertNotNull($protection_rule, 'The protection rule was saved.'); - - // Now delete the role. - $role = entity_load('user_role', $rid); - $role->delete(); - - // Assert that the rule no longer exists. - $protection_rule = entity_load('userprotect_rule', $protection_rule->id(), TRUE); - $this->assertNull($protection_rule, 'The protection rule was deleted.'); - } - - /** - * Tests UI for non-existent protected users. - * - * Tests if there are no PHP errors in the UI when a protection rule for a - * non-existent user still exists. - */ - protected function testNonExistentProtectedUser() { - // Create a protection rule for a non-existent user. - $fake_uid = 10; - $protection_rule = $this->createProtectionRule($fake_uid, array(), 'user'); - $protection_rule->save(); - - // Check user interface. - $account = $this->drupalCreateUser(array('userprotect.administer')); - $this->drupalLogin($account); - $this->drupalGet('admin/config/people/userprotect'); - $this->assertText(t('Missing')); - } - - /** - * Tests UI for non-existent protected roles. - * - * Tests if there are no PHP errors in the UI when a protection rule for a - * non-existent role still exists. - */ - protected function testNonExistentProtectedRole() { - // Create a protection rule for a non-existent user. - $protection_rule = $this->createProtectionRule('non-existent role', array(), 'user_role'); - $protection_rule->save(); - - // Check user interface. - $account = $this->drupalCreateUser(array('userprotect.administer')); - $this->drupalLogin($account); - $this->drupalGet('admin/config/people/userprotect'); - $this->assertText(t('Missing')); - } -} diff --git a/web/modules/userprotect/src/Tests/ProtectionRuleCrudWebTest.php b/web/modules/userprotect/src/Tests/ProtectionRuleCrudWebTest.php deleted file mode 100644 index b828ee417010b574500957cf18a0884a7900a466..0000000000000000000000000000000000000000 --- a/web/modules/userprotect/src/Tests/ProtectionRuleCrudWebTest.php +++ /dev/null @@ -1,185 +0,0 @@ -<?php - -namespace Drupal\userprotect\Tests; - -use Drupal\userprotect\Entity\ProtectionRuleInterface; - -/** - * Tests creating, editing and deleting protection rules through the UI. - * - * @group userprotect - */ -class ProtectionRuleCrudWebTest extends UserProtectWebTestBase { - - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); - - /** - * The operating account. - * - * @var \Drupal\user\UserInterface - */ - protected $account; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - - $this->account = $this->drupalCreateUser(array('userprotect.administer')); - $this->drupalLogin($this->account); - } - - /** - * Tests if role based protection rules can be created through the UI. - */ - protected function testCrudRoleProtectionRule() { - $rid = $this->drupalCreateRole(array()); - $rule_id = strtolower($this->randomMachineName()); - $label = $this->randomMachineName(); - - // Create rule. - $edit = array( - 'label' => $label, - 'name' => $rule_id, - 'entity_id' => $rid, - 'protection[user_mail]' => TRUE, - ); - $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save')); - - // Assert that the rule was created. - $protection_rule = entity_load('userprotect_rule', $rule_id); - $this->assertTrue(($protection_rule instanceof ProtectionRuleInterface), 'A protection rule was created through the UI.'); - - // Stop the test if rule is not an instance of ProtectionRuleInterface. - if (!($protection_rule instanceof ProtectionRuleInterface)) { - return; - } - - // Assert that the rule has the expected values. - $this->assertEqual($rule_id, $protection_rule->id()); - $this->assertEqual($label, $protection_rule->label); - $this->assertEqual('user_role', $protection_rule->getProtectedEntityTypeId()); - $this->assertEqual($rid, $protection_rule->getProtectedEntityId()); - $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); - $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.'); - $plugin = reset($enabled_plugins); - $this->assertEqual('user_mail', $plugin->getPluginId()); - - // Edit rule. - $edit = array( - 'protection[user_name]' => TRUE, - 'protection[user_mail]' => FALSE, - ); - $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save')); - - // Assert that the rule was updated with the expected values. - $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE); - $this->assertEqual($rule_id, $protection_rule->id()); - $this->assertEqual($label, $protection_rule->label); - $this->assertEqual('user_role', $protection_rule->getProtectedEntityTypeId()); - $this->assertEqual($rid, $protection_rule->getProtectedEntityId()); - $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); - $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.'); - $plugin = reset($enabled_plugins); - $this->assertEqual('user_name', $plugin->getPluginId()); - - // Attempt to create a rule with the same name. - $edit = array( - 'label' => $label, - 'name' => $rule_id, - 'entity_id' => $rid, - 'protection[user_mail]' => TRUE, - ); - $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save')); - $this->assertText('The machine-readable name is already in use. It must be unique.'); - - // Assert only one protection rule exists. - $entities = entity_load_multiple('userprotect_rule', NULL, TRUE); - $this->assertEqual(1, count($entities), 'Only one protection rule exists.'); - - // Delete rule. - $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', array(), t('Delete')); - // Assert the rule no longer exists. - $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE); - $this->assertFalse($protection_rule, 'The protection rule was deleted.'); - } - - /** - * Tests if user based protection rules can be created through the UI. - */ - protected function testCrudUserProtectionRule() { - $account = $this->drupalCreateUser(); - $rule_id = strtolower($this->randomMachineName()); - $label = $this->randomMachineName(); - - // Create rule. - $edit = array( - 'label' => $label, - 'name' => $rule_id, - 'entity_id' => $account->getUsername(), - 'protection[user_mail]' => TRUE, - ); - $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save')); - - // Assert that the rule was created. - $protection_rule = entity_load('userprotect_rule', $rule_id); - $this->assertTrue(($protection_rule instanceof ProtectionRuleInterface), 'A protection rule was created through the UI.'); - - // Stop the test if rule is not an instance of ProtectionRuleInterface. - if (!($protection_rule instanceof ProtectionRuleInterface)) { - return; - } - - // Assert that the rule has the expected values. - $this->assertEqual($rule_id, $protection_rule->id()); - $this->assertEqual($label, $protection_rule->label); - $this->assertEqual('user', $protection_rule->getProtectedEntityTypeId()); - $this->assertEqual($account->id(), $protection_rule->getProtectedEntityId()); - $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); - $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.'); - $plugin = reset($enabled_plugins); - $this->assertEqual('user_mail', $plugin->getPluginId()); - - // Edit rule. - $edit = array( - 'protection[user_name]' => TRUE, - 'protection[user_mail]' => FALSE, - ); - $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save')); - - // Assert that the rule was updated with the expected values. - $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE); - $this->assertEqual($rule_id, $protection_rule->id()); - $this->assertEqual($label, $protection_rule->label); - $this->assertEqual('user', $protection_rule->getProtectedEntityTypeId()); - $this->assertEqual($account->id(), $protection_rule->getProtectedEntityId()); - $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); - $this->assertEqual(1, count($enabled_plugins), 'One plugin was enabled.'); - $plugin = reset($enabled_plugins); - $this->assertEqual('user_name', $plugin->getPluginId()); - - // Attempt to create a rule with the same name. - $edit = array( - 'label' => $label, - 'name' => $rule_id, - 'entity_id' => $account->getUsername(), - 'protection[user_mail]' => TRUE, - ); - $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save')); - $this->assertText('The machine-readable name is already in use. It must be unique.'); - - // Assert only one protection rule exists. - $entities = entity_load_multiple('userprotect_rule', NULL, TRUE); - $this->assertEqual(1, count($entities), 'Only one protection rule exists.'); - - // Delete rule. - $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', array(), t('Delete')); - // Assert the rule no longer exists. - $protection_rule = entity_load('userprotect_rule', $rule_id, TRUE); - $this->assertFalse($protection_rule, 'The protection rule was deleted.'); - } -} diff --git a/web/modules/userprotect/src/Tests/UserProtectWebTestBase.php b/web/modules/userprotect/src/Tests/UserProtectWebTestBase.php deleted file mode 100644 index f7a163bf4246fee552a7646f22f4b365ae879a6a..0000000000000000000000000000000000000000 --- a/web/modules/userprotect/src/Tests/UserProtectWebTestBase.php +++ /dev/null @@ -1,190 +0,0 @@ -<?php - -namespace Drupal\userprotect\Tests; - -use Drupal\Component\Utility\SafeMarkup; -use Drupal\userprotect\Entity\ProtectionRuleInterface; -use Drupal\simpletest\WebTestBase; - -/** - * Base class for User protect web tests. - */ -abstract class UserProtectWebTestBase extends WebTestBase { - - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); - - /** - * Creates a protected role. - * - * @param array $protections - * (optional) The active protections. - * Defaults to an empty array. - * - * @return string - * The ID of the created role. - */ - protected function createProtectedRole(array $protections = array()) { - // Create a role. - $rid = $this->drupalCreateRole(array()); - - // Protect this role. - $protection_rule = $this->createProtectionRule($rid, $protections); - $protection_rule->save(); - // Reset available permissions. - drupal_static_reset('checkPermissions'); - - return $rid; - } - - /** - * Creates a protected user. - * - * @param array $protections - * (optional) The active protections. - * Defaults to an empty array. - * - * @return object - * The created user. - */ - protected function createProtectedUser(array $protections = array()) { - // Create a user. - $account = $this->drupalCreateUser(); - - // Protect this user. - $protection_rule = $this->createProtectionRule($account->id(), $protections, 'user'); - $protection_rule->save(); - // Reset available permissions. - drupal_static_reset('checkPermissions'); - - return $account; - } - - /** - * Creates an user with a protected role. - * - * @param array $protections - * (optional) The active protections. - * Defaults to an empty array. - * - * @return object - * The created user. - */ - protected function createUserWithProtectedRole(array $protections = array()) { - // Create a protected role. - $rid = $this->createProtectedRole($protections); - - // Create an account with this protected role. - $protected_account = $this->drupalCreateUser(); - $protected_account->addRole($rid); - $protected_account->save(); - - return $protected_account; - } - - /** - * Creates protection rule. - * - * @param int|string $entity_id - * The id of the entity to protect. - * @param array $protections - * (optional) The active protections. - * Defaults to an empty array. - * @param string $entity_type - * (optional) The protected entity type. - * Defaults to "user_role". - * @param array $values - * (optional) Extra values of the protection rule. - * - * @return \Drupal\userprotect\Entity\ProtectionRuleInterface - * An instance of ProtectionRuleInterface. - */ - protected function createProtectionRule($entity_id, array $protections = array(), $entity_type = 'user_role', array $values = array()) { - // Setup default values. - $values += array( - 'name' => 'dummy', - 'label' => 'Dummy', - 'protections' => array(), - 'protectedEntityTypeId' => $entity_type, - 'protectedEntityId' => $entity_id, - ); - // Define protections. - foreach ($protections as $key) { - $values['protections'][$key] = array( - 'status' => TRUE, - ); - } - - // Create protection rule. - $protection_rule = entity_create('userprotect_rule', $values); - $this->assertTrue($protection_rule instanceof ProtectionRuleInterface, SafeMarkup::format('Created protection rule %rule.', array('%rule' => $protection_rule->id()))); - return $protection_rule; - } - - /** - * Executes a form submission, but does not require all fields to be present. - * - * @param NULL|string $path - * Location of the post form. - * @param array $edit - * Field data in an associative array. - * @param string $submit - * Value of the submit button whose click is to be emulated. - * @param array $options - * (optional) Options to be forwarded to the url generator. - * @param array $headers - * (optional) An array containing additional HTTP request headers. - * @param string $form_html_id - * (optional) HTML ID of the form to be submitted. - * - * @return NULL|string - * Result of CURL in case form could be posted. - * NULL otherwise. - */ - protected function userprotectPostForm($path, $edit, $submit, array $options = array(), array $headers = array(), $form_html_id = NULL) { - if (isset($path)) { - $this->drupalGet($path, $options); - } - if ($this->parse()) { - $edit_save = $edit; - // Let's iterate over all the forms. - $xpath = "//form"; - if (!empty($form_html_id)) { - $xpath .= "[@id='" . $form_html_id . "']"; - } - $forms = $this->xpath($xpath); - foreach ($forms as $form) { - // We try to set the fields of this form as specified in $edit. - $edit = $edit_save; - $post = array(); - $upload = array(); - $submit_matches = $this->handleForm($post, $edit, $upload, $submit, $form); - $action = isset($form['action']) ? $this->getAbsoluteUrl((string) $form['action']) : $this->getUrl(); - - if ($submit_matches) { - $post = array_merge($post, $edit); - $out = $this->curlExec(array( - CURLOPT_URL => $action, - CURLOPT_POST => TRUE, - CURLOPT_POSTFIELDS => $post, - CURLOPT_HTTPHEADER => $headers, - )); - - $verbose = 'POST request to: ' . $path; - $verbose .= '<hr />Ending URL: ' . $this->getUrl(); - if ($this->dumpHeaders) { - $verbose .= '<hr />Headers: <pre>' . SafeMarkup::checkPlain(var_export(array_map('trim', $this->headers), TRUE)) . '</pre>'; - } - $verbose .= '<hr />Fields: ' . highlight_string('<?php ' . var_export($post, TRUE), TRUE); - $verbose .= '<hr />' . $out; - - $this->verbose($verbose); - return $out; - } - } - $this->fail(SafeMarkup::format('Found the requested form fields at @path', array('@path' => $path))); - } - } -} diff --git a/web/modules/userprotect/src/Tests/UserProtectionWebTest.php b/web/modules/userprotect/src/Tests/UserProtectionWebTest.php deleted file mode 100644 index 14de81fea8e3807440f11351c3f723f89b53662d..0000000000000000000000000000000000000000 --- a/web/modules/userprotect/src/Tests/UserProtectionWebTest.php +++ /dev/null @@ -1,144 +0,0 @@ -<?php - -namespace Drupal\userprotect\Tests; - -/** - * Tests each UserProtection plugin in action. - * - * @group userprotect - * @todo Assert protection messages. - */ -class UserProtectionWebTest extends UserProtectWebTestBase { - - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); - - /** - * The operating account. - * - * @var \Drupal\user\UserInterface - */ - protected $account; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - - $this->account = $this->drupalCreateUser(array('administer users', 'administer permissions')); - $this->drupalLogin($this->account); - } - - /** - * Tests if the user's name field has the expected protection. - */ - protected function testNameProtection() { - $protected_account = $this->createProtectedUser(array('user_name')); - - // Remember the user's name. - $expected_name = $protected_account->getUsername(); - - $edit = array( - 'name' => $this->randomMachineName(), - ); - $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save')); - - // Re-load the user and check the user name didn't change. - $protected_account = entity_load('user', $protected_account->id(), TRUE); - $this->assertEqual($expected_name, $protected_account->getUsername()); - } - - /** - * Tests if the user's mail address field has the expected protection. - */ - protected function testMailProtection() { - $protected_account = $this->createProtectedUser(array('user_mail')); - - // Remember the user's mail address. - $expected_mail = $protected_account->getEmail(); - - $edit = array( - 'mail' => $this->randomMachineName() . '@example.com', - ); - $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save')); - - // Re-load the user and check the user mail address didn't change. - $protected_account = entity_load('user', $protected_account->id(), TRUE); - $this->assertEqual($expected_mail, $protected_account->getEmail()); - } - - /** - * Tests if the user's password field has the expected protection. - */ - protected function testPassProtection() { - $protected_account = $this->createProtectedUser(array('user_pass')); - - // Remember the user's pass. - $expected_pass = $protected_account->pass_raw; - - $new_pass = $this->randomMachineName(); - $edit = array( - 'pass[pass1]' => $new_pass, - 'pass[pass2]' => $new_pass, - ); - $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save')); - - // Try to login as this user with the expected password. - $protected_account = entity_load('user', $protected_account->id(), TRUE); - $protected_account->pass_raw = $expected_pass; - $this->drupalLogout(); - $this->drupalLogin($protected_account); - } - - /** - * Tests if the user's status field has the expected protection. - */ - protected function testStatusProtection() { - $protected_account = $this->createProtectedUser(array('user_status')); - - // Try to deactivate user's status. - $edit = array( - 'status' => '0', - ); - $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save')); - - // Re-load the user and check the user is still active. - $protected_account = entity_load('user', $protected_account->id(), TRUE); - $this->assertTrue($protected_account->isActive()); - } - - /** - * Tests if the user's roles field has the expected protection. - */ - protected function testRolesProtection() { - $protected_account = $this->createProtectedUser(array('user_roles')); - - // Add a role to the protected account. - $rid1 = $this->drupalCreateRole(array()); - $protected_account->addRole($rid1); - $protected_account->save(); - - // Add another role. We try to add this role to the user form later. - $rid2 = $this->drupalCreateRole(array()); - - // Re-load the user and check its roles. - $protected_account = entity_load('user', $protected_account->id(), TRUE); - // Assert the protected account's roles. - $this->assertTrue($protected_account->hasRole($rid1)); - $this->assertFalse($protected_account->hasRole($rid2)); - - // Try to add the second role to this user. - $edit = array( - 'roles[' . $rid2 . ']' => $rid2, - ); - $this->userprotectPostForm('user/' . $protected_account->id() . '/edit', $edit, t('Save')); - - // Re-load the user and assert the roles it has are still the same. - $protected_account = entity_load('user', $protected_account->id(), TRUE); - $this->assertTrue($protected_account->hasRole($rid1)); - $this->assertFalse($protected_account->hasRole($rid2)); - } -} diff --git a/web/modules/userprotect/src/UserProtectPermissions.php b/web/modules/userprotect/src/UserProtectPermissions.php index d3d535357c30d8f0abd0794300ff80248a0b8a8a..f4961de38f2d4d3bfa53147c995a92188f1d8e19 100644 --- a/web/modules/userprotect/src/UserProtectPermissions.php +++ b/web/modules/userprotect/src/UserProtectPermissions.php @@ -3,12 +3,12 @@ namespace Drupal\userprotect; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Provides dynamic permissions of the filter module. + * Provides dynamic permissions for bypassing user protect rules. */ class UserProtectPermissions implements ContainerInjectionInterface { @@ -17,25 +17,25 @@ class UserProtectPermissions implements ContainerInjectionInterface { /** * The entity manager. * - * @var \Drupal\Core\Entity\EntityManagerInterface + * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ - protected $entityManager; + protected $entityTypeManager; /** * Constructs a new UserProtectPermissions instance. * - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. */ - public function __construct(EntityManagerInterface $entity_manager) { - $this->entityManager = $entity_manager; + public function __construct(EntityTypeManagerInterface $entity_type_manager) { + $this->entityTypeManager = $entity_type_manager; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static($container->get('entity.manager')); + return new static($container->get('entity_type.manager')); } /** @@ -48,7 +48,7 @@ public function permissions() { $permissions = []; // For each protection rule, create a permission to bypass the rule. /** @var \Drupal\userprotect\Entity\ProtectionRuleInterface[] $rules */ - $rules = $this->entityManager->getStorage('userprotect_rule')->loadMultiple(); + $rules = $this->entityTypeManager->getStorage('userprotect_rule')->loadMultiple(); uasort($rules, 'Drupal\Core\Config\Entity\ConfigEntityBase::sort'); foreach ($rules as $rule) { $vars = [ diff --git a/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.info.yml b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..b5b1ca38b4003c00f848b7d6d511232321cfb310 --- /dev/null +++ b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.info.yml @@ -0,0 +1,13 @@ +name: User protect test +type: module +description: 'Support module for the User protect tests.' +package: Testing +core: 8.x +core_version_requirement: ^8 || ^9 +dependencies: + - userprotect + +# Information added by Drupal.org packaging script on 2020-01-06 +version: '8.x-1.1' +project: 'userprotect' +datestamp: 1578341587 diff --git a/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.module b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.module new file mode 100644 index 0000000000000000000000000000000000000000..05361f64c234379fd016e02ae9790d685d2131f9 --- /dev/null +++ b/web/modules/userprotect/tests/modules/userprotect_test/userprotect_test.module @@ -0,0 +1,16 @@ +<?php + +/** + * @file + * Support module for the User protect tests. + */ + +/** + * Implements hook_user_format_name_alter(). + * + * Alters the display name of an user to test when the user's display name must + * be used and when the raw account name. + */ +function userprotect_test_user_format_name_alter(&$name, $account) { + $name .= '-userprotect'; +} diff --git a/web/modules/userprotect/tests/src/Functional/InstallTest.php b/web/modules/userprotect/tests/src/Functional/InstallTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c2e19d1ee5a62f72e7759aac45e742c1d7b253d5 --- /dev/null +++ b/web/modules/userprotect/tests/src/Functional/InstallTest.php @@ -0,0 +1,80 @@ +<?php + +namespace Drupal\Tests\userprotect\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Tests module installation and uninstallation. + * + * @group userprotect + */ +class InstallTest extends BrowserTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = []; + + /** + * Module handler to ensure installed modules. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface + */ + protected $moduleHandler; + + /** + * Module installer. + * + * @var \Drupal\Core\Extension\ModuleInstallerInterface + */ + protected $moduleInstaller; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + $this->moduleHandler = $this->container->get('module_handler'); + $this->moduleInstaller = $this->container->get('module_installer'); + } + + /** + * Test installation and uninstallation. + */ + public function testInstallationAndUninstallation() { + // Install userprotect. + $this->assertFalse($this->moduleHandler->moduleExists('userprotect')); + $this->assertTrue($this->moduleInstaller->install(['userprotect'])); + $this->assertTrue($this->moduleHandler->moduleExists('userprotect')); + + // Test default configuration. + $account = $this->drupalCreateUser(); + $this->assertTrue($account->hasPermission('userprotect.mail.edit'), 'Authenticated user can edit own mail address.'); + $this->assertTrue($account->hasPermission('userprotect.pass.edit'), 'Authenticated user can edit own password.'); + $this->assertTrue($account->hasPermission('userprotect.account.edit'), 'Authenticated user can edit own account.'); + + // Ensure an authenticated user can edit its own account. + $this->drupalLogin($account); + $this->drupalGet('user/' . $account->id() . '/edit'); + $this->assertResponse(200, 'Authenticated user has access to edit page of own account.'); + + // Uninstall userprotect. + $this->moduleInstaller->uninstall(['userprotect']); + + // Workaround https://www.drupal.org/node/2021959 + // See \Drupal\Core\Test\FunctionalTestSetupTrait::rebuildContainer. + unset($this->moduleHandler); + $this->rebuildContainer(); + $this->moduleHandler = $this->container->get('module_handler'); + + // Assert that userprotect is uninstalled. + $this->assertFalse($this->moduleHandler->moduleExists('userprotect')); + } + +} diff --git a/web/modules/userprotect/tests/src/Functional/ProtectedEntityDeleteTest.php b/web/modules/userprotect/tests/src/Functional/ProtectedEntityDeleteTest.php new file mode 100644 index 0000000000000000000000000000000000000000..58e77f7f55f4f707710af5c49bb4c3d911dcd36d --- /dev/null +++ b/web/modules/userprotect/tests/src/Functional/ProtectedEntityDeleteTest.php @@ -0,0 +1,49 @@ +<?php + +namespace Drupal\Tests\userprotect\Functional; + +/** + * Tests if protection rules are cleaned up upon entity deletion. + * + * @group userprotect + */ +class ProtectedEntityDeleteTest extends UserProtectBrowserTestBase { + + /** + * Tests UI for non-existent protected users. + * + * Tests if there are no PHP errors in the UI when a protection rule for a + * non-existent user still exists. + */ + public function testNonExistentProtectedUser() { + // Create a protection rule for a non-existent user. + $fake_uid = 10; + $protection_rule = $this->createProtectionRule($fake_uid, [], 'user'); + $protection_rule->save(); + + // Check user interface. + $account = $this->drupalCreateUser(['userprotect.administer']); + $this->drupalLogin($account); + $this->drupalGet('admin/config/people/userprotect'); + $this->assertSession()->pageTextContains('Missing'); + } + + /** + * Tests UI for non-existent protected roles. + * + * Tests if there are no PHP errors in the UI when a protection rule for a + * non-existent role still exists. + */ + public function testNonExistentProtectedRole() { + // Create a protection rule for a non-existent user. + $protection_rule = $this->createProtectionRule('non-existent role', [], 'user_role'); + $protection_rule->save(); + + // Check user interface. + $account = $this->drupalCreateUser(['userprotect.administer']); + $this->drupalLogin($account); + $this->drupalGet('admin/config/people/userprotect'); + $this->assertSession()->pageTextContains('Missing'); + } + +} diff --git a/web/modules/userprotect/tests/src/Functional/ProtectionRuleCrudTest.php b/web/modules/userprotect/tests/src/Functional/ProtectionRuleCrudTest.php new file mode 100644 index 0000000000000000000000000000000000000000..40a2309e005e135444b81e117c445eb959f7b096 --- /dev/null +++ b/web/modules/userprotect/tests/src/Functional/ProtectionRuleCrudTest.php @@ -0,0 +1,172 @@ +<?php + +namespace Drupal\Tests\userprotect\Functional; + +use Drupal\userprotect\Entity\ProtectionRule; +use Drupal\userprotect\Entity\ProtectionRuleInterface; + +/** + * Tests creating, editing and deleting protection rules through the UI. + * + * @group userprotect + */ +class ProtectionRuleCrudTest extends UserProtectBrowserTestBase { + + /** + * The operating account. + * + * @var \Drupal\user\UserInterface + */ + protected $account; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->account = $this->drupalCreateUser(['userprotect.administer']); + $this->drupalLogin($this->account); + } + + /** + * Tests if role based protection rules can be created through the UI. + */ + public function testCrudRoleProtectionRule() { + $rid = $this->drupalCreateRole([]); + $rule_id = strtolower($this->randomMachineName()); + $label = $this->randomMachineName(); + + // Create rule. + $edit = [ + 'label' => $label, + 'name' => $rule_id, + 'entity_id' => $rid, + 'protection[user_mail]' => TRUE, + ]; + $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save')); + + // Assert that the rule was created. + $protection_rule = ProtectionRule::load($rule_id); + $this->assertInstanceOf(ProtectionRuleInterface::class, $protection_rule, 'A protection rule was created through the UI.'); + + // Assert that the rule has the expected values. + $this->assertEquals($rule_id, $protection_rule->id()); + $this->assertEquals($label, $protection_rule->label); + $this->assertEquals('user_role', $protection_rule->getProtectedEntityTypeId()); + $this->assertEquals($rid, $protection_rule->getProtectedEntityId()); + $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); + $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.'); + $plugin = reset($enabled_plugins); + $this->assertEquals('user_mail', $plugin->getPluginId()); + + // Edit rule. + $edit = [ + 'protection[user_name]' => TRUE, + 'protection[user_mail]' => FALSE, + ]; + $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save')); + + // Assert that the rule was updated with the expected values. + $protection_rule = ProtectionRule::load($rule_id); + $this->assertEquals($rule_id, $protection_rule->id()); + $this->assertEquals($label, $protection_rule->label); + $this->assertEquals('user_role', $protection_rule->getProtectedEntityTypeId()); + $this->assertEquals($rid, $protection_rule->getProtectedEntityId()); + $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); + $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.'); + $plugin = reset($enabled_plugins); + $this->assertEquals('user_name', $plugin->getPluginId()); + + // Attempt to create a rule with the same name. + $edit = [ + 'label' => $label, + 'name' => $rule_id, + 'entity_id' => $rid, + 'protection[user_mail]' => TRUE, + ]; + $this->drupalPostForm('admin/config/people/userprotect/add', $edit, t('Save')); + $this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.'); + + // Assert only one protection rule exists. + $entities = ProtectionRule::loadMultiple(NULL); + $this->assertCount(1, $entities, 'Only one protection rule exists.'); + + // Delete rule. + $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', [], t('Delete')); + // Assert the rule no longer exists. + $protection_rule = ProtectionRule::load($rule_id); + $this->assertEmpty($protection_rule, 'The protection rule was deleted.'); + } + + /** + * Tests if user based protection rules can be created through the UI. + */ + public function testCrudUserProtectionRule() { + $account = $this->drupalCreateUser(); + $rule_id = strtolower($this->randomMachineName()); + $label = $this->randomMachineName(); + + // Create rule. + $edit = [ + 'label' => $label, + 'name' => $rule_id, + 'entity_id' => $account->getAccountName(), + 'protection[user_mail]' => TRUE, + ]; + $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save')); + + // Assert that the rule was created. + $protection_rule = ProtectionRule::load($rule_id); + $this->assertInstanceOf(ProtectionRuleInterface::class, $protection_rule, 'A protection rule was created through the UI.'); + + // Assert that the rule has the expected values. + $this->assertEquals($rule_id, $protection_rule->id()); + $this->assertEquals($label, $protection_rule->label); + $this->assertEquals('user', $protection_rule->getProtectedEntityTypeId()); + $this->assertEquals($account->id(), $protection_rule->getProtectedEntityId()); + $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); + $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.'); + $plugin = reset($enabled_plugins); + $this->assertEquals('user_mail', $plugin->getPluginId()); + + // Edit rule. + $edit = [ + 'protection[user_name]' => TRUE, + 'protection[user_mail]' => FALSE, + ]; + $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id, $edit, t('Save')); + + // Assert that the rule was updated with the expected values. + $protection_rule = ProtectionRule::load($rule_id); + $this->assertEquals($rule_id, $protection_rule->id()); + $this->assertEquals($label, $protection_rule->label); + $this->assertEquals('user', $protection_rule->getProtectedEntityTypeId()); + $this->assertEquals($account->id(), $protection_rule->getProtectedEntityId()); + $enabled_plugins = $protection_rule->getProtections()->getEnabledPlugins(); + $this->assertCount(1, $enabled_plugins, 'One plugin was enabled.'); + $plugin = reset($enabled_plugins); + $this->assertEquals('user_name', $plugin->getPluginId()); + + // Attempt to create a rule with the same name. + $edit = [ + 'label' => $label, + 'name' => $rule_id, + 'entity_id' => $account->getAccountName(), + 'protection[user_mail]' => TRUE, + ]; + $this->drupalPostForm('admin/config/people/userprotect/add/user', $edit, t('Save')); + $this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.'); + + // Assert only one protection rule exists. + $entities = ProtectionRule::loadMultiple(NULL); + $this->assertCount(1, $entities, 'Only one protection rule exists.'); + + // Delete rule. + $this->drupalPostForm('admin/config/people/userprotect/manage/' . $rule_id . '/delete', [], t('Delete')); + // Assert the rule no longer exists. + $protection_rule = ProtectionRule::load($rule_id); + $this->assertEmpty($protection_rule, 'The protection rule was deleted.'); + } + +} diff --git a/web/modules/userprotect/tests/src/Functional/RoleDelegation/RoleDelegationIntegrationTest.php b/web/modules/userprotect/tests/src/Functional/RoleDelegation/RoleDelegationIntegrationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..71f7f5cb03fd5f43d21b29511b42423e40e98dab --- /dev/null +++ b/web/modules/userprotect/tests/src/Functional/RoleDelegation/RoleDelegationIntegrationTest.php @@ -0,0 +1,209 @@ +<?php + +namespace Drupal\Tests\userprotect\Functional\RoleDelegation; + +use Drupal\Tests\BrowserTestBase; +use Drupal\userprotect\Entity\ProtectionRule; + +/** + * Functional tests for integration with role_delegation. + * + * @group userprotect + */ +class RoleDelegationIntegrationTest extends BrowserTestBase { + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = ['userprotect', 'user', 'role_delegation']; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * Role ID. + * + * @var string + */ + protected $rid1; + + /** + * Role ID. + * + * @var string + */ + protected $rid2; + + /** + * An admin user. + * + * @var \Drupal\user\UserInterface + */ + protected $adminUser; + + /** + * User with 'assign [role] role' permission'. + * + * @var \Drupal\user\UserInterface + */ + protected $roleDelegatedAdminUser; + + /** + * User with 'administer permissions' permission. + * + * @var \Drupal\user\UserInterface + */ + protected $regularRolesAdminUser; + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + + $admin_role = $this->createAdminRole(); + $this->adminUser = $this->createUser(); + $this->adminUser->addRole($admin_role); + $this->adminUser->save(); + + $this->rid1 = $this->drupalCreateRole([]); + $this->rid2 = $this->drupalCreateRole([]); + + $this->roleDelegatedAdminUser = $this->drupalCreateUser([ + 'administer users', + sprintf('assign %s role', $this->rid1), + sprintf('assign %s role', $this->rid2), + ]); + + $this->regularRolesAdminUser = $this->drupalCreateUser([ + 'administer users', + 'administer permissions', + ]); + + // Create a protection rule to protect users with the admin role. + ProtectionRule::create([ + 'name' => 'protect_admin_role', + 'label' => 'Protect admin role', + 'protections' => [ + 'user_roles' => [ + 'status' => TRUE, + ], + ], + 'protectedEntityTypeId' => 'user_role', + 'protectedEntityId' => $admin_role, + ])->save(); + } + + /** + * Ensure the roles element is only accessible for the right users. + */ + public function testUserEditPage() { + // Login as the delegated admin user. This user has permission to assign + // roles 1 and 2 to users. + $this->drupalLogin($this->roleDelegatedAdminUser); + + // Check if the delegated admin user can edit roles 1 and 2 on its own + // account page. Also check if the roles are presented by Role Delegation, + // not by Drupal core. + $this->drupalGet(sprintf('/user/%s/edit', $this->roleDelegatedAdminUser->id())); + $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid1)); + $this->assertSession()->fieldExists(sprintf('role_change[%s]', $this->rid1)); + $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid2)); + $this->assertSession()->fieldExists(sprintf('role_change[%s]', $this->rid2)); + + // The admin user, having the admin role, has role protection. Ensure that + // the delegated admin user cannot edit its roles. + $this->drupalGet(sprintf('/user/%s/edit', $this->adminUser->id())); + $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid1)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1)); + $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $this->rid2)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2)); + + // Login as roles admin user. This user has permission to assign all roles. + $this->drupalLogin($this->regularRolesAdminUser); + + // The delegated admin user does not have a protected role. Check if the + // roles admin user may edit its roles. Since the roles admin user has the + // specific Drupal core permission for assigning roles - 'administer + // permissions' - the roles should be presented by Drupal Core, not Role + // Delegation. + $this->drupalGet(sprintf('/user/%s/edit', $this->roleDelegatedAdminUser->id())); + $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid1)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1)); + $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid2)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2)); + + // Since the admin user has role protection, ensure that the roles admin + // user cannot edit its roles. + $this->drupalGet(sprintf('/user/%s/edit', $this->adminUser->id())); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1)); + $this->assertSession()->elementAttributeContains('css', sprintf('[name="roles[%s]"]', $this->rid1), 'disabled', 'disabled'); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2)); + $this->assertSession()->elementAttributeContains('css', sprintf('[name="roles[%s]"]', $this->rid2), 'disabled', 'disabled'); + + // Login as an user with the admin role. This user has all privileges. + $this->drupalLogin($this->adminUser); + + // Ensure the admin user can edit the roles of the delegated admin user. + $this->drupalGet(sprintf('/user/%s/edit', $this->roleDelegatedAdminUser->id())); + $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid1)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1)); + $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid2)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2)); + + // Ensure the admin user can edit its own roles. + $this->drupalGet(sprintf('/user/%s/edit', $this->adminUser->id())); + $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid1)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid1)); + $this->assertSession()->fieldExists(sprintf('roles[%s]', $this->rid2)); + $this->assertSession()->fieldNotExists(sprintf('role_change[%s]', $this->rid2)); + } + + /** + * Test that user protect rules are also enabled on /user/%user/roles. + */ + public function testRolesPage() { + // Ensure that an anonymous user cannot access teh user protect settings + // page. + $this->drupalGet('admin/config/people/userprotect/manage/protect_admin_role'); + + // Login as the delegated admin user. This user has permission to assign + // roles 1 and 2 to users. + $this->drupalLogin($this->roleDelegatedAdminUser); + + // Ensure that the delegated admin user can access its own roles edit page. + $this->drupalGet(sprintf('/user/%s/roles', $this->roleDelegatedAdminUser->id())); + $this->assertSession()->statusCodeEquals(200); + + // Ensure that the delegated admin user cannot access the roles edit page of + // the admin user, since that user has a protected role. + $this->drupalGet(sprintf('/user/%s/roles', $this->adminUser->id())); + $this->assertSession()->statusCodeEquals(403); + + // Login as roles admin user. This user has permission to assign all roles. + $this->drupalLogin($this->regularRolesAdminUser); + + // Ensure that the roles admin user cannot access any roles edit pages, as + // that requires specific Roles Delegation permissions. + $this->drupalGet(sprintf('/user/%s/roles', $this->roleDelegatedAdminUser->id())); + $this->assertSession()->statusCodeEquals(403); + + $this->drupalGet(sprintf('/user/%s/roles', $this->adminUser->id())); + $this->assertSession()->statusCodeEquals(403); + + // Login as an user with the admin role. This user has all privileges. + $this->drupalLogin($this->adminUser); + + // Ensure the admin user can access the roles edit page of all users. + $this->drupalGet(sprintf('/user/%s/roles', $this->roleDelegatedAdminUser->id())); + $this->assertSession()->statusCodeEquals(200); + + $this->drupalGet(sprintf('/user/%s/roles', $this->adminUser->id())); + $this->assertSession()->statusCodeEquals(200); + } + +} diff --git a/web/modules/userprotect/src/Tests/UnsavedUserFieldAccessWebTest.php b/web/modules/userprotect/tests/src/Functional/UnsavedUserFieldAccessTest.php similarity index 66% rename from web/modules/userprotect/src/Tests/UnsavedUserFieldAccessWebTest.php rename to web/modules/userprotect/tests/src/Functional/UnsavedUserFieldAccessTest.php index 2247369086bb8c613749cfbf735ab58420aaa0e1..bd35f4f15a22a3913e07b7ba24567f4a0b4f37a5 100644 --- a/web/modules/userprotect/src/Tests/UnsavedUserFieldAccessWebTest.php +++ b/web/modules/userprotect/tests/src/Functional/UnsavedUserFieldAccessTest.php @@ -1,20 +1,18 @@ <?php -namespace Drupal\userprotect\Tests; +namespace Drupal\Tests\userprotect\Functional; use Drupal\user\Entity\User; /** - * Tests field access for a user that has not been saved, such as when a user - * is created via REST POST. + * Tests field access for an unsaved user. + * + * Field access checks could for example be performed on new users when created + * via REST POST. * * @group userprotect */ -class UnsavedUserFieldAccessWebTest extends UserProtectWebTestBase { - /** - * {@inheritdoc} - */ - public static $modules = ['userprotect']; +class UnsavedUserFieldAccessTest extends UserProtectBrowserTestBase { /** * The operating account. @@ -36,7 +34,7 @@ protected function setUp() { /** * Tests if userprotect doesn't interfere with creating users. */ - protected function testUserCreate() { + public function testUserCreate() { // Create an account using the user interface. $name = $this->randomMachineName(); $edit = [ @@ -47,30 +45,30 @@ protected function testUserCreate() { 'notify' => FALSE, ]; $this->drupalPostForm('admin/people/create', $edit, t('Create new account')); - $this->assertText(t('Created a new user account for @name. No email has been sent.', ['@name' => $edit['name']]), 'User created'); + $this->assertSession()->pageTextContains(t('Created a new user account for @name. No email has been sent.', ['@name' => $edit['name']]), 'User created'); // Try to create an user with the same name and assert that it doesn't // result into a fatal error. - $edit = array( + $edit = [ 'name' => $name, 'mail' => $this->randomMachineName() . '@example.com', 'pass[pass1]' => $pass = $this->randomString(), 'pass[pass2]' => $pass, 'notify' => FALSE, - ); + ]; $this->drupalPostForm('admin/people/create', $edit, t('Create new account')); - $this->assertText(t('The username @name is already taken.', ['@name' => $edit['name']])); + $this->assertSession()->pageTextContains(t('The username @name is already taken.', ['@name' => $edit['name']])); } /** * Tests field access for an unsaved user's name. */ - protected function testNameAccessForUnsavedUser() { - $module_handler = \Drupal::moduleHandler(); - $module_installer = \Drupal::service('module_installer'); + public function testNameAccessForUnsavedUser() { + $module_handler = $this->container->get('module_handler'); + $module_installer = $this->container->get('module_installer'); // Create an unsaved user entity. - $unsavedUserEntity = User::Create([]); + $unsavedUserEntity = User::create([]); // The logged in user should have the privileges to edit the unsaved user's // name. @@ -79,10 +77,16 @@ protected function testNameAccessForUnsavedUser() { // Uninstall userprotect and verify that logged in user has privileges to // edit the unsaved user's name. - $module_installer->uninstall(['userprotect']); + $module_installer->uninstall(['userprotect_test', 'userprotect']); + + // Workaround https://www.drupal.org/node/2021959 + // See \Drupal\Core\Test\FunctionalTestSetupTrait::rebuildContainer. + $this->rebuildContainer(); + $module_handler = $this->container->get('module_handler'); $this->assertFalse($module_handler->moduleExists('userprotect'), 'Userprotect uninstalled successfully.'); $this->assertTrue($unsavedUserEntity->isAnonymous(), 'Unsaved user is considered anonymous when userprotect is uninstalled.'); $this->assertTrue($unsavedUserEntity->get('name')->access('edit'), 'Logged in user is allowed to edit name field when userprotect is uninstalled.'); } + } diff --git a/web/modules/userprotect/tests/src/Functional/UserProtectBrowserTestBase.php b/web/modules/userprotect/tests/src/Functional/UserProtectBrowserTestBase.php new file mode 100644 index 0000000000000000000000000000000000000000..a0f6d8ed7c8f1b0e540a8a4699d2c405f4ba2492 --- /dev/null +++ b/web/modules/userprotect/tests/src/Functional/UserProtectBrowserTestBase.php @@ -0,0 +1,42 @@ +<?php + +namespace Drupal\Tests\userprotect\Functional; + +use Drupal\Core\Entity\EntityInterface; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\userprotect\Traits\UserProtectCreationTrait; + +/** + * Provides a base class for User Protect functional tests. + */ +abstract class UserProtectBrowserTestBase extends BrowserTestBase { + + use UserProtectCreationTrait; + + /** + * {@inheritdoc} + */ + public static $modules = ['userprotect', 'userprotect_test']; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * Reloads an entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity to reload. + * + * @return \Drupal\Core\Entity\EntityInterface + * The reloaded entity. + */ + protected function reloadEntity(EntityInterface $entity) { + /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */ + $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId()); + $storage->resetCache([$entity->id()]); + return $storage->load($entity->id()); + } + +} diff --git a/web/modules/userprotect/src/Tests/UserProtectionPermissionsWebTest.php b/web/modules/userprotect/tests/src/Functional/UserProtectionPermissionsTest.php similarity index 58% rename from web/modules/userprotect/src/Tests/UserProtectionPermissionsWebTest.php rename to web/modules/userprotect/tests/src/Functional/UserProtectionPermissionsTest.php index 0d577e3ba7df5d934ae35ebe71fcbb3c5636d42e..5b618eb191a0a7f23927f5ec1059bb66fa8ffb2f 100644 --- a/web/modules/userprotect/src/Tests/UserProtectionPermissionsWebTest.php +++ b/web/modules/userprotect/tests/src/Functional/UserProtectionPermissionsTest.php @@ -1,20 +1,20 @@ <?php -namespace Drupal\userprotect\Tests; +namespace Drupal\Tests\userprotect\Functional; -use Drupal\userprotect\Entity\ProtectionRuleInterface; +use Drupal\Core\Session\AccountInterface; /** - * Tests if permissions "Change own e-mail", "Change own password" and "Change own account" are respected. + * Tests if "change own" User Protect permissions are respected. + * + * The test includes coverage for the following permissions: + * - Change own e-mail (userprotect.mail.edit); + * - Change own password (userprotect.pass.edit); + * - Change own account (userprotect.account.edit). * * @group userprotect */ -class UserProtectionPermissionsWebTest extends UserProtectWebTestBase { - - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); +class UserProtectionPermissionsTest extends UserProtectBrowserTestBase { /** * The operating account. @@ -32,7 +32,7 @@ protected function setUp() { // Revoke default permissions on the authenticated user role that are // installed by the userprotect module. // @see userprotect_install(). - $role = entity_load('user_role', DRUPAL_AUTHENTICATED_RID); + $role = \Drupal::entityTypeManager()->getStorage('user_role')->load(AccountInterface::AUTHENTICATED_ROLE); $role->revokePermission('userprotect.mail.edit'); $role->revokePermission('userprotect.pass.edit'); $role->revokePermission('userprotect.account.edit'); @@ -45,41 +45,35 @@ protected function setUp() { * Tests if an user with the permission "userprotect.mail.edit" can edit its * own mail. */ - protected function testEditOwnMail() { + public function testEditOwnMail() { // Create account that may edit its own mail address. - $account = $this->drupalCreateUser(array('userprotect.mail.edit', 'userprotect.account.edit')); + $account = $this->drupalCreateUser(['userprotect.mail.edit', 'userprotect.account.edit']); $this->drupalLogin($account); - $edit = array( + $edit = [ 'mail' => $this->randomMachineName() . '@example.com', - ); + ]; $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); // Assert the mail address changed. - $account = entity_load('user', $account->id(), TRUE); - $this->assertEqual($edit['mail'], $account->getEmail(), "The user has changed its own mail address."); + $account = $this->reloadEntity($account); + $this->assertEquals($edit['mail'], $account->getEmail(), "The user has changed its own mail address."); } /** * Tests edit mail without permission "userprotect.mail.edit". * - * Tests if an user without the permission "userprotect.mail.edit" can not + * Tests if an user without the permission "userprotect.mail.edit" cannot * edit its own mail address. */ - protected function testNoEditOwnMail() { + public function testNoEditOwnMail() { // Create account that may NOT edit its own mail address. - $account = $this->drupalCreateUser(array('userprotect.account.edit')); + $account = $this->drupalCreateUser(['userprotect.account.edit']); $expected_mail = $account->getEmail(); $this->drupalLogin($account); - $edit = array( - 'mail' => $this->randomMachineName() . '@example.com', - ); - $this->userprotectPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); - - // Assert the mail address changed. - $account = entity_load('user', $account->id(), TRUE); - $this->assertEqual($expected_mail, $account->getEmail(), "The user's mail address was NOT changed."); + $this->drupalGet('user/' . $account->id() . '/edit'); + $this->assertSession()->fieldDisabled('mail'); } /** @@ -88,22 +82,22 @@ protected function testNoEditOwnMail() { * Tests if an user with the permission "userprotect.pass.edit" can edit its * own password. */ - protected function testEditOwnPass() { + public function testEditOwnPass() { // Create account that may edit its own password. - $account = $this->drupalCreateUser(array('userprotect.pass.edit', 'userprotect.account.edit')); + $account = $this->drupalCreateUser(['userprotect.pass.edit', 'userprotect.account.edit']); $this->drupalLogin($account); $new_pass = $this->randomMachineName(); - $edit = array( + $edit = [ 'current_pass' => $account->pass_raw, 'pass[pass1]' => $new_pass, 'pass[pass2]' => $new_pass, - ); + ]; $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); // Assert the password changed. - $account = entity_load('user', $account->id(), TRUE); - $account->pass_raw = $new_pass; + $account = $this->reloadEntity($account); + $account->passRaw = $new_pass; $this->drupalLogout(); $this->drupalLogin($account); } @@ -111,28 +105,18 @@ protected function testEditOwnPass() { /** * Tests edit password without permission "userprotect.pass.edit". * - * Tests if an user without the permission "userprotect.pass.edit" can not + * Tests if an user without the permission "userprotect.pass.edit" cannot * edit its own password. */ - protected function testNoEditOwnPass() { + public function testNoEditOwnPass() { // Create account that may NOT edit its own password. - $account = $this->drupalCreateUser(array('userprotect.account.edit')); + $account = $this->drupalCreateUser(['userprotect.account.edit']); $expected_pass = $account->pass_raw; $this->drupalLogin($account); - $new_pass = $this->randomMachineName(); - $edit = array( - 'current_pass' => $account->pass_raw, - 'pass[pass1]' => $new_pass, - 'pass[pass2]' => $new_pass, - ); - $this->userprotectPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); - - // Assert the password did not change. - $account = entity_load('user', $account->id(), TRUE); - $account->pass_raw = $expected_pass; - $this->drupalLogout(); - $this->drupalLogin($account); + $this->drupalGet('user/' . $account->id() . '/edit'); + $this->assertSession()->fieldNotExists('pass[pass1]'); + $this->assertSession()->fieldNotExists('pass[pass2]'); } /** @@ -141,9 +125,9 @@ protected function testNoEditOwnPass() { * Tests if an user with the permission "userprotect.account.edit" can edit * its own account. */ - protected function testEditOwnAccount() { + public function testEditOwnAccount() { // Create an account that may edit its own account. - $account = $this->drupalCreateUser(array('userprotect.account.edit')); + $account = $this->drupalCreateUser(['userprotect.account.edit']); $this->drupalLogin($account); // Assert the user can edit its own account. @@ -157,7 +141,7 @@ protected function testEditOwnAccount() { * Tests if an user without the permission "userprotect.account.edit" can * not edit its own account. */ - protected function testNoEditOwnAccount() { + public function testNoEditOwnAccount() { // Create an account that may NOT edit its own account. $account = $this->drupalCreateUser(); $this->drupalLogin($account); @@ -166,4 +150,5 @@ protected function testNoEditOwnAccount() { $this->drupalGet('user/' . $account->id() . '/edit'); $this->assertResponse(403, "The user may NOT edit its own account."); } + } diff --git a/web/modules/userprotect/tests/src/Functional/UserProtectionTest.php b/web/modules/userprotect/tests/src/Functional/UserProtectionTest.php new file mode 100644 index 0000000000000000000000000000000000000000..72edbfeea25a76416425b04fde1f120987ff996f --- /dev/null +++ b/web/modules/userprotect/tests/src/Functional/UserProtectionTest.php @@ -0,0 +1,95 @@ +<?php + +namespace Drupal\Tests\userprotect\Functional; + +/** + * Tests each UserProtection plugin in action. + * + * @group userprotect + * @todo Assert protection messages. + */ +class UserProtectionTest extends UserProtectBrowserTestBase { + + /** + * The operating account. + * + * @var \Drupal\user\UserInterface + */ + protected $account; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->account = $this->drupalCreateUser(['administer users', 'administer permissions']); + $this->drupalLogin($this->account); + } + + /** + * Tests if the user's name field has the expected protection. + */ + public function testNameProtection() { + $protected_account = $this->createProtectedUser(['user_name']); + + $this->drupalGet('user/' . $protected_account->id() . '/edit'); + $this->assertSession()->fieldNotExists('name'); + } + + /** + * Tests if the user's mail address field has the expected protection. + */ + public function testMailProtection() { + $protected_account = $this->createProtectedUser(['user_mail']); + + $this->drupalGet('user/' . $protected_account->id() . '/edit'); + $this->assertSession()->fieldDisabled('mail'); + } + + /** + * Tests if the user's password field has the expected protection. + */ + public function testPassProtection() { + $protected_account = $this->createProtectedUser(['user_pass']); + + $this->drupalGet('user/' . $protected_account->id() . '/edit'); + $this->assertSession()->fieldNotExists('pass[pass1]'); + $this->assertSession()->fieldNotExists('pass[pass2]'); + } + + /** + * Tests if the user's status field has the expected protection. + */ + public function testStatusProtection() { + $protected_account = $this->createProtectedUser(['user_status']); + + $this->drupalGet('user/' . $protected_account->id() . '/edit'); + $this->assertSession()->fieldNotExists('status'); + } + + /** + * Tests if the user's roles field has the expected protection. + */ + public function testRolesProtection() { + $protected_account = $this->createProtectedUser(['user_roles']); + + // Add a role to the protected account. + $rid1 = $this->drupalCreateRole([]); + $protected_account->addRole($rid1); + $protected_account->save(); + + // Add another role. We try to add this role to the user form later. + $rid2 = $this->drupalCreateRole([]); + + // Reload the user and check its roles. + $protected_account = $this->reloadEntity($protected_account); + // Assert the protected account's roles. + $this->assertTrue($protected_account->hasRole($rid1)); + $this->assertFalse($protected_account->hasRole($rid2)); + + // Ensure a checkbox for the second role is not available. + $this->assertSession()->fieldNotExists(sprintf('roles[%s]', $rid2)); + } + +} diff --git a/web/modules/userprotect/src/Tests/Entity/ProtectionRuleUnitTest.php b/web/modules/userprotect/tests/src/Kernel/Entity/ProtectionRuleUnitTest.php similarity index 66% rename from web/modules/userprotect/src/Tests/Entity/ProtectionRuleUnitTest.php rename to web/modules/userprotect/tests/src/Kernel/Entity/ProtectionRuleUnitTest.php index aee4ee1010b2282ea5907538611a49aba4e13445..8a9f599b65a0cc33c457971750f4790eaad369cb 100644 --- a/web/modules/userprotect/src/Tests/Entity/ProtectionRuleUnitTest.php +++ b/web/modules/userprotect/tests/src/Kernel/Entity/ProtectionRuleUnitTest.php @@ -1,21 +1,28 @@ <?php -namespace Drupal\userprotect\Tests\Entity; +namespace Drupal\Tests\userprotect\Kernel\Entity; +use Drupal\user\Entity\User; use Drupal\Core\Session\UserSession; +use Drupal\userprotect\Entity\ProtectionRule; use Drupal\userprotect\Entity\ProtectionRuleInterface; use Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface; use Drupal\userprotect\UserProtect; use Drupal\userprotect\Plugin\UserProtection\UserProtectionPluginCollection; -use Drupal\simpletest\KernelTestBase; +use Drupal\KernelTests\KernelTestBase; /** - * \Drupal\userprotect\Entity\ProtectionRule unit test. + * Various unit tests for protection rules. * * @group userprotect */ class ProtectionRuleUnitTest extends KernelTestBase { + /** + * {@inheritdoc} + */ + public static $modules = ['user', 'userprotect', 'field']; + /** * The user protection plugin manager. * @@ -23,11 +30,6 @@ class ProtectionRuleUnitTest extends KernelTestBase { */ protected $manager; - /** - * {@inheritdoc} - */ - public static $modules = array('user', 'userprotect', 'field'); - /** * The protection rule to test on. * @@ -41,98 +43,98 @@ class ProtectionRuleUnitTest extends KernelTestBase { protected function setUp() { parent::setUp(); $this->manager = UserProtect::pluginManager(); - $this->protectionRule = entity_create('userprotect_rule', array( + $this->protectionRule = ProtectionRule::create([ 'name' => 'dummy', 'label' => 'Dummy', - 'protections' => array( - 'user_mail' => array( + 'protections' => [ + 'user_mail' => [ 'status' => TRUE, - ), - ), + ], + ], 'protectedEntityTypeId' => 'user_role', 'protectedEntityId' => 'administrator', - )); + ]); } /** * Tests id(). */ - protected function testId() { + public function testId() { $this->assertIdentical('dummy', $this->protectionRule->id()); } /** * Tests setProtectedEntityTypeId() and getProtectedEntityTypeId(). */ - protected function testProtectedEntityTypeId() { + public function testProtectedEntityTypeId() { $this->assertIdentical('user_role', $this->protectionRule->getProtectedEntityTypeId()); $entity_type = 'user'; - $this->assertTrue($this->protectionRule->setProtectedEntityTypeId($entity_type) instanceof ProtectionRuleInterface); + $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->setProtectedEntityTypeId($entity_type)); $this->assertIdentical($entity_type, $this->protectionRule->getProtectedEntityTypeId()); } /** * Tests setProtectedEntityId() and getProtectedEntityId(). */ - protected function testProtectedEntityId() { + public function testProtectedEntityId() { $this->assertIdentical('administrator', $this->protectionRule->getProtectedEntityId()); $entity_id = 'authenticated'; - $this->assertTrue($this->protectionRule->setProtectedEntityId($entity_id) instanceof ProtectionRuleInterface); + $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->setProtectedEntityId($entity_id)); $this->assertIdentical($entity_id, $this->protectionRule->getProtectedEntityId()); } /** * Tests setBypassRoles() and getBypassRoles(). */ - protected function testBypassRoles() { - $this->assertIdentical(array(), $this->protectionRule->getBypassRoles()); - $roles = array('administrator'); - $this->assertTrue($this->protectionRule->setBypassRoles($roles) instanceof ProtectionRuleInterface); + public function testBypassRoles() { + $this->assertIdentical([], $this->protectionRule->getBypassRoles()); + $roles = ['administrator']; + $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->setBypassRoles($roles)); $this->assertIdentical($roles, $this->protectionRule->getBypassRoles()); } /** * Tests getProtection(). */ - protected function testGetProtection() { - $this->assertTrue($this->protectionRule->getProtection('user_mail') instanceof UserProtectionInterface); + public function testGetProtection() { + $this->assertInstanceOf(UserProtectionInterface::class, $this->protectionRule->getProtection('user_mail')); } /** * Tests getProtections(). */ - protected function testGetProtections() { - $this->assertTrue($this->protectionRule->getProtections() instanceof UserProtectionPluginCollection); + public function testGetProtections() { + $this->assertInstanceOf(UserProtectionPluginCollection::class, $this->protectionRule->getProtections()); } /** * Tests enableProtection(). */ - protected function testEnableProtection() { - $this->assertTrue($this->protectionRule->enableProtection('user_name') instanceof ProtectionRuleInterface); + public function testEnableProtection() { + $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->enableProtection('user_name')); $this->assertTrue($this->protectionRule->hasProtection('user_name')); } /** * Tests disableProtection(). */ - protected function testDisableProtection() { - $this->assertTrue($this->protectionRule->disableProtection('user_mail') instanceof ProtectionRuleInterface); + public function testDisableProtection() { + $this->assertInstanceOf(ProtectionRuleInterface::class, $this->protectionRule->disableProtection('user_mail')); $this->assertFalse($this->protectionRule->hasProtection('user_mail')); } /** * Tests toArray(). */ - protected function testToArray() { + public function testToArray() { $array = $this->protectionRule->toArray(); $this->assertIdentical('dummy', $array['name']); $this->assertIdentical('Dummy', $array['label']); - $expected_protections = array( - 'user_mail' => array( + $expected_protections = [ + 'user_mail' => [ 'status' => TRUE, - ), - ); + ], + ]; $this->assertIdentical($expected_protections, $array['protections']); $this->assertIdentical('user_role', $array['protectedEntityTypeId']); $this->assertIdentical('administrator', $array['protectedEntityId']); @@ -141,30 +143,30 @@ protected function testToArray() { /** * Tests getPermissionName(). */ - protected function testGetPermissionName() { + public function testGetPermissionName() { $this->assertIdentical('userprotect.dummy.bypass', $this->protectionRule->getPermissionName()); } /** * Tests appliesTo(). */ - protected function testAppliesTo() { + public function testAppliesTo() { // Create an user with administrator role. - $values = array( + $values = [ 'uid' => 3, 'name' => 'lorem', - 'roles' => array( + 'roles' => [ 'administrator', - ), - ); - $lorem = entity_create('user', $values); + ], + ]; + $lorem = User::create($values); // Create an authenticated user. - $values = array( + $values = [ 'uid' => 4, 'name' => 'ipsum', - ); - $ipsum = entity_create('user', $values); + ]; + $ipsum = User::create($values); // Assert that the protection rule applies to the user with the // administrator role and not to the authenticated user. @@ -172,17 +174,17 @@ protected function testAppliesTo() { $this->assertFalse($this->protectionRule->appliesTo($ipsum)); // Create an user based protection rule. - $user_protection_rule = entity_create('userprotect_rule', array( + $user_protection_rule = ProtectionRule::create([ 'name' => 'dummy', 'label' => 'Dummy', - 'protections' => array( - 'user_mail' => array( + 'protections' => [ + 'user_mail' => [ 'status' => TRUE, - ), - ), + ], + ], 'protectedEntityTypeId' => 'user', 'protectedEntityId' => 4, - )); + ]); // Assert that the protection rule applies to "ipsum", but no to "lorem". $this->assertFalse($user_protection_rule->appliesTo($lorem)); @@ -192,7 +194,7 @@ protected function testAppliesTo() { /** * Tests hasProtection(). */ - protected function testHasProtection() { + public function testHasProtection() { // The protection rule was created with only the protection "user_mail" // enabled. $this->assertTrue($this->protectionRule->hasProtection('user_mail')); @@ -203,23 +205,23 @@ protected function testHasProtection() { /** * Tests isProtected(). */ - protected function testIsProtected() { + public function testIsProtected() { // Create an user with administrator role. - $values = array( + $values = [ 'uid' => 3, 'name' => 'lorem', - 'roles' => array( + 'roles' => [ 'administrator', - ), - ); - $lorem = entity_create('user', $values); + ], + ]; + $lorem = User::create($values); // Create an authenticated user. - $values = array( + $values = [ 'uid' => 4, 'name' => 'ipsum', - ); - $ipsum = entity_create('user', $values); + ]; + $ipsum = User::create($values); // Create an operating account. $account = new UserSession(); @@ -229,4 +231,5 @@ protected function testIsProtected() { $this->assertTrue($this->protectionRule->isProtected($lorem, 'user_mail', $account)); $this->assertFalse($this->protectionRule->isProtected($ipsum, 'user_mail', $account)); } + } diff --git a/web/modules/userprotect/src/Tests/FieldAccessWebTest.php b/web/modules/userprotect/tests/src/Kernel/FieldAccessTest.php similarity index 54% rename from web/modules/userprotect/src/Tests/FieldAccessWebTest.php rename to web/modules/userprotect/tests/src/Kernel/FieldAccessTest.php index 4ecd50ab08ae2ec6d4e430fefd009ee49fb401ab..1e132254a78648f2f524d4acb0df8e3c67e63781 100644 --- a/web/modules/userprotect/src/Tests/FieldAccessWebTest.php +++ b/web/modules/userprotect/tests/src/Kernel/FieldAccessTest.php @@ -1,24 +1,20 @@ <?php -namespace Drupal\userprotect\Tests; +namespace Drupal\Tests\userprotect\Kernel; /** * Tests field access for each UserProtection plugin that protects a field. * * @group userprotect */ -class FieldAccessWebTest extends UserProtectWebTestBase { - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); +class FieldAccessTest extends UserProtectKernelTestBase { /** - * The operating account. + * The user admin. * * @var \Drupal\user\UserInterface */ - protected $account; + protected $userAdmin; /** * {@inheritdoc} @@ -26,82 +22,87 @@ class FieldAccessWebTest extends UserProtectWebTestBase { protected function setUp() { parent::setUp(); - $this->account = $this->drupalCreateUser(array('administer users', 'administer permissions')); - $this->drupalLogin($this->account); + // Create an user who administer users. Explicitly set user ID to '2' + // because user 1 would have all permissions. + $perm = ['administer users', 'administer permissions']; + $this->userAdmin = $this->drupalCreateUser($perm, NULL, FALSE, [ + 'uid' => 2, + ]); } /** * Tests field access for the user's name. */ - protected function testNameAccess() { + public function testNameAccess() { // Create an account with no protection. The logged in user should have the // privileges to edit this account's name. $account = $this->drupalCreateUser(); - $this->assertTrue($account->name->access('edit', $this->account)); + $this->assertTrue($account->name->access('edit', $this->userAdmin), 'User admin can edit account name of non-protected user.'); // Create a protected account. The logged in user should NOT have the // privileges to edit this account's name. - $protected_account = $this->createProtectedUser(array('user_name')); - $this->assertFalse($protected_account->name->access('edit', $this->account)); + $protected_account = $this->createProtectedUser(['user_name']); + $this->assertFalse($protected_account->name->access('edit', $this->userAdmin), 'User admin cannot edit account name of protected user.'); } /** * Tests field access for the user's mail address. */ - protected function testMailAccess() { + public function testMailAccess() { // Create an account with no protection. The logged in user should have the // privileges to edit this account's mail address. $account = $this->drupalCreateUser(); - $this->assertTrue($account->mail->access('edit', $this->account)); + $this->assertTrue($account->mail->access('edit', $this->userAdmin), 'User admin can edit mail address of non-protected user.'); // Create a protected account. The logged in user should NOT have the // privileges to edit this account's mail address. - $protected_account = $this->createProtectedUser(array('user_mail')); - $this->assertFalse($protected_account->mail->access('edit', $this->account)); + $protected_account = $this->createProtectedUser(['user_mail']); + $this->assertFalse($protected_account->mail->access('edit', $this->userAdmin), 'User admin cannot edit mail address of protected user.'); } /** * Tests field access for the user's password. */ - protected function testPassAccess() { + public function testPassAccess() { // Create an account with no protection. The logged in user should have the // privileges to edit this account's password. $account = $this->drupalCreateUser(); - $this->assertTrue($account->pass->access('edit', $this->account)); + $this->assertTrue($account->pass->access('edit', $this->userAdmin), 'User admin can edit password of non-protected user.'); // Create a protected account. The logged in user should NOT have the // privileges to edit this account's password. - $protected_account = $this->createProtectedUser(array('user_pass')); - $this->assertFalse($protected_account->pass->access('edit', $this->account)); + $protected_account = $this->createProtectedUser(['user_pass']); + $this->assertFalse($protected_account->pass->access('edit', $this->userAdmin), 'User admin cannot edit password of protected user.'); } /** * Tests field access for the user's status. */ - protected function testStatusAccess() { + public function testStatusAccess() { // Create an account with no protection. The logged in user should have the // privileges to edit this account's status. $account = $this->drupalCreateUser(); - $this->assertTrue($account->status->access('edit', $this->account)); + $this->assertTrue($account->status->access('edit', $this->userAdmin), 'User admin can edit status of non-protected user.'); // Create a protected account. The logged in user should NOT have the // privileges to edit this account's status. - $protected_account = $this->createProtectedUser(array('user_status')); - $this->assertFalse($protected_account->status->access('edit', $this->account)); + $protected_account = $this->createProtectedUser(['user_status']); + $this->assertFalse($protected_account->status->access('edit', $this->userAdmin), 'User admin cannot edit status of protected user.'); } /** * Tests field access for the user's roles. */ - protected function testRolesAccess() { + public function testRolesAccess() { // Create an account with no protection. The logged in user should have the // privileges to edit this account's roles. $account = $this->drupalCreateUser(); - $this->assertTrue($account->roles->access('edit', $this->account)); + $this->assertTrue($account->roles->access('edit', $this->userAdmin), 'User admin can edit roles of non-protected user.'); // Create a protected account. The logged in user should NOT have the // privileges to edit this account's roles. - $protected_account = $this->createProtectedUser(array('user_roles')); - $this->assertFalse($protected_account->roles->access('edit', $this->account)); + $protected_account = $this->createProtectedUser(['user_roles']); + $this->assertFalse($protected_account->roles->access('edit', $this->userAdmin), 'User admin cannot edit roles of protected user.'); } + } diff --git a/web/modules/userprotect/tests/src/Kernel/ProtectedEntityDeleteTest.php b/web/modules/userprotect/tests/src/Kernel/ProtectedEntityDeleteTest.php new file mode 100644 index 0000000000000000000000000000000000000000..73731c9c6ded2e88be567049cc188754f69ddb6e --- /dev/null +++ b/web/modules/userprotect/tests/src/Kernel/ProtectedEntityDeleteTest.php @@ -0,0 +1,65 @@ +<?php + +namespace Drupal\Tests\userprotect\Kernel; + +/** + * Tests if protection rules are cleaned up upon entity deletion. + * + * @group userprotect + */ +class ProtectedEntityDeleteTest extends UserProtectKernelTestBase { + + /** + * Tests reaction upon user deletion. + * + * Tests if an user based protection rule is cleaned up when the protected + * user is deleted. + */ + public function testUserDelete() { + // Create a user. + $account = $this->drupalCreateUser(); + + // Protect this user. + $protection_rule = $this->createProtectionRule($account->id(), [], 'user'); + $protection_rule->save(); + + // Assert that the rule was saved. + $protection_rule = $this->reloadEntity($protection_rule); + $this->assertNotNull($protection_rule, 'The protection rule was saved.'); + + // Now delete the account. + $account->delete(); + + // Assert that the rule no longer exists. + $protection_rule = $this->reloadEntity($protection_rule); + $this->assertNull($protection_rule, 'The protection rule was deleted.'); + } + + /** + * Tests reaction upon role deletion. + * + * Tests if a role based protection rule is cleaned up when the protected + * role is deleted. + */ + public function testRoleDelete() { + // Create a role. + $rid = $this->drupalCreateRole([]); + + // Protect this role. + $protection_rule = $this->createProtectionRule($rid, [], 'user_role'); + $protection_rule->save(); + + // Assert that the rule was saved. + $protection_rule = $this->reloadEntity($protection_rule); + $this->assertNotNull($protection_rule, 'The protection rule was saved.'); + + // Now delete the role. + $role = \Drupal::entityTypeManager()->getStorage('user_role')->load($rid); + $role->delete(); + + // Assert that the rule no longer exists. + $protection_rule = $this->reloadEntity($protection_rule); + $this->assertNull($protection_rule, 'The protection rule was deleted.'); + } + +} diff --git a/web/modules/userprotect/src/Tests/ProtectionRuleBypassWebTest.php b/web/modules/userprotect/tests/src/Kernel/ProtectionRuleBypassTest.php similarity index 70% rename from web/modules/userprotect/src/Tests/ProtectionRuleBypassWebTest.php rename to web/modules/userprotect/tests/src/Kernel/ProtectionRuleBypassTest.php index 65880c0e3c96a2c3c6bcc0752b33e700eca18275..20eacbc6d7236fd8a5764d21d1610c0afedeaa77 100644 --- a/web/modules/userprotect/src/Tests/ProtectionRuleBypassWebTest.php +++ b/web/modules/userprotect/tests/src/Kernel/ProtectionRuleBypassTest.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\userprotect\Tests; +namespace Drupal\Tests\userprotect\Kernel; /** * Tests bypassing protection rules. @@ -8,12 +8,7 @@ * @group userprotect * @todo add bypass test for 'all' protection rules. */ -class ProtectionRuleBypassWebTest extends UserProtectWebTestBase { - - /** - * {@inheritdoc} - */ - public static $modules = array('userprotect'); +class ProtectionRuleBypassTest extends UserProtectKernelTestBase { /** * The user access controller. @@ -28,41 +23,41 @@ class ProtectionRuleBypassWebTest extends UserProtectWebTestBase { protected function setUp() { parent::setUp(); - $this->accessController = \Drupal::entityManager()->getAccessControlHandler('user'); + $this->accessController = \Drupal::entityTypeManager()->getAccessControlHandler('user'); } /** * Tests if bypassing role name edit protection is respected. */ - protected function testRoleNameEditProtectionBypass() { + public function testRoleNameEditProtectionBypass() { $this->doRoleProtectionBypassTest('user_name', 'user_name'); } /** * Tests if bypassing role mail edit protection is respected. */ - protected function testRoleMailEditProtectionBypass() { + public function testRoleMailEditProtectionBypass() { $this->doRoleProtectionBypassTest('user_mail', 'user_mail'); } /** * Tests if bypassing role password edit protection is respected. */ - protected function testRolePassEditProtectionBypass() { + public function testRolePassEditProtectionBypass() { $this->doRoleProtectionBypassTest('user_pass', 'user_pass'); } /** * Tests if bypassing role edit protection is respected. */ - protected function testRoleEditProtectionBypass() { + public function testRoleEditProtectionBypass() { $this->doRoleProtectionBypassTest('user_edit', 'update'); } /** * Tests if bypassing role delete protection is respected. */ - protected function testRoleDeleteProtectionBypass() { + public function testRoleDeleteProtectionBypass() { $this->doRoleProtectionBypassTest('user_delete', 'delete'); } @@ -76,51 +71,51 @@ protected function testRoleDeleteProtectionBypass() { */ protected function doRoleProtectionBypassTest($plugin, $operation) { // Create a protected role. - $rid = $this->createProtectedRole(array($plugin)); + $rid = $this->createProtectedRole([$plugin]); // Create an account with this protected role. $protected_account = $this->drupalCreateUser(); $protected_account->addRole($rid); // Create operating account. - $account = $this->drupalCreateUser(array('administer users', 'userprotect.dummy.bypass')); + $account = $this->drupalCreateUser(['administer users', 'userprotect.dummy.bypass']); // Test if account has the expected access. - $this->assertTrue($this->accessController->access($protected_account, $operation, NULL, $account)); + $this->assertTrue($this->accessController->access($protected_account, $operation, $account)); } /** * Tests if bypassing user name edit protection is respected. */ - protected function testUserNameEditProtectionBypass() { + public function testUserNameEditProtectionBypass() { $this->doUserProtectionBypassTest('user_name', 'user_name'); } /** * Tests if bypassing user mail edit protection is respected. */ - protected function testUserMailEditProtectionBypass() { + public function testUserMailEditProtectionBypass() { $this->doUserProtectionBypassTest('user_mail', 'user_mail'); } /** * Tests if bypassing user password edit protection is respected. */ - protected function testUserPassEditProtectionBypass() { + public function testUserPassEditProtectionBypass() { $this->doUserProtectionBypassTest('user_pass', 'user_pass'); } /** * Tests if bypassing user edit protection is respected. */ - protected function testUserEditProtectionBypass() { + public function testUserEditProtectionBypass() { $this->doUserProtectionBypassTest('user_edit', 'update'); } /** * Tests if bypassing user delete protection is respected. */ - protected function testUserDeleteProtectionBypass() { + public function testUserDeleteProtectionBypass() { $this->doUserProtectionBypassTest('user_delete', 'delete'); } @@ -134,12 +129,13 @@ protected function testUserDeleteProtectionBypass() { */ protected function doUserProtectionBypassTest($plugin, $operation) { // Create a protected user. - $protected_account = $this->createProtectedUser(array($plugin)); + $protected_account = $this->createProtectedUser([$plugin]); // Create operating account. - $account = $this->drupalCreateUser(array('administer users', 'userprotect.dummy.bypass')); + $account = $this->drupalCreateUser(['administer users', 'userprotect.dummy.bypass']); // Test if account has the expected access. - $this->assertTrue($this->accessController->access($protected_account, $operation, NULL, $account)); + $this->assertTrue($this->accessController->access($protected_account, $operation, $account)); } + } diff --git a/web/modules/userprotect/tests/src/Kernel/UserProtectKernelTestBase.php b/web/modules/userprotect/tests/src/Kernel/UserProtectKernelTestBase.php new file mode 100644 index 0000000000000000000000000000000000000000..b5b099fbf9ca844604b407fd58e47a2082b8343b --- /dev/null +++ b/web/modules/userprotect/tests/src/Kernel/UserProtectKernelTestBase.php @@ -0,0 +1,28 @@ +<?php + +namespace Drupal\Tests\userprotect\Kernel; + +use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; +use Drupal\Tests\userprotect\Traits\UserProtectCreationTrait; + +/** + * Provides a base class for User Protect kernel tests. + */ +abstract class UserProtectKernelTestBase extends EntityKernelTestBase { + + use UserProtectCreationTrait; + + /** + * {@inheritdoc} + */ + public static $modules = ['userprotect']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->installSchema('user', ['users_data']); + } + +} diff --git a/web/modules/userprotect/tests/src/Traits/UserProtectCreationTrait.php b/web/modules/userprotect/tests/src/Traits/UserProtectCreationTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..cbc6bbbd67f968a2b99bd43b8055c75a9af5ddb1 --- /dev/null +++ b/web/modules/userprotect/tests/src/Traits/UserProtectCreationTrait.php @@ -0,0 +1,122 @@ +<?php + +namespace Drupal\Tests\userprotect\Traits; + +use Drupal\userprotect\Entity\ProtectionRule; +use Drupal\userprotect\Entity\ProtectionRuleInterface; + +/** + * Provides methods to create protection rules. + * + * This trait is meant to be used only by test classes. + */ +trait UserProtectCreationTrait { + + /** + * Creates a protected role. + * + * @param array $protections + * (optional) The active protections. + * Defaults to an empty array. + * + * @return string + * The ID of the created role. + */ + protected function createProtectedRole(array $protections = []) { + // Create a role. + $rid = $this->drupalCreateRole([]); + + // Protect this role. + $protection_rule = $this->createProtectionRule($rid, $protections); + $protection_rule->save(); + // Reset available permissions. + drupal_static_reset('checkPermissions'); + + return $rid; + } + + /** + * Creates a protected user. + * + * @param array $protections + * (optional) The active protections. + * Defaults to an empty array. + * + * @return object + * The created user. + */ + protected function createProtectedUser(array $protections = []) { + // Create a user. + $account = $this->drupalCreateUser(); + + // Protect this user. + $protection_rule = $this->createProtectionRule($account->id(), $protections, 'user'); + $protection_rule->save(); + // Reset available permissions. + drupal_static_reset('checkPermissions'); + + return $account; + } + + /** + * Creates an user with a protected role. + * + * @param array $protections + * (optional) The active protections. + * Defaults to an empty array. + * + * @return object + * The created user. + */ + protected function createUserWithProtectedRole(array $protections = []) { + // Create a protected role. + $rid = $this->createProtectedRole($protections); + + // Create an account with this protected role. + $protected_account = $this->drupalCreateUser(); + $protected_account->addRole($rid); + $protected_account->save(); + + return $protected_account; + } + + /** + * Creates protection rule. + * + * @param int|string $entity_id + * The id of the entity to protect. + * @param array $protections + * (optional) The active protections. + * Defaults to an empty array. + * @param string $entity_type + * (optional) The protected entity type. + * Defaults to "user_role". + * @param array $values + * (optional) Extra values of the protection rule. + * + * @return \Drupal\userprotect\Entity\ProtectionRuleInterface + * An instance of ProtectionRuleInterface. + */ + protected function createProtectionRule($entity_id, array $protections = [], $entity_type = 'user_role', array $values = []) { + // Setup default values. + $values += [ + 'name' => 'dummy', + 'label' => 'Dummy', + 'protections' => [], + 'protectedEntityTypeId' => $entity_type, + 'protectedEntityId' => $entity_id, + ]; + // Define protections. + foreach ($protections as $key) { + $values['protections'][$key] = [ + 'status' => TRUE, + ]; + } + + // Create protection rule. + $protection_rule = ProtectionRule::create($values); + $this->assertInstanceOf(ProtectionRuleInterface::class, $protection_rule); + return $protection_rule; + } + +} diff --git a/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php b/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php index d1ae1fae5b66c7f2960aefdfc1ac76bad24d27b0..904fc1dac84199e58947911d6570235dc804e536 100644 --- a/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php +++ b/web/modules/userprotect/tests/src/Unit/Plugin/UserProtection/UserProtectionBaseUnitTest.php @@ -29,13 +29,13 @@ class UserProtectionBaseUnitTest extends UnitTestCase { * * @var array */ - protected $pluginDefinition = array( + protected $pluginDefinition = [ 'id' => 'dummy', 'label' => 'Dummy', 'description' => 'This is a dummy plugin definition.', 'provider' => '', 'status' => FALSE, - ); + ]; /** * {@inheritdoc} @@ -43,16 +43,16 @@ class UserProtectionBaseUnitTest extends UnitTestCase { public function setUp() { parent::setUp(); - $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface'); + $this->moduleHandler = $this->createMock('\Drupal\Core\Extension\ModuleHandlerInterface'); $this->plugin = $this->getMockBuilder('\Drupal\userprotect\Plugin\UserProtection\UserProtectionBase') - ->setConstructorArgs(array( - array(), + ->setConstructorArgs([ + [], '', $this->pluginDefinition, $this->moduleHandler, - )) - ->setMethods(array('t')) + ]) + ->setMethods(['t']) ->getMock(); $this->plugin->expects($this->any()) ->method('t') @@ -78,9 +78,9 @@ public function testDescription() { * @covers ::getConfiguration */ public function testGetConfiguration() { - $configuration = array( + $configuration = [ 'status' => TRUE, - ); + ]; $this->assertInstanceOf('\Drupal\userprotect\Plugin\UserProtection\UserProtectionInterface', $this->plugin->setConfiguration($configuration)); $saved_configuration = $this->plugin->getConfiguration(); $this->assertSame($configuration['status'], $saved_configuration['status']); @@ -92,4 +92,5 @@ public function testGetConfiguration() { public function testDefaultConfiguration() { $this->assertInternalType('array', $this->plugin->defaultConfiguration()); } + } diff --git a/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php b/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php index 14d65d21f41ac5f8239240221e4e3abb507f3f00..c871a628e71f48d89fd53fd845d91e1867a131c0 100644 --- a/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php +++ b/web/modules/userprotect/tests/src/Unit/UserProtectUnitTest.php @@ -17,9 +17,10 @@ class UserProtectUnitTest extends UnitTestCase { */ public function testPluginManager() { $container = new Container(); - $plugin_manager = $this->getMock('\Drupal\Component\Plugin\PluginManagerInterface'); + $plugin_manager = $this->createMock('\Drupal\Component\Plugin\PluginManagerInterface'); $container->set('plugin.manager.userprotect.user_protection', $plugin_manager); \Drupal::setContainer($container); $this->assertSame($plugin_manager, UserProtect::pluginManager()); } + } diff --git a/web/modules/userprotect/userprotect.info.yml b/web/modules/userprotect/userprotect.info.yml index b42cf5ea8fd817d52974a366ef4dc929cf17e7c8..e384e9eadd9f90e4a962a33253af2fd5f86abe1f 100644 --- a/web/modules/userprotect/userprotect.info.yml +++ b/web/modules/userprotect/userprotect.info.yml @@ -1,13 +1,14 @@ -name: User protect +name: User Protect type: module description: 'Allows admins to protect users from being edited or cancelled, on a per-user basis.' -# core: 8.x +core: 8.x +core_version_requirement: ^8 || ^9 configure: userprotect.rule_list dependencies: - - user + - drupal:system (>=8.7.0) + - drupal:user -# Information added by Drupal.org packaging script on 2016-10-29 -version: '8.x-1.0' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-01-06 +version: '8.x-1.1' project: 'userprotect' -datestamp: 1477741140 +datestamp: 1578341587 diff --git a/web/modules/userprotect/userprotect.install b/web/modules/userprotect/userprotect.install index 45e7aaf037d3f9a63b59c6225b1c37e07cb7e139..a4a2c463ee75e90f9cb751aadc14a9101651c4b5 100644 --- a/web/modules/userprotect/userprotect.install +++ b/web/modules/userprotect/userprotect.install @@ -5,13 +5,15 @@ * Install, update and uninstall functions for the userprotect module. */ +use Drupal\Core\Session\AccountInterface; + /** * Implements hook_install(). * * Installs default userprotect permissions for authenticated users. */ function userprotect_install() { - $role = entity_load('user_role', DRUPAL_AUTHENTICATED_RID); + $role = \Drupal::entityTypeManager()->getStorage('user_role')->load(AccountInterface::AUTHENTICATED_ROLE); $role->grantPermission('userprotect.mail.edit'); $role->grantPermission('userprotect.pass.edit'); $role->grantPermission('userprotect.account.edit'); diff --git a/web/modules/userprotect/userprotect.module b/web/modules/userprotect/userprotect.module index 6902b869342ad4b6cb9a85c94b05bf96a94b4518..72d069c5d34c6f8011a8338d5da4dae18662411e 100644 --- a/web/modules/userprotect/userprotect.module +++ b/web/modules/userprotect/userprotect.module @@ -2,8 +2,7 @@ /** * @file - * Allows admins to protect users from being edited or cancelled, on a per-user - * basis. + * Allows admins to protect users from being edited or cancelled. */ use Drupal\Core\Access\AccessResult; @@ -23,14 +22,11 @@ * An instance of an userprotect_rule entity. */ function userprotect_rule_load($name) { - return entity_load('userprotect_rule', $name); + return \Drupal::entityTypeManager()->getStorage('userprotect_rule')->load($name); } /** * Implements hook_ENTITY_TYPE_access() for entity type "user". - * - * @param \Drupal\user\UserInterface $entity - * The user object to check access for. */ function userprotect_user_access(UserInterface $entity, $op, AccountInterface $account) { // Check if the account has the permission "userprotect.bypass_all". @@ -118,8 +114,8 @@ function userprotect_user_access(UserInterface $entity, $op, AccountInterface $a */ function userprotect_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemList $items = NULL) { if (is_null($items)) { - // Sometimes no field item list is passed. In this case, there is nothing for - // userprotect to check. + // Sometimes no field item list is passed. In this case, there is nothing + // for userprotect to check. return AccessResult::neutral(); } @@ -152,6 +148,11 @@ function userprotect_entity_field_access($operation, FieldDefinitionInterface $f // userprotect_user_access(). $entity_operation = 'user_' . $name; return ($entity->access($entity_operation, $account)) ? AccessResult::neutral() : AccessResult::forbidden(); + + // Make sure this module also works when role_delegation is enabled. + case 'role_change': + $entity_operation = 'user_roles'; + return ($entity->access($entity_operation, $account)) ? AccessResult::neutral() : AccessResult::forbidden(); } // The field is not one of the fields that userprotect supports. @@ -171,7 +172,9 @@ function userprotect_user_delete($account) { ->execute(); // Delete protection rules. if (!empty($entity_ids)) { - entity_delete_multiple('userprotect_rule', $entity_ids); + $storage_handler = \Drupal::entityTypeManager()->getStorage('userprotect_rule'); + $entities = $storage_handler->loadMultiple($entity_ids); + $storage_handler->delete($entities); } } @@ -188,7 +191,9 @@ function userprotect_user_role_delete($role) { ->execute(); // Delete protection rules. if (!empty($entity_ids)) { - entity_delete_multiple('userprotect_rule', $entity_ids); + $storage_handler = \Drupal::entityTypeManager()->getStorage('userprotect_rule'); + $entities = $storage_handler->loadMultiple($entity_ids); + $storage_handler->delete($entities); } } @@ -214,7 +219,7 @@ function userprotect_form_user_form_alter(&$form, &$form_state) { // For each protection plugin, check if the current user has access // to the element the plugin protects. If not, apply the protection. - $applied = array(); + $applied = []; foreach ($protection_definitions as $protection_definition) { if (!$entity->access($protection_definition['id'], $account)) { // Apply protection. @@ -229,11 +234,11 @@ function userprotect_form_user_form_alter(&$form, &$form_state) { // Display a message about the applied protections if there were protections // applied and if the current user is an admin user. if (count($applied) && $account->hasPermission('administer users')) { - $message = t('%user has been protected from the following editing operations: @operations', array( - '%user' => $entity->getUsername(), + $message = t('%user has been protected from the following editing operations: @operations', [ + '%user' => $entity->getAccountName(), '@operations' => implode(', ', $applied), - )); - drupal_set_message($message); + ]); + \Drupal::messenger()->addMessage($message); } } @@ -261,5 +266,5 @@ function userprotect_get_user_protection_rules(UserInterface $account) { $entity_ids = $query ->condition($group) ->execute(); - return entity_load_multiple('userprotect_rule', $entity_ids); + return \Drupal::entityTypeManager()->getStorage('userprotect_rule')->loadMultiple($entity_ids); } diff --git a/web/modules/userprotect/userprotect.services.yml b/web/modules/userprotect/userprotect.services.yml index cd707c3f77769cb3da3e931e1605df6cd37145dc..0d689587e4dc9e55b7e87b3164c9718e3e8cc6e6 100644 --- a/web/modules/userprotect/userprotect.services.yml +++ b/web/modules/userprotect/userprotect.services.yml @@ -2,3 +2,11 @@ services: plugin.manager.userprotect.user_protection: class: Drupal\userprotect\Plugin\UserProtection\UserProtectionManager parent: default_plugin_manager + userprotect.route_subscriber: + class: Drupal\userprotect\Routing\RouteSubscriber + tags: + - { name: event_subscriber } + access_check.user_protect.role_access: + class: Drupal\userprotect\Access\UserProtectRoleAccessCheck + tags: + - { name: access_check, applies_to: _userprotect_role_access_check }