View source
<?php
namespace Drupal\cas_attributes\Subscriber;
use Drupal\cas\Event\CasPostLoginEvent;
use Drupal\cas\Event\CasPreLoginEvent;
use Drupal\cas\Event\CasPreRegisterEvent;
use Drupal\cas_attributes\Form\CasAttributesSettings;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\cas\Service\CasHelper;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Utility\Token;
use Symfony\Component\HttpFoundation\RequestStack;
class CasAttributesSubscriber implements EventSubscriberInterface {
protected $settings;
protected $tokenService;
protected $requestStack;
public function __construct(ConfigFactoryInterface $config_factory, Token $token_service, RequestStack $request_stack) {
$this->settings = $config_factory
->get('cas_attributes.settings');
$this->tokenService = $token_service;
$this->requestStack = $request_stack;
}
public static function getSubscribedEvents() {
$events[CasHelper::EVENT_PRE_REGISTER][] = [
'onPreRegister',
-1,
];
$events[CasHelper::EVENT_PRE_LOGIN][] = [
'onPreLogin',
20,
];
$events[CasHelper::EVENT_POST_LOGIN][] = [
'onPostLogin',
];
return $events;
}
public function onPreRegister(CasPreRegisterEvent $event) {
if ($this->settings
->get('field.sync_frequency') !== CasAttributesSettings::SYNC_FREQUENCY_NEVER) {
$field_mappings = $this
->getFieldMappings($event
->getCasPropertyBag()
->getAttributes());
if (!empty($field_mappings)) {
$event
->setPropertyValues($field_mappings);
}
}
if ($this->settings
->get('role.sync_frequency') !== CasAttributesSettings::SYNC_FREQUENCY_NEVER) {
$roleMappingResults = $this
->doRoleMapCheck($event
->getCasPropertyBag()
->getAttributes());
if (empty($roleMappingResults['add']) && $this->settings
->get('role.deny_registration_no_match')) {
$event
->setAllowAutomaticRegistration(FALSE);
}
else {
$existingProperties = $event
->getPropertyValues();
$rolesForUser = [];
if (!empty($existingProperties['roles'])) {
$rolesForUser = $existingProperties['roles'];
}
$rolesForUser = array_diff($rolesForUser, $roleMappingResults['remove']);
$rolesForUser = array_merge($rolesForUser, $roleMappingResults['add']);
$rolesForUser = array_unique($rolesForUser);
$event
->setPropertyValue('roles', $rolesForUser);
}
}
}
public function onPreLogin(CasPreLoginEvent $event) {
$account = $event
->getAccount();
if ($this->settings
->get('field.sync_frequency') === CasAttributesSettings::SYNC_FREQUENCY_EVERY_LOGIN) {
$field_mappings = $this
->getFieldMappings($event
->getCasPropertyBag()
->getAttributes());
if (!empty($field_mappings)) {
$overwrite = $this->settings
->get('field.overwrite');
foreach ($field_mappings as $field_name => $field_value) {
if ($overwrite || empty($account
->get($field_name))) {
$account
->set($field_name, $field_value);
}
}
}
}
$roleMappingResults = $this
->doRoleMapCheck($event
->getCasPropertyBag()
->getAttributes());
if ($this->settings
->get('role.sync_frequency') === CasAttributesSettings::SYNC_FREQUENCY_EVERY_LOGIN) {
foreach ($roleMappingResults['remove'] as $rid) {
$account
->removeRole($rid);
}
foreach ($roleMappingResults['add'] as $rid) {
$account
->addRole($rid);
}
}
if (empty($roleMappingResults['add']) && $this->settings
->get('role.deny_login_no_match')) {
$event
->cancelLogin();
}
}
protected function getFieldMappings(array $casAttributes) {
$mappings = $this->settings
->get('field.mappings');
if (empty($mappings)) {
return [];
}
$field_data = [];
foreach ($mappings as $field_name => $attribute_token) {
$result = trim($this->tokenService
->replace($attribute_token, [
'cas_attributes' => $casAttributes,
], [
'clear' => TRUE,
]));
$result = html_entity_decode($result);
if (!empty($result)) {
$field_data[$field_name] = $result;
}
}
return $field_data;
}
protected function doRoleMapCheck(array $attributes = NULL) {
$role_map = $this->settings
->get('role.mappings');
if (empty($role_map)) {
return [
'add' => [],
'remove' => [],
];
}
$rolesToAdd = [];
$rolesToRemove = [];
if (is_array($attributes)) {
$attributes = array_change_key_case($attributes, CASE_LOWER);
}
foreach ($role_map as $condition) {
$conditionAttribute = strtolower($condition['attribute']);
if (!isset($attributes[$conditionAttribute])) {
continue;
}
$attributeValue = $attributes[$conditionAttribute];
if (!is_array($attributeValue)) {
$attributeValue = [
$attributeValue,
];
}
$valueToMatch = $condition['value'];
$matched = FALSE;
switch ($condition['method']) {
case 'exact_single':
$matched = $this
->checkRoleMatchExactSingle($attributeValue, $valueToMatch);
break;
case 'exact_any':
$matched = $this
->checkRoleMatchExactAny($attributeValue, $valueToMatch);
break;
case 'contains_any':
$matched = $this
->checkRoleMatchContainsAny($attributeValue, $valueToMatch);
break;
case 'regex_any':
$matched = $this
->checkRoleMatchRegexAny($attributeValue, $valueToMatch);
default:
}
if (isset($condition['negate']) && $condition['negate']) {
$matched = !$matched;
}
if ($matched) {
$rolesToAdd[] = $condition['rid'];
}
elseif ($condition['remove_without_match']) {
$rolesToRemove[] = $condition['rid'];
}
}
return [
'add' => $rolesToAdd,
'remove' => $rolesToRemove,
];
}
protected function checkRoleMatchExactSingle(array $attributeValue, $valueToMatch) {
if (count($attributeValue) > 1) {
return FALSE;
}
$value = array_shift($attributeValue);
if ($value === $valueToMatch) {
return TRUE;
}
return FALSE;
}
protected function checkRoleMatchExactAny(array $attributeValue, $valueToMatch) {
foreach ($attributeValue as $value) {
if ($value === $valueToMatch) {
return TRUE;
}
}
return FALSE;
}
protected function checkRoleMatchContainsAny(array $attributeValue, $valueToMatch) {
foreach ($attributeValue as $value) {
if (strpos($value, $valueToMatch) !== FALSE) {
return TRUE;
}
}
return FALSE;
}
protected function checkRoleMatchRegexAny(array $attributeValue, $regex) {
foreach ($attributeValue as $value) {
if (@preg_match($regex, $value)) {
return TRUE;
}
}
return FALSE;
}
public function onPostLogin(CasPostLoginEvent $casPostLoginEvent) {
if ($this->settings
->get('sitewide_token_support')) {
$session = $this->requestStack
->getCurrentRequest()
->getSession();
$attributes = $casPostLoginEvent
->getCasPropertyBag()
->getAttributes();
$token_allowed_attributes = $this->settings
->get('token_allowed_attributes');
if (!empty($token_allowed_attributes)) {
$token_allowed_attributes = array_map('mb_strtolower', $token_allowed_attributes);
foreach ($attributes as $key => $value) {
if (!in_array(mb_strtolower($key), $token_allowed_attributes)) {
unset($attributes[$key]);
}
}
}
$session
->set('cas_attributes', $attributes);
}
}
}