public function UserSyncEventSubscriber::onUserSync in SAML Authentication 8.2
Same name and namespace in other branches
- 8.3 src/EventSubscriber/UserSyncEventSubscriber.php \Drupal\samlauth\EventSubscriber\UserSyncEventSubscriber::onUserSync()
- 4.x src/EventSubscriber/UserSyncEventSubscriber.php \Drupal\samlauth\EventSubscriber\UserSyncEventSubscriber::onUserSync()
Performs actions to synchronize users with Factory data on login.
Parameters
\Drupal\samlauth\Event\SamlauthUserSyncEvent $event: The event.
File
- src/
EventSubscriber/ UserSyncEventSubscriber.php, line 97
Class
- UserSyncEventSubscriber
- Event subscriber that synchronizes user properties on a user_sync event.
Namespace
Drupal\samlauth\EventSubscriberCode
public function onUserSync(SamlauthUserSyncEvent $event) {
// If the account is new, we are in the middle of a user save operation;
// the current user name is 'samlauth_AUTHNAME' (as set by externalauth) and
// e-mail is not set yet.
$account = $event
->getAccount();
$fatal_errors = [];
// Synchronize username.
if ($account
->isNew() || $this->config
->get('sync_name')) {
// Get value from the SAML attribute whose name is configured in the
// samlauth module.
$name = $this
->getAttributeByConfig('user_name_attribute', $event);
if ($name && $name != $account
->getAccountName()) {
// Validate the username. This shouldn't be necessary to mitigate
// attacks; assuming our SAML setup is correct, noone can insert fake
// data here. It protects against SAML attribute misconfigurations.
// Invalid names will cancel the login / account creation. The code is
// copied from user_validate_name().
$definition = BaseFieldDefinition::create('string')
->addConstraint('UserName', []);
$data = \Drupal::typedDataManager()
->create($definition);
$data
->setValue($name);
$violations = $data
->validate();
if ($violations) {
foreach ($violations as $violation) {
$fatal_errors[] = $violation
->getMessage();
}
}
// Check if the username is not already taken by someone else. For new
// accounts this can happen if the 'map existing users' setting is off.
if (!$fatal_errors) {
$account_search = $this->entityTypeManager
->getStorage('user')
->loadByProperties(array(
'name' => $name,
));
$existing_account = reset($account_search);
if (!$existing_account || $account
->id() == $existing_account
->id()) {
$account
->setUsername($name);
$event
->markAccountChanged();
}
else {
$error = 'An account with the username @username already exists.';
if ($account
->isNew()) {
$fatal_errors[] = t($error, [
'@username' => $name,
]);
}
else {
// We continue and keep the old name. A DSM should be OK here
// since login only happens interactively. (And we're ignoring
// the law of dependency injection for this.)
$error = "Error updating user name from SAML attribute: {$error}";
$this->logger
->error($error, [
'@username' => $name,
]);
drupal_set_message(t($error, [
'@username' => $name,
]), 'error');
}
}
}
}
}
// Synchronize e-mail.
if ($account
->isNew() || $this->config
->get('sync_mail')) {
$mail = $this
->getAttributeByConfig('user_mail_attribute', $event);
if ($mail) {
if ($mail != $account
->getEmail()) {
// Invalid e-mail cancels the login / account creation just like name.
if ($this->emailValidator
->isValid($mail)) {
$account
->setEmail($mail);
if ($account
->isNew()) {
// externalauth sets init to a non e-mail value so we will fix it.
$account
->set('init', $mail);
}
$event
->markAccountChanged();
}
else {
$fatal_errors[] = t('Invalid e-mail address @mail', [
'@mail' => $mail,
]);
}
}
}
elseif ($account
->isNew()) {
// We won't allow new accounts with empty e-mail.
$fatal_errors[] = t('Email address is not provided in SAML attribute.');
}
}
if ($fatal_errors) {
// Cancel the whole login process and/or account creation.
throw new \RuntimeException('Error(s) encountered during SAML attribute synchronization: ' . join(' // ', $fatal_errors));
}
}