class CasUserManager in CAS 2.x
Same name and namespace in other branches
- 8 src/Service/CasUserManager.php \Drupal\cas\Service\CasUserManager
Provides the 'cas.user_manager' service default implementation.
Hierarchy
- class \Drupal\cas\Service\CasUserManager
Expanded class hierarchy of CasUserManager
5 files declare their use of CasUserManager
- CasProtectedUserFieldConstraintValidator.php in src/
Plugin/ Validation/ Constraint/ CasProtectedUserFieldConstraintValidator.php - CasSettings.php in src/
Form/ CasSettings.php - CasUserAccessCheck.php in src/
Access/ CasUserAccessCheck.php - CasUserManagerTest.php in tests/
src/ Unit/ Service/ CasUserManagerTest.php - ServiceController.php in src/
Controller/ ServiceController.php
1 string reference to 'CasUserManager'
1 service uses CasUserManager
File
- src/
Service/ CasUserManager.php, line 24
Namespace
Drupal\cas\ServiceView source
class CasUserManager {
/**
* Email address for new users is combo of username + custom hostname.
*
* @var int
*/
const EMAIL_ASSIGNMENT_STANDARD = 0;
/**
* Email address for new users is derived from a CAS attirbute.
*
* @var int
*/
const EMAIL_ASSIGNMENT_ATTRIBUTE = 1;
/**
* Used to include the externalauth service from the external_auth module.
*
* @var \Drupal\externalauth\ExternalAuthInterface
*/
protected $externalAuth;
/**
* An authmap service object.
*
* @var \Drupal\externalauth\AuthmapInterface
*/
protected $authmap;
/**
* Stores settings object.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $settings;
/**
* Used to get session data.
*
* @var \Symfony\Component\HttpFoundation\Session\SessionInterface
*/
protected $session;
/**
* Used when storing CAS login data.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The CAS Helper.
*
* @var \Drupal\cas\Service\CasHelper
*/
protected $casHelper;
/**
* CAS proxy helper.
*
* @var \Drupal\cas\Service\CasProxyHelper
*/
protected $casProxyHelper;
/**
* Used to dispatch CAS login events.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* The name of the external auth provider we use.
*
* @var string
*/
protected $provider = 'cas';
/**
* CasUserManager constructor.
*
* @param \Drupal\externalauth\ExternalAuthInterface $external_auth
* The external auth interface.
* @param \Drupal\externalauth\AuthmapInterface $authmap
* The authmap interface.
* @param \Drupal\Core\Config\ConfigFactoryInterface $settings
* The settings.
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
* The session.
* @param \Drupal\Core\Database\Connection $database_connection
* The database connection.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
* @param \Drupal\cas\Service\CasHelper $cas_helper
* The CAS helper.
* @param \Drupal\cas\Service\CasProxyHelper $cas_proxy_helper
* The CAS Proxy helper.
*/
public function __construct(ExternalAuthInterface $external_auth, AuthmapInterface $authmap, ConfigFactoryInterface $settings, SessionInterface $session, Connection $database_connection, EventDispatcherInterface $event_dispatcher, CasHelper $cas_helper, CasProxyHelper $cas_proxy_helper) {
$this->externalAuth = $external_auth;
$this->authmap = $authmap;
$this->settings = $settings;
$this->session = $session;
$this->connection = $database_connection;
$this->eventDispatcher = $event_dispatcher;
$this->casHelper = $cas_helper;
$this->casProxyHelper = $cas_proxy_helper;
}
/**
* Register a local Drupal user given a CAS username.
*
* @param string $authname
* The CAS username.
* @param string $local_username
* The local Drupal username to be created.
* @param array $property_values
* (optional) Property values to assign to the user on registration.
*
* @return \Drupal\user\UserInterface
* The user entity of the newly registered user.
*
* @throws \Drupal\cas\Exception\CasLoginException
* When the user account could not be registered.
*/
public function register($authname, $local_username, array $property_values = []) {
$property_values['name'] = $local_username;
$property_values['pass'] = $this
->randomPassword();
try {
$user = $this->externalAuth
->register($authname, $this->provider, $property_values);
} catch (ExternalAuthRegisterException $e) {
throw new CasLoginException($e
->getMessage(), CasLoginException::USERNAME_ALREADY_EXISTS);
}
return $user;
}
/**
* Attempts to log the user in to the Drupal site.
*
* @param \Drupal\cas\CasPropertyBag $property_bag
* CasPropertyBag containing username and attributes from CAS.
* @param string $ticket
* The service ticket.
*
* @throws \Drupal\cas\Exception\CasLoginException
* Thrown if there was a problem logging in the user.
*/
public function login(CasPropertyBag $property_bag, $ticket) {
$account = $this->externalAuth
->load($property_bag
->getUsername(), $this->provider);
if ($account === FALSE) {
// Check if we should create the user or not.
$config = $this->settings
->get('cas.settings');
if ($config
->get('user_accounts.auto_register') === TRUE) {
$this->casHelper
->log(LogLevel::DEBUG, 'Existing account not found for user, attempting to auto-register.');
// Dispatch an event that allows modules to deny automatic registration
// for this user account or to set properties for the user that will
// be created.
$cas_pre_register_event = new CasPreRegisterEvent($property_bag);
$cas_pre_register_event
->setPropertyValue('mail', $this
->getEmailForNewAccount($property_bag));
$this->casHelper
->log(LogLevel::DEBUG, 'Dispatching EVENT_PRE_REGISTER.');
$this->eventDispatcher
->dispatch(CasHelper::EVENT_PRE_REGISTER, $cas_pre_register_event);
if ($cas_pre_register_event
->getAllowAutomaticRegistration()) {
$account = $this
->register($property_bag
->getUsername(), $cas_pre_register_event
->getDrupalUsername(), $cas_pre_register_event
->getPropertyValues());
}
else {
$reason = $cas_pre_register_event
->getCancelRegistrationReason();
throw (new CasLoginException("Cannot register user, an event listener denied access.", CasLoginException::SUBSCRIBER_DENIED_REG))
->setSubscriberCancelReason($reason);
}
}
else {
throw new CasLoginException("Cannot login, local Drupal user account does not exist.", CasLoginException::NO_LOCAL_ACCOUNT);
}
}
// Check if the retrieved user is blocked before moving forward.
if (!$account
->isActive()) {
throw new CasLoginException(sprintf('The username %s has not been activated or is blocked.', $account
->getAccountName()), CasLoginException::ACCOUNT_BLOCKED);
}
// Dispatch an event that allows modules to prevent this user from logging
// in and/or alter the user entity before we save it.
$pre_login_event = new CasPreLoginEvent($account, $property_bag);
$this->casHelper
->log(LogLevel::DEBUG, 'Dispatching EVENT_PRE_LOGIN.');
$this->eventDispatcher
->dispatch(CasHelper::EVENT_PRE_LOGIN, $pre_login_event);
// Save user entity since event listeners may have altered it.
// @todo Don't take it for granted. Find if the account was really altered.
// @todo Should this be swapped with the following if(...) block? Why
// altering the account if the login has been denied?
$account
->save();
if (!$pre_login_event
->getAllowLogin()) {
$reason = $pre_login_event
->getCancelLoginReason();
throw (new CasLoginException('Cannot login, an event listener denied access.', CasLoginException::SUBSCRIBER_DENIED_LOGIN))
->setSubscriberCancelReason($reason);
}
$this->externalAuth
->userLoginFinalize($account, $property_bag
->getUsername(), $this->provider);
$this
->storeLoginSessionData($this->session
->getId(), $ticket);
$this->session
->set('is_cas_user', TRUE);
$this->session
->set('cas_username', $property_bag
->getOriginalUsername());
$postLoginEvent = new CasPostLoginEvent($account, $property_bag);
$this->casHelper
->log(LogLevel::DEBUG, 'Dispatching EVENT_POST_LOGIN.');
$this->eventDispatcher
->dispatch(CasHelper::EVENT_POST_LOGIN, $postLoginEvent);
if ($this->settings
->get('proxy.initialize') && $property_bag
->getPgt()) {
$this->casHelper
->log(LogLevel::DEBUG, "Storing PGT information for this session.");
$this->casProxyHelper
->storePgtSession($property_bag
->getPgt());
}
}
/**
* Store the Session ID and ticket for single-log-out purposes.
*
* @param string $session_id
* The session ID, to be used to kill the session later.
* @param string $ticket
* The CAS service ticket to be used as the lookup key.
*/
protected function storeLoginSessionData($session_id, $ticket) {
if ($this->settings
->get('cas.settings')
->get('logout.enable_single_logout') === TRUE) {
$this->connection
->insert('cas_login_data')
->fields([
'sid',
'plainsid',
'ticket',
'created',
], [
Crypt::hashBase64($session_id),
$session_id,
$ticket,
time(),
])
->execute();
}
}
/**
* Return CAS username for account, or FALSE if it doesn't have one.
*
* @param int $uid
* The user ID.
*
* @return bool|string
* The CAS username if it exists, or FALSE otherwise.
*/
public function getCasUsernameForAccount($uid) {
return $this->authmap
->get($uid, $this->provider);
}
/**
* Return uid of account associated with passed in CAS username.
*
* @param string $cas_username
* The CAS username to lookup.
*
* @return bool|int
* The uid of the user associated with the $cas_username, FALSE otherwise.
*/
public function getUidForCasUsername($cas_username) {
return $this->authmap
->getUid($cas_username, $this->provider);
}
/**
* Save an association of the passed in Drupal user account and CAS username.
*
* @param \Drupal\user\UserInterface $account
* The user account entity.
* @param string $cas_username
* The CAS username.
*/
public function setCasUsernameForAccount(UserInterface $account, $cas_username) {
$this->authmap
->save($account, $this->provider, $cas_username);
}
/**
* Remove the CAS username association with the provided user.
*
* @param \Drupal\user\UserInterface $account
* The user account entity.
*/
public function removeCasUsernameForAccount(UserInterface $account) {
$this->authmap
->delete($account
->id(), $this->provider);
}
/**
* Generate a random password for new user registrations.
*
* @return string
* A random password.
*/
protected function randomPassword() {
// Default length is 10, use a higher number that's harder to brute force.
return \user_password(30);
}
/**
* Return the email address that should be assigned to an auto-register user.
*
* @param \Drupal\cas\CasPropertyBag $cas_property_bag
* The CasPropertyBag associated with the user's login attempt.
*
* @return string
* The email address.
*
* @throws \Drupal\cas\Exception\CasLoginException
* Thrown when the email address cannot be derived properly.
*/
public function getEmailForNewAccount(CasPropertyBag $cas_property_bag) {
$email_assignment_strategy = $this->settings
->get('cas.settings')
->get('user_accounts.email_assignment_strategy');
if ($email_assignment_strategy === self::EMAIL_ASSIGNMENT_STANDARD) {
return $cas_property_bag
->getUsername() . '@' . $this->settings
->get('cas.settings')
->get('user_accounts.email_hostname');
}
elseif ($email_assignment_strategy === self::EMAIL_ASSIGNMENT_ATTRIBUTE) {
$email_attribute = $this->settings
->get('cas.settings')
->get('user_accounts.email_attribute');
if (empty($email_attribute) || !array_key_exists($email_attribute, $cas_property_bag
->getAttributes())) {
throw new CasLoginException('Specified CAS email attribute does not exist.', CasLoginException::ATTRIBUTE_PARSING_ERROR);
}
$val = $cas_property_bag
->getAttributes()[$email_attribute];
if (empty($val)) {
throw new CasLoginException('Empty data found for CAS email attribute.', CasLoginException::ATTRIBUTE_PARSING_ERROR);
}
// The attribute value may actually be an array of values, but we need it
// to only contain 1 value.
if (is_array($val) && count($val) !== 1) {
throw new CasLoginException('Specified CAS email attribute was formatted in an unexpected way.', CasLoginException::ATTRIBUTE_PARSING_ERROR);
}
if (is_array($val)) {
$val = $val[0];
}
return trim($val);
}
else {
throw new CasLoginException('Invalid email address assignment type for auto user registration specified in settings.');
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
CasUserManager:: |
protected | property | An authmap service object. | |
CasUserManager:: |
protected | property | The CAS Helper. | |
CasUserManager:: |
protected | property | CAS proxy helper. | |
CasUserManager:: |
protected | property | Used when storing CAS login data. | |
CasUserManager:: |
protected | property | Used to dispatch CAS login events. | |
CasUserManager:: |
protected | property | Used to include the externalauth service from the external_auth module. | |
CasUserManager:: |
protected | property | The name of the external auth provider we use. | |
CasUserManager:: |
protected | property | Used to get session data. | |
CasUserManager:: |
protected | property | Stores settings object. | |
CasUserManager:: |
constant | Email address for new users is derived from a CAS attirbute. | ||
CasUserManager:: |
constant | Email address for new users is combo of username + custom hostname. | ||
CasUserManager:: |
public | function | Return CAS username for account, or FALSE if it doesn't have one. | |
CasUserManager:: |
public | function | Return the email address that should be assigned to an auto-register user. | |
CasUserManager:: |
public | function | Return uid of account associated with passed in CAS username. | |
CasUserManager:: |
public | function | Attempts to log the user in to the Drupal site. | |
CasUserManager:: |
protected | function | Generate a random password for new user registrations. | |
CasUserManager:: |
public | function | Register a local Drupal user given a CAS username. | |
CasUserManager:: |
public | function | Remove the CAS username association with the provided user. | |
CasUserManager:: |
public | function | Save an association of the passed in Drupal user account and CAS username. | |
CasUserManager:: |
protected | function | Store the Session ID and ticket for single-log-out purposes. | |
CasUserManager:: |
public | function | CasUserManager constructor. |