oidc-1.0.0-alpha2/src/EventSubscriber/UpdateUserSubscriber.php
src/EventSubscriber/UpdateUserSubscriber.php
<?php
namespace Drupal\oidc\EventSubscriber;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\externalauth\Event\ExternalAuthEvents;
use Drupal\externalauth\Event\ExternalAuthLoginEvent;
use Drupal\oidc\OpenidConnectSessionInterface;
use Drupal\user\UserInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Event subscriber to update the synced user fields on login.
*/
class UpdateUserSubscriber implements EventSubscriberInterface {
/**
* The OpenID Connect session service.
*
* @var \Drupal\oidc\OpenidConnectSessionInterface
*/
protected $session;
/**
* The user storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $userStorage;
/**
* Class constructor.
*
* @param \Drupal\oidc\OpenidConnectSessionInterface $session
* The OpenID Connect session service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function __construct(OpenidConnectSessionInterface $session, EntityTypeManagerInterface $entity_type_manager) {
$this->session = $session;
$this->userStorage = $entity_type_manager->getStorage('user');
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[ExternalAuthEvents::LOGIN][] = ['onLogin', 1000];
return $events;
}
/**
* Updates the synced user fields on login.
*
* @param \Drupal\externalauth\Event\ExternalAuthLoginEvent $event
* The login event.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function onLogin(ExternalAuthLoginEvent $event) {
// The provider must match the realm.
$plugin_id = $this->session->getRealmPluginId();
$provider = 'oidc:' . $this->session->getRealmPluginId();
if (!$plugin_id || $provider !== $event->getProvider()) {
return;
}
$tokens = $this->session->getJsonWebTokens();
$account = $event->getAccount();
$save = FALSE;
// Update the username.
$username = $tokens->getUsername();
if ($username !== NULL) {
$username = mb_substr($username, 0, UserInterface::USERNAME_MAX_LENGTH);
$account_name = $account->getAccountName();
if ($username !== $account_name) {
$regex = mb_substr($username, 0, UserInterface::USERNAME_MAX_LENGTH - 2);
$regex = '#^' . preg_quote($regex, '#') . '_\d$#';
if (!preg_match($regex, $account_name)) {
$username = $this->generateUsername($username);
if ($username !== NULL) {
$account->setUsername($username);
$save = TRUE;
}
}
}
}
// Update the email address.
$email = $tokens->getEmail();
if ($email !== NULL && $email !== $account->getEmail()) {
$account->setEmail($email);
$save = TRUE;
}
// Update the given name.
$given_name = $tokens->getGivenName();
if ($given_name !== NULL && $given_name !== $account->get('given_name')->value) {
$account->set('given_name', $given_name);
$save = TRUE;
}
// Update the family name.
$family_name = $tokens->getFamilyName();
if ($family_name !== NULL && $family_name !== $account->get('family_name')->value) {
$account->set('family_name', $family_name);
$save = TRUE;
}
// Save the changes.
if ($save) {
$account->save();
}
}
/**
* Try to generate a unique username.
*
* @param string $base
* The string to use as base.
*
* @return string|null
* The username or null if no unique username could be generated.
*/
protected function generateUsername($base) {
// Check if $base exists, otherwise just use that.
$count = $this->userStorage->getQuery()
->count()
->condition('name', $base)
->accessCheck(FALSE)
->execute();
if (!$count) {
return $base;
}
// Try suffix "_1" until "_9".
$base = mb_substr($base, 0, UserInterface::USERNAME_MAX_LENGTH - 2);
for ($index = 1; $index <= 9; $index++) {
$name = $base . '_' . $index;
$count = $this->userStorage->getQuery()
->count()
->condition('name', $name)
->accessCheck(FALSE)
->execute();
if (!$count) {
return $name;
}
}
return NULL;
}
}
