Mapping Google Groups to Drupal user roles with Google Authentication
Mapping Google Groups to Drupal user roles with Google Authentication
jennifer
Thu, 06/03/2021 - 13:19
Mapping Google Groups to Drupal user roles with Google Authentication seemed like a straightforward task, but there were a few wrinkles in the process that I didn’t expect. We stumbled into the need for mapping groups to roles while performing a routine Drupal core upgrade from 8.8.5 to 8.9.13. Complications with the existing LDAP authentication’s upgrade path — and conversations with the client — steered us towards replacing LDAP with Google Authentication.
Overall the idea is simple enough: when a user signs into your Drupal site using Google Authentication, their membership(s) to various Google Groups should map to some existing Drupal user roles. This way, users in your organization who are already affiliated with various groups can be automatically assigned appropriate user permissions in your Drupal site for editing or accessing content, approving comments, re-arranging homepage promotions or whatever the case may be.
The majority of the functionality is established with just a few downloads, installations, and configurations. Our custom functionality relies on the Social API, Social Auth, and Social Auth Google modules, as well as the Google APIs Client Library for PHP. The first step is to install and enable the above mentioned modules and library. Then comes a little insider info on configuring the necessary Google Service Account, and finally a custom implementation of the EventSubscriberInterface that reacts to authentication via Social Auth to read from Google Groups memberships. Our custom code is packaged into a simple demo module you can download to get all of this working for yourself.
There are a lot of moving parts for something you’d expect to be a simple task, but in the end it’s a relatively quick setup if you know what to expect.
The devil’s in the details: Google Service Account configuration
This bit is pretty counterintuitive: Google users that authenticate via Google Authentication don’t actually have read access to their own groups. Weird, right? Where are you supposed to pull group information if the accounts can’t read their own group data from the API?
The answer is a Google Service Account. A properly configured Google Service Account can have read access to both users and their group relationship information, which allows it to act as a go-between during authentication to pull Google Group data and map it to Drupal roles. Configuring your Google Service Account isn’t self-explanatory, but luckily Joel Steidl put together the following screencast to walk you through it. Once you’ve set up the Google Service Account, you’ll just need to create and download a JSON key file to include in the code we’ll walk through further below.
Now that your Google Service Account is properly configured and your JSON key file has been safely stored away, it’s time to tie everything together with a few blocks of code that do the actual role assigning.
Role assignment during Google Authentication: The who’s who handshake
Once you’ve configured your Google Service Account and downloaded your JSON key file, you need code that reacts to Social Auth events (like a login via Google Authentication) to trigger the role mapping functionality. I’ve added some example code below that's part of a demo module that should get you 95% of the way there, although in our demo the role mapping itself — which Google Group becomes which Drupal role — is hard coded.
If you download my demo module you’ll see I’m reacting to both the USER_CREATED and USER_LOGIN events provided by the Social Auth module’s getSubscribedEvents method. This way we can reevaluate Google Group to Drupal role mappings each time a user logs in to make sure their roles and permissions stay up to date. You’ll also see that I’m verifying the user’s email address to make sure it falls within our expectations (user@your_domain.com), which you can modify or remove depending on your needs — but you want to make sure that your Google Service Account will have the appropriate access to this user’s group info.
The magic happens in the determineRoles method, where the JSON key file and the Google Service Account you setup previously will come into play. You’ll need to modify the getSecretsFile method to return your JSON key file, then change the $user_to_impersonate variable to the email address that you granted the Groups Reader role as discussed in Joel’s screencast. Finally, you'll need to update the $roleAssignment array with actual Google Group names and Drupal roles.
/**
* When a user logs in verify their Google assigned group & set permissions
*
* @param \Drupal\user\UserInterface $givenUser
* The passed in user object.
*
*/
protected function determineRoles($givenUser)
{
$KEY_FILE_LOCATION = $this->getSecretsFile();
// Only run if we have the secrets file
if ($KEY_FILE_LOCATION) {
// 1. Admin SDK API must get enabled for relevant project in Dev Console.
// 2. Service user must get created under relevant project and based on a user with
// 3. User must have Groups Reader permission.
// 4. Scope must get added to Sitewide Delegation.
$user_to_impersonate = 'example_google_account@your_domain.com';
$client = new Google_Client();
$client->setAuthConfig($KEY_FILE_LOCATION);
$client->setApplicationName('Get a Users Groups');
$client->setSubject($user_to_impersonate);
$client->setScopes([Google_Service_Directory::ADMIN_DIRECTORY_GROUP_READONLY]);
$groups = new Google_Service_Directory($client);
$params = [
'userKey' => $givenUser->getEmail(),
];
$results = $groups->groups->listGroups($params);
// Hold Map for roles based on Google Groups
$roleAssignment = [
"Author Group Name" => "author",
"Editor Group Name" => "editor",
"Publisher Group Name" => "publisher",
];
// Loop through the user's groups an add approved roles to array
foreach ($results['groups'] as $result) {
$name = $result['name'];
//Assign roles based on what was determined
if (array_key_exists($name, $roleAssignment)) {
$givenUser->addRole($roleAssignment[$name]);
$givenUser->save();
}
}
}
}
That’s it! With your modified demo module enabled, your users should get their roles automatically assigned on login. We were pretty excited to get Google Groups mapping to Drupal roles, so much so that my colleague Matthew Luzitano is considering packaging this functionality (and GUI configurations!) into a Drupal module. So if you’re not in any rush and don’t feel like browsing our demo code, you can always wait until that happens.
Do you have a different approach to mapping Google Groups to Drupal roles? We’d love to hear about it! Let us know in the comments below.