diff --git a/oe_authentication.services.yml b/oe_authentication.services.yml index a003bb9..1c84676 100644 --- a/oe_authentication.services.yml +++ b/oe_authentication.services.yml @@ -12,4 +12,9 @@ services: class: \Drupal\oe_authentication\Event\EuLoginEventSubscriber tags: - { name: event_subscriber } - arguments: ['@config.factory', '@messenger'] + arguments: ['@config.factory'] + oe_authentication.messenger.event_subscriber: + class: \Drupal\oe_authentication\Event\MessengerEuLoginEventSubscriber + tags: + - { name: event_subscriber } + arguments: ['@messenger'] diff --git a/src/CasProcessor.php b/src/CasProcessor.php index 6e87c91..e83e02b 100644 --- a/src/CasProcessor.php +++ b/src/CasProcessor.php @@ -49,21 +49,21 @@ public static function convertCasAttributesToFieldValues(array $attributes): arr * An array containing the parsed attributes. */ public static function processValidationResponseAttributes(string $source): array { - if (!CasProcessor::isValidResponse($source)) { + if (!static::isValidResponse($source)) { throw new \InvalidArgumentException(); } // Load cas attributes. $dom = new \DOMDocument(); $dom->preserveWhiteSpace = FALSE; - $dom->encoding = "utf-8"; + $dom->encoding = 'utf-8'; @$dom->loadXML($source); - $success_elements = $dom->getElementsByTagName("authenticationSuccess"); + $success_elements = $dom->getElementsByTagName('authenticationSuccess'); // There should only be one success element, grab it and extract username. $success_element = $success_elements->item(0); // Parse the attributes coming from Eu Login // and add them to the default ones. - $eulogin_attributes = CasProcessor::parseAttributes($success_element); + $eulogin_attributes = static::parseAttributes($success_element); return $eulogin_attributes; } @@ -72,26 +72,60 @@ public static function processValidationResponseAttributes(string $source): arra * * @param \DOMElement $node * An XML element containing attributes. + * @param bool $toplevel + * Whether the method is called from out of the recursive loop. * * @return array - * An associative array of attributes. + * An array of attributes. */ - private static function parseAttributes(\DOMElement $node): array { + protected static function parseAttributes(\DOMElement $node, bool $toplevel = TRUE): array { + // Check if we can return an associative array or if + // we must use numeric keys. + $associative = $toplevel || static::isAssociative($node); + $attributes = []; // @var \DOMElement $child - foreach ($node->childNodes as $child) { + foreach ($node->childNodes as $key => $child) { $name = $child->localName; + // If the child has sub-levels, recursively parse the attributes + // underneath. if ($child->hasAttribute('number')) { - $value = CasProcessor::parseAttributes($child); + $value = static::parseAttributes($child, FALSE); } else { $value = $child->nodeValue; } - $attributes[$name] = $value; + + if ($associative) { + $attributes[$name] = $value; + } + else { + $attributes[] = $value; + } + } return $attributes; } + /** + * Checks if the node children can be represented as an associative array. + * + * Array can be associative if it will get different names for all keys. + * + * @param \DOMElement $node + * The node element. + * + * @return bool + * Whether the node children should be mapped to an associated array. + */ + protected static function isAssociative(\DOMElement $node): bool { + $names = $counter = []; + foreach ($node->childNodes as $child) { + $names[$child->localName] = $counter[] = $child->localName; + } + return count($names) === count($counter); + } + /** * Check whether the validation response is valid or not. * @@ -104,7 +138,7 @@ private static function parseAttributes(\DOMElement $node): array { public static function isValidResponse(string $response) { $dom = new \DOMDocument(); $dom->preserveWhiteSpace = FALSE; - $dom->encoding = "utf-8"; + $dom->encoding = 'utf-8'; // Suppress errors from this function, as we intend to allow other // event subscribers to work on the data. @@ -112,7 +146,7 @@ public static function isValidResponse(string $response) { return FALSE; } - $success_elements = $dom->getElementsByTagName("authenticationSuccess"); + $success_elements = $dom->getElementsByTagName('authenticationSuccess'); return $success_elements->length !== 0; } diff --git a/src/Event/EuLoginEventSubscriber.php b/src/Event/EuLoginEventSubscriber.php index 1a354c7..b5def25 100644 --- a/src/Event/EuLoginEventSubscriber.php +++ b/src/Event/EuLoginEventSubscriber.php @@ -10,7 +10,6 @@ use Drupal\cas\Event\CasPreValidateEvent; use Drupal\cas\Service\CasHelper; use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -45,12 +44,9 @@ class EuLoginEventSubscriber implements EventSubscriberInterface { * * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory * The config factory. - * @param \Drupal\Core\Messenger\MessengerInterface $messenger - * The messenger. */ - public function __construct(ConfigFactoryInterface $configFactory, MessengerInterface $messenger) { + public function __construct(ConfigFactoryInterface $configFactory) { $this->configFactory = $configFactory; - $this->messenger = $messenger; } /** @@ -111,7 +107,6 @@ public function processUserProperties(CasPreRegisterEvent $event): void { $user_settings = $this->configFactory->get('user.settings'); if ($user_settings->get('register') === USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) { $event->setPropertyValue('status', 0); - $this->messenger->addStatus($this->t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.')); } } @@ -145,6 +140,7 @@ public function alterValidationPath(CasPreValidateEvent $event): void { 'assuranceLevel' => $config->get('assurance_level'), 'ticketTypes' => $config->get('ticket_types'), 'userDetails' => 'true', + 'groups' => '*', ]; $event->addParameters($params); } diff --git a/src/Event/MessengerEuLoginEventSubscriber.php b/src/Event/MessengerEuLoginEventSubscriber.php new file mode 100644 index 0000000..cda471e --- /dev/null +++ b/src/Event/MessengerEuLoginEventSubscriber.php @@ -0,0 +1,70 @@ +messenger = $messenger; + } + + /** + * Returns an array of event names this subscriber wants to listen to. + * + * @return array + * The event names to listen to. + */ + public static function getSubscribedEvents(): array { + $events = []; + $events[CasHelper::EVENT_PRE_REGISTER] = ['showUserMessage', -100]; + return $events; + } + + /** + * Show user message about its activation status. + * + * @param \Drupal\cas\Event\CasPreRegisterEvent $event + * The triggered event. + */ + public function showUserMessage(CasPreRegisterEvent $event): void { + $properties = $event->getPropertyValues(); + + if (!isset($properties['status'])) { + return; + } + + if (!$properties['status']) { + $this->messenger->addStatus($this->t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.')); + } + } + +}