mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
MDL-61789 auth_oauth2: Allow admin to choose profile fields for mapping
Update oauth2 to allow mapping of provider attributes against user profile fields. Fields can also be locked to prevent user changes. Co-Authored-By: Michael Milette <michael.milette@tngconsulting.ca>
This commit is contained in:
parent
b8b905cd90
commit
6793891887
@ -60,7 +60,7 @@ class user_field_mapping extends persistent {
|
||||
|
||||
// Internal.
|
||||
$choices = $userfieldmapping->get_internalfield_list();
|
||||
$mform->addElement('select', 'internalfield', get_string('userfieldinternalfield', 'tool_oauth2'), $choices);
|
||||
$mform->addElement('selectgroups', 'internalfield', get_string('userfieldinternalfield', 'tool_oauth2'), $choices);
|
||||
$mform->addHelpButton('internalfield', 'userfieldinternalfield', 'tool_oauth2');
|
||||
|
||||
$mform->addElement('hidden', 'action', 'edit');
|
||||
|
39
admin/tool/oauth2/tests/behat/user_profile_fields.feature
Normal file
39
admin/tool/oauth2/tests/behat/user_profile_fields.feature
Normal file
@ -0,0 +1,39 @@
|
||||
@tool @tool_oauth2 @javascript
|
||||
|
||||
Feature: OAuth2 user profile fields functionality
|
||||
In order to use them later for authentication or repository plugins
|
||||
As an administrator
|
||||
I need to be able to map data fields provided by an Oauth2 provider
|
||||
to custom user profile fields defined by an administrator.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| userwithinformation | userwithinformation | 1 | userwithinformation@example.com |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Users > Accounts > User profile fields" in site administration
|
||||
And I click on "Create a new profile field" "link"
|
||||
And I click on "Text input" "link"
|
||||
And I set the following fields to these values:
|
||||
| Short name | test_shortname |
|
||||
| Name | test field name |
|
||||
And I click on "Save changes" "button"
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
|
||||
Scenario: Verify custom user profile field mapping
|
||||
Given I press "Microsoft"
|
||||
And I should see "Create new service: Microsoft"
|
||||
And I set the following fields to these values:
|
||||
| Name | Testing service |
|
||||
| Client ID | thisistheclientid |
|
||||
| Client secret | supersecret |
|
||||
When I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And I should see "Testing service"
|
||||
And I click on "Configure user field mappings" "link" in the "Testing service" "table_row"
|
||||
And I click on "Create new user field mapping for issuer \"Testing service\"" "button"
|
||||
And I set the following fields to these values:
|
||||
| External field name | sub |
|
||||
| Internal field name | test field name |
|
||||
And I click on "Save changes" "button"
|
||||
And I should see "test_shortname"
|
@ -260,7 +260,8 @@ class api {
|
||||
|
||||
// Map supplied issuer user info to Moodle user fields.
|
||||
$userfieldmapping = new \core\oauth2\user_field_mapping();
|
||||
foreach ($userfieldmapping->get_internalfield_list() as $field) {
|
||||
$userfieldlist = $userfieldmapping->get_internalfield_list();
|
||||
foreach (reset($userfieldlist) as $field) {
|
||||
if (isset($userinfo[$field]) && $userinfo[$field]) {
|
||||
$user->$field = $userinfo[$field];
|
||||
}
|
||||
@ -309,7 +310,8 @@ class api {
|
||||
|
||||
// Map supplied issuer user info to Moodle user fields.
|
||||
$userfieldmapping = new \core\oauth2\user_field_mapping();
|
||||
foreach ($userfieldmapping->get_internalfield_list() as $field) {
|
||||
$userfieldlist = $userfieldmapping->get_internalfield_list();
|
||||
foreach (reset($userfieldlist) as $field) {
|
||||
if (isset($userinfo[$field]) && $userinfo[$field]) {
|
||||
$user->$field = $userinfo[$field];
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ class auth extends \auth_plugin_base {
|
||||
public function __construct() {
|
||||
$this->authtype = 'oauth2';
|
||||
$this->config = get_config('auth_oauth2');
|
||||
$this->customfields = $this->get_custom_user_profile_fields();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,23 +310,35 @@ class auth extends \auth_plugin_base {
|
||||
return $userdata;
|
||||
}
|
||||
|
||||
$allfields = array_merge($this->userfields, $this->customfields);
|
||||
|
||||
// Go through each field from the external data.
|
||||
foreach ($externaldata as $fieldname => $value) {
|
||||
if (!in_array($fieldname, $this->userfields)) {
|
||||
if (!in_array($fieldname, $allfields)) {
|
||||
// Skip if this field doesn't belong to the list of fields that can be synced with the OAuth2 issuer.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!property_exists($userdata, $fieldname)) {
|
||||
// Just in case this field is on the list, but not part of the user data. This shouldn't happen though.
|
||||
$userhasfield = property_exists($userdata, $fieldname);
|
||||
// Find out if it is a profile field.
|
||||
$isprofilefield = strpos($fieldname, 'profile_field_') === 0;
|
||||
$profilefieldname = str_replace('profile_field_', '', $fieldname);
|
||||
$userhasprofilefield = $isprofilefield && array_key_exists($profilefieldname, $userdata->profile);
|
||||
|
||||
// Just in case this field is on the list, but not part of the user data. This shouldn't happen though.
|
||||
if (!($userhasfield || $userhasprofilefield)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the old value.
|
||||
$oldvalue = (string)$userdata->$fieldname;
|
||||
$oldvalue = $isprofilefield ? (string) $userdata->profile[$profilefieldname] : (string) $userdata->$fieldname;
|
||||
|
||||
// Get the lock configuration of the field.
|
||||
$lockvalue = $this->config->{'field_lock_' . $fieldname};
|
||||
if (!empty($this->config->{'field_lock_' . $fieldname})) {
|
||||
$lockvalue = $this->config->{'field_lock_' . $fieldname};
|
||||
} else {
|
||||
$lockvalue = 'unlocked';
|
||||
}
|
||||
|
||||
// We should update fields that meet the following criteria:
|
||||
// - Lock value set to 'unlocked'; or 'unlockedifempty', given the current value is empty.
|
||||
@ -525,6 +538,9 @@ class auth extends \auth_plugin_base {
|
||||
exit();
|
||||
} else {
|
||||
\auth_oauth2\api::link_login($userinfo, $issuer, $moodleuser->id, true);
|
||||
// We dont have profile loaded on $moodleuser, so load it.
|
||||
require_once($CFG->dirroot.'/user/profile/lib.php');
|
||||
profile_load_custom_fields($moodleuser);
|
||||
$userinfo = $this->update_user($userinfo, $moodleuser);
|
||||
// No redirect, we will complete this login.
|
||||
}
|
||||
|
@ -31,5 +31,6 @@ if ($ADMIN->fulltree) {
|
||||
|
||||
$authplugin = get_auth_plugin('oauth2');
|
||||
display_auth_lock_options($settings, $authplugin->authtype, $authplugin->userfields,
|
||||
get_string('auth_fieldlocks_help', 'auth'), false, false);
|
||||
get_string('auth_fieldlocks_help', 'auth'), false, false,
|
||||
$authplugin->customfields);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ class user_field_mapping extends persistent {
|
||||
* @return array
|
||||
*/
|
||||
private static function get_user_fields() {
|
||||
return array_merge(\core_user::AUTHSYNCFIELDS, ['picture', 'username']);
|
||||
return array_merge(\core_user::AUTHSYNCFIELDS, ['picture', 'username'], self::get_profile_field_names());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,7 +72,9 @@ class user_field_mapping extends persistent {
|
||||
* @return array
|
||||
*/
|
||||
public function get_internalfield_list() {
|
||||
return array_combine(self::get_user_fields(), self::get_user_fields());
|
||||
$userfields = array_merge(\core_user::AUTHSYNCFIELDS, ['picture', 'username']);
|
||||
$internalfields = array_combine($userfields, $userfields);
|
||||
return array_merge(['' => $internalfields], self::get_profile_field_list());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,4 +89,39 @@ class user_field_mapping extends persistent {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of valid custom profile user fields.
|
||||
*
|
||||
* @return array array of profile field names
|
||||
*/
|
||||
private static function get_profile_field_names(): array {
|
||||
$profilefields = profile_get_user_fields_with_data(0);
|
||||
$profilefieldnames = [];
|
||||
foreach ($profilefields as $field) {
|
||||
$profilefieldnames[] = $field->inputname;
|
||||
}
|
||||
return $profilefieldnames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of profile fields
|
||||
* in a format they can be used for choices in a group select menu.
|
||||
*
|
||||
* @return array array of category name with its profile fields
|
||||
*/
|
||||
private function get_profile_field_list(): array {
|
||||
$customfields = profile_get_user_fields_with_data_by_category(0);
|
||||
$data = [];
|
||||
foreach ($customfields as $category) {
|
||||
foreach ($category as $field) {
|
||||
$categoryname = $field->get_category_name();
|
||||
if (!isset($data[$categoryname])) {
|
||||
$data[$categoryname] = [];
|
||||
}
|
||||
$data[$categoryname][$field->inputname] = $field->field->name;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user