openid_connect_windows_aad.module in OpenID Connect Microsoft Azure Active Directory client 2.0.x
Same filename and directory in other branches
OpenID Connect Windows AAD module file.
File
openid_connect_windows_aad.moduleView source
<?php
/**
* @file
* OpenID Connect Windows AAD module file.
*/
use Drupal\user\Entity\Role;
use Drupal\user\UserInterface;
use Drupal\user\RoleInterface;
use Drupal\Core\Form\FormState;
/**
* Implements hook_admin_settings_alter().
*/
function openid_connect_windows_aad_form_openid_connect_admin_settings_alter(&$form, FormState $form_state, $form_id) {
array_unshift($form['#submit'], '_openid_connect_windows_aad_form_submit_refresh_routes');
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function _openid_connect_windows_aad_form_submit_refresh_routes(&$form, FormState $form_state) {
$assume_disabled = FALSE;
try {
$configuration = \Drupal::config('openid_connect.settings.windows_aad');
$settings = $configuration
->get('settings');
$aad_enabled = (bool) $configuration
->get('enabled');
$sso_enabled = isset($settings['enable_single_sign_out']) && $settings['enable_single_sign_out'];
} catch (Exception $exception) {
// Not likely to happen but assume windows_aad is not enabled if it does.
$assume_disabled = TRUE;
}
// Get clients' enabled status.
$aad_checked = (bool) $form_state
->getValue([
'clients_enabled',
'windows_aad',
]);
$sso_checked = (bool) $form_state
->getValue([
'clients',
'windows_aad',
'settings',
'enable_single_sign_out',
]);
// Rebuild routes since we may override the user.logout route for single
// sign off.
if (!$assume_disabled && ($aad_enabled !== $aad_checked || $sso_enabled !== $sso_checked) || $assume_disabled && (isset($aad_enabled) && $aad_enabled !== $aad_checked || $aad_checked)) {
\Drupal::logger('openid_connect_windows_aad')
->debug('rebuild routes');
\Drupal::service('router.builder')
->setRebuildNeeded();
}
}
/**
* Implements hook_openid_connect_userinfo_save().
*/
function openid_connect_windows_aad_openid_connect_userinfo_save(UserInterface $account, array $context) {
if ($context['plugin_id'] !== 'windows_aad' || !isset($context['user_data']['groups']) && !isset($context['userinfo']['groups']['value'])) {
return;
}
try {
// Ensure windows_aad auth is enabled and configured for group mapping.
$configuration = \Drupal::config('openid_connect.settings.windows_aad');
$settings = $configuration
->get('settings');
$aad_enabled = (bool) $configuration
->get('enabled');
if (!$aad_enabled || !$settings['map_ad_groups_to_roles']) {
return;
}
} catch (Exception $exception) {
// Not likely to happen but assume windows_aad is not enabled if it does.
return;
}
$mapped_roles = $groups = [];
$user_roles = $account
->getRoles(TRUE);
$all_roles = Role::loadMultiple();
unset($all_roles[RoleInterface::ANONYMOUS_ID], $all_roles[RoleInterface::AUTHENTICATED_ID]);
// Retreive a list of previously mapped roles.
$UserData = \Drupal::service('user.data');
$previous_mapped_roles = $UserData
->get('openid_connect_windows_aad', $account
->id(), 'mapped_roles');
if (!isset($previous_mapped_roles)) {
$previous_mapped_roles = [];
}
// Groups found in the user_data returned from the auth request.
if (isset($context['user_data']['groups'])) {
foreach ($context['user_data']['groups'] as $gid) {
$groups[$gid] = $gid;
}
}
$group_id_key = 'id';
// Depending on the API the group data has different keys.
if ($settings['userinfo_graph_api_wa'] === 1) {
$group_id_key = 'objectId';
}
// Groups found in the userinfo returned from the user info request.
if (isset($context['userinfo']['groups']['value'])) {
foreach ($context['userinfo']['groups']['value'] as $group) {
$groups[$group['displayName']] = $group['displayName'];
if (!isset($groups[$group[$group_id_key]])) {
$groups[$group[$group_id_key]] = $group[$group_id_key];
}
}
}
switch ($settings['group_mapping']['method']) {
// Manual mapping.
case 1:
if (!empty($settings['group_mapping']['mappings'])) {
$role_group_map = [];
// The mappings is a text area with each line containing the following
// format: <role id or label>|<AD Group ID or Label>;<AD Group ID or Label>; ...
// Thus we need to split the text out into its components and determine
// if there are any roles that should map to this user.
$list = explode("\n", $settings['group_mapping']['mappings']);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
foreach ($list as $position => $text) {
$matches = [];
if (preg_match('/(.*)\\|(.*)/', $text, $matches)) {
// Trim key and value to avoid unwanted spaces issues.
$key = trim($matches[1]);
if (!$key) {
continue;
}
// Ensure we are dealing with the Role's id and not label.
if (!isset($all_roles[$key])) {
foreach ($all_roles as $role) {
if ($key === $role
->label()) {
$key = $role
->id();
}
}
}
if (!isset($all_roles[$key])) {
continue;
}
// Ensure we end up with a non-empty array of AD groups.
$value = trim($matches[2]);
$values = explode(';', $value);
$values = array_map('trim', $values);
if (!$values) {
continue;
}
// If any of the mappings match the user's groups then the user
// should be granted the mapped role.
if (array_intersect($values, $groups)) {
$mapped_roles[$key] = $key;
}
}
}
}
break;
// Automatic mapping.
default:
foreach ($all_roles as $role) {
// Only Role labels can be matched to the list of the user's groups.
if (in_array($role
->label(), $groups)) {
$key = $role
->id();
$mapped_roles[$key] = $key;
}
}
break;
}
if ($mapped_roles) {
$mapped_roles = array_keys($mapped_roles);
}
// Determine which mapped roles the user does not already have
$add = array_diff($mapped_roles, $user_roles);
if ($settings['group_mapping']['strict']) {
// Strict mode so remove any role the user has that is unmapped.
$remove = array_diff($user_roles, $mapped_roles);
}
else {
// Not so strict, only remove roles previously mapped, but nolonger are.
$remove = array_diff($previous_mapped_roles, $mapped_roles);
}
// Remove Drupal roles the user is no longer permitted to have.
foreach ($remove as $rid) {
if (isset($all_roles[$rid])) {
$role = $all_roles[$rid];
$account
->removeRole($rid);
$vars = [
'@role' => $role
->label(),
'@user' => $account
->id(),
];
\Drupal::logger('openid_connect_windows_aad')
->notice('Removed role @role from user @user', $vars);
}
}
// Add Drupal roles that the user should be granted.
foreach ($add as $rid) {
$account
->addRole($rid);
$role = $all_roles[$rid];
$vars = [
'@role' => $role
->label(),
'@user' => $account
->id(),
];
\Drupal::logger('openid_connect_windows_aad')
->notice('Added role @role to user @user', $vars);
}
// Save which roles were mapped so we can properly handle removing mapped
// roles that change the next time.
$UserData
->set('openid_connect_windows_aad', $account
->id(), 'mapped_roles', $mapped_roles);
}
Functions
Name | Description |
---|---|
openid_connect_windows_aad_form_openid_connect_admin_settings_alter | Implements hook_admin_settings_alter(). |
openid_connect_windows_aad_openid_connect_userinfo_save | Implements hook_openid_connect_userinfo_save(). |
_openid_connect_windows_aad_form_submit_refresh_routes | Implements hook_form_FORM_ID_alter(). |