LoginHandler.php in Shibboleth Authentication 8
File
src/Login/LoginHandler.php
View source
<?php
namespace Drupal\shib_auth\Login;
use Drupal\Component\Utility\Random;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\SessionManagerInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
use Drupal\user\Entity\User;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
class LoginHandler implements LoginHandlerInterface {
protected $user;
protected $user_store;
protected $config;
protected $adv_config;
protected $db;
protected $shib_session;
protected $shib_logger;
protected $temp_store_factory;
protected $custom_data_store;
protected $session_manager;
protected $current_user;
protected $error_message;
protected $messenger;
const MYSQL_ER_DUP_KEY = 23000;
public function __construct(Connection $db, ImmutableConfig $config, ImmutableConfig $adv_config, EntityTypeManagerInterface $etm, ShibSessionVars $shib_session, LoggerInterface $shib_logger, PrivateTempStoreFactory $temp_store_factory, SessionManagerInterface $session_manager, AccountInterface $current_user, MessengerInterface $messenger) {
$this->db = $db;
$this->config = $config;
$this->adv_config = $adv_config;
$this->user_store = $etm
->getStorage('user');
$this->shib_session = $shib_session;
$this->shib_logger = $shib_logger;
$this->temp_store_factory = $temp_store_factory;
$this->session_manager = $session_manager;
$this->current_user = $current_user;
$this->messenger = $messenger;
$this->custom_data_store = $this->temp_store_factory
->get('shib_auth');
if ($this->current_user
->isAnonymous() && !isset($_SESSION['session_started'])) {
$_SESSION['session_started'] = TRUE;
$this->session_manager
->start();
}
}
public function shibLogin() {
try {
if (!$this
->checkUserExists()) {
if (!empty($this->shib_session
->getEmail())) {
$this->custom_data_store
->set('custom_email', $this->shib_session
->getEmail());
}
if (!$this->custom_data_store
->get('custom_email')) {
$this->custom_data_store
->set('return_url', \Drupal::request()
->getRequestUri());
$response = new RedirectResponse(Url::fromRoute('shib_auth.custom_data_form')
->toString());
return $response;
}
else {
$user_registered = $this
->registerNewUser();
}
}
else {
$user_registered = TRUE;
}
if ($user_registered) {
$this
->authenticateUser();
return FALSE;
}
} catch (\Exception $e) {
$this->shib_logger
->error($e);
$user = \Drupal::currentUser();
if ($user
->isAuthenticated()) {
user_logout();
}
if ($this
->getErrorMessage()) {
$this->messenger
->addError($this
->getErrorMessage());
}
$return_url = '';
if ($this->adv_config
->get('url_redirect_logout')) {
$return_url = '?return=' . $this->adv_config
->get('url_redirect_logout');
}
return new RedirectResponse($this->config
->get('shibboleth_logout_handler_url') . $return_url);
}
return FALSE;
}
private function registerNewUser($success = FALSE) {
$user_data = [
'name' => $this->shib_session
->getTargetedId(),
'mail' => $this->custom_data_store
->get('custom_email'),
'pass' => $this
->genPassword(),
'status' => 1,
];
try {
$this->user = $this->user_store
->create($user_data);
if (!($results = $this->user
->save())) {
throw new \Exception();
}
} catch (\Exception $e) {
if ($e
->getCode() == self::MYSQL_ER_DUP_KEY) {
$this
->setErrorMessage(t('There was an error creating your user. A user with your email address already exists.'));
throw new \Exception('Error creating new Drupal user from Shibboleth Session. Duplicate user row.');
}
else {
$this
->setErrorMessage(t('There was an error creating your user.'));
throw new \Exception('Error creating new Drupal user from Shibboleth Session.');
}
}
try {
$shib_data = [
'uid' => $this->user
->id(),
'targeted_id' => $this->shib_session
->getTargetedId(),
'idp' => $this->shib_session
->getIdp(),
'created' => \Drupal::time()
->getRequestTime(),
];
$success = $this->db
->insert('shib_authmap')
->fields($shib_data)
->execute();
if (!$success) {
throw new \Exception();
}
} catch (\Exception $e) {
$this
->setErrorMessage(t('There was an error creating your user.'));
throw new \Exception('Error creating new Drupal user from Shibboleth Session. Database insert on shib_authmap failed.');
}
return TRUE;
}
private function authenticateUser() {
if (empty($this->user)) {
$this
->setErrorMessage(t('There was an error logging you in.'));
throw new \Exception('No uid found for user when trying to initialize Drupal session.');
}
user_login_finalize($this->user);
return TRUE;
}
private function checkUserExists() {
$user_query = $this->db
->select('shib_authmap');
$user_query
->fields('shib_authmap', [
'id',
'uid',
'targeted_id',
]);
$user_query
->condition('targeted_id', $this->shib_session
->getTargetedId());
$results = $user_query
->execute()
->fetchAll();
if (empty($results)) {
return FALSE;
}
if (count($results) > 1) {
$this
->setErrorMessage(t('There was an error logging you in.'));
throw new \Exception('Multiple entries for a user exist in the shib_authmap table.');
}
$this->user = User::load($results[0]->uid);
if (empty($this->user)) {
$this
->setErrorMessage(t('There was an error logging you in.'));
throw new \Exception('User information exists in shib_authmap table, but Drupal user does not exist.');
}
return TRUE;
}
private function genPassword() {
$rand = new Random();
return $rand
->string(30);
}
public function getShibSession() {
return $this->shib_session;
}
private function setErrorMessage($message) {
$this->error_message = $message;
}
private function getErrorMessage() {
return $this->error_message;
}
}