Score:0

Adding role to a user after login - after simplesamlphp/externalauth

mx flag

Adding more context to my question

here is the scenario: a) the organization has different departments b) actual Drupal roles are not assigned through simplesaml role attribute but through simplesaml attribute: IsUnit_A => value: yes or no c) all members of UnitA >> 'isUnit_A=yes', get 'unitA' role; which is assigned through suggestion #1 of the below answer "Assign them via the module's configuration". such as: unitA:IsUnit_A,=,Yes d) all non-UnitA members are assigned 'noUnitA' role such as: noUnitA:IsUnit_A,=,No e) Exceptions: using the module's configuration as well we grant exceptions to a few users; for example, some users from other departments are granted 'unitA' role. For example: unitA:uid,=,user21

So, my goal is to once all roles have been assigned according to the "Automatic role population from simpleSAMLphp attributes" in simplesaml configuration, then using a hook check if the current user has both roles, then remove one: noUniteA.

The problem with the simplesaml hooks is that they evaluate the current user pre rendering what is specified in 'Automatic role population from simpleSAMLphp attributes'

Do you happen to know if there is any hook that it's triggered after SAML roles are assigned through 'Automatic role population from simpleSAMLphp attributes' is rendered and before page content is loaded?

- - - - - - - - - - - - - - -

I've successfully created a custom module calling the 'hook_user_login' to add a role to the current user if the condition is met.

Environment:

Drupal Version: 9.5.10 | PHP Version: 8.1.17 | Database Version: 8.0.34

In my local everything runs to satisfaction;

<?php

use Drupal\user\Entity\User;

/**
 * Implements hook_user_login().
 * 
 * Custom query function to remove role after the user logged in.
 */
function remove_role_user_login($account){
    
    // load current user
    $loaded_user = User::load(\Drupal::currentUser()->id());

    $current_user = \Drupal::currentUser();

    // get current user's roles
    $array_roles = $current_user->getRoles();

    $roles = implode(", ", $array_roles );

    if (in_array("role_1", $array_roles) && in_array("role_2", $array_roles)) {
       // adding some logging for debugging purpoes
        \Drupal::logger('remove_role')->notice("role_1 and role_2 are in roles");
        \Drupal::logger('remove_role')->notice($roles);
        // it has both roles, so remove 'role_2' 
        $loaded_user->removeRole('role_2');
        $loaded_user->save();

    } 
    // leaving the else statement for dubigging purposes
    else {
        \Drupal::logger('remove_role')->notice("role_1 and role_2 are not in roles");
        \Drupal::logger('remove_role')->notice($roles);
    }
}

However, on the server where authentication goes through SimpleSamlphp script changes get overwritten with the roles assigned by SimpleSamlphp

I can confirm that the hook_user_login() is triggered because notices are recorded in database log ('drush ws')

Which hook shall I use to apply changes after SimpleSaml authentication?

Thanks

UPDATE I was not able to find a solution to dynamically change user's roles. I ended up applying content access by role using content hook; not ideal because is more demanding for the application (it has to check on every page), but it go the job done.

Score:2
br flag

You can:

  1. Assign them via the module's configuration, if they are listed by the Identity Provider. Go to admin/config/people/simplesamlphp_auth/sync and configure Automatic role population from simpleSAMLphp attributes according the instruction.

  2. Use hook_simplesamlphp_auth_user_roles_alter

  3. hook_simplesamlphp_auth_user_attributes should also actually work with the user roles

The hooks are well documented inside simplesamlphp_auth.api.php

/**
 * Hook to alter the roles assigned to a SAML-authenticated user.
 *
 * Whenever a user's roles are evaluated this hook will be called, allowing
 * custom logic to be used to alter or even completely replace the roles
 * evaluated.
 *
 * @param array &$roles
 *   The roles that have been selected for the current user
 *   by the role evaluation process.
 * @param array $attributes
 *   The SimpleSAMLphp attributes for this user.
 */
function hook_simplesamlphp_auth_user_roles_alter(&$roles, $attributes) {
  if (isset($attributes['roles'])) {
    // The roles provided by the IdP.
    $sso_roles = $attributes['roles'];

    // Match role names in the saml attributes to local role names.
    $user_roles = array_intersect(user_roles(), $sso_roles);

    foreach (array_keys($user_roles) as $rid) {
      $roles[$rid] = $rid;
    }
  }
}

/**
 * Hook to alter a Drupal user account after SAML authentication.
 *
 * Allows other modules to change fields or properties on the Drupal account
 * after a user logged in through SimpleSAMLphp. This can be used to add
 * map additional SAML attributes to Drupal user profile fields.
 *
 * @param \Drupal\user\UserInterface $account
 *   The Drupal account that can be altered.
 * @param array $attributes
 *   The SimpleSAMLphp attributes for this user.
 *
 * @return \Drupal\user\UserInterface|bool
 *   The altered Drupal account or FALSE if nothing was changed.
 */
function hook_simplesamlphp_auth_user_attributes(\Drupal\user\UserInterface $account, $attributes) {
  $saml_first_name = $attributes['first_name'];
  if ($saml_first_name) {
    $account->set('field_first_name', $saml_first_name);
    return $account;
  }
  return FALSE;
}

user3891775 avatar
mx flag
many thanks for your response; it was very insightful. Unfortunately, after testing with different hooks, the are all triggered before "your #1 suggestion Assign them via the module's configuration, if they are listed by the Identity Provider" which is the one I have implemented and wanted to modify on the fly. I've updated my question to give more context.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.