Skip to content

Commit 2024110

Browse files
committed
feat: add fallback idp/mdl attribute mapping
Used when the primary mapping does not match against any particular user. This can be used in the case where attributes used for id management are transitioned from one field to another, and allows for a gradual non-disruptive rollover.
1 parent 2dc645c commit 2024110

File tree

3 files changed

+66
-22
lines changed

3 files changed

+66
-22
lines changed

classes/auth.php

+48-22
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,9 @@ public function saml_login_complete($attributes) {
671671
}
672672

673673
$attr = $this->config->idpattr;
674-
if (empty($attributes[$attr])) {
675-
// Missing mapping IdP attribute. Login failed.
674+
$attrsecondary = $this->config->idpattrsecondary;
675+
if (empty($attributes[$attr]) && empty($attributes[$attrsecondary])) {
676+
// Missing mapping IdP attribute (both primary and secondary). Login failed.
676677
$event = \core\event\user_login_failed::create(['other' => ['username' => 'unknown',
677678
'reason' => AUTH_LOGIN_NOUSER]]);
678679
$event->trigger();
@@ -689,26 +690,15 @@ public function saml_login_complete($attributes) {
689690

690691
// Find Moodle user.
691692
$user = false;
692-
foreach ($attributes[$attr] as $uid) {
693-
$insensitive = false;
694-
$accentsensitive = true;
695-
if ($this->config->tolower == saml2_settings::OPTION_TOLOWER_LOWER_CASE) {
696-
$this->log(__FUNCTION__ . " to lowercase for $uid");
697-
$uid = strtolower($uid);
698-
}
699-
if ($this->config->tolower == saml2_settings::OPTION_TOLOWER_CASE_INSENSITIVE) {
700-
$this->log(__FUNCTION__ . " case insensitive compare for $uid");
701-
$insensitive = true;
702-
}
703-
if ($this->config->tolower == saml2_settings::OPTION_TOLOWER_CASE_AND_ACCENT_INSENSITIVE) {
704-
$this->log(__FUNCTION__ . " case and accent insensitive compare for $uid");
705-
$insensitive = true;
706-
$accentsensitive = false;
707-
}
708-
if ($user = user_extractor::get_user($this->config->mdlattr, $uid, $insensitive, $accentsensitive)) {
709-
// We found a user.
710-
break;
711-
}
693+
694+
// Primary IdP attribute mapping.
695+
if (!empty($attributes[$attr])) {
696+
$user = $this->find_user_by_attributes($attributes[$attr], $this->config->mdlattr);
697+
}
698+
699+
// Secondary IdP attribute mapping (if user not found yet).
700+
if ($user === false && !empty($attributes[$attrsecondary])) {
701+
$user = $this->find_user_by_attributes($attributes[$attrsecondary], $this->config->mdlattrsecondary);
712702
}
713703

714704
// Moodle Workplace - Check IdP's tenant availability, for new user pre-allocate to tenant.
@@ -1343,4 +1333,40 @@ private function execute_callback($function, $file = 'lib.php') {
13431333
}
13441334
}
13451335
}
1336+
1337+
/**
1338+
* Find and return a user matched using a list of provided attributes, against a Moodle field.
1339+
*
1340+
* Applies any case matching settings configured.
1341+
*
1342+
* @param array $idpattrs
1343+
* @param string $mdlattr
1344+
* @return mixed false if no user found, otherwise the user object.
1345+
*/
1346+
private function find_user_by_attributes(array $idpattrs, string $mdlattr) {
1347+
$user = false;
1348+
foreach ($idpattrs as $uid) {
1349+
$insensitive = false;
1350+
$accentsensitive = true;
1351+
if ($this->config->tolower == saml2_settings::OPTION_TOLOWER_LOWER_CASE) {
1352+
$this->log(__FUNCTION__ . " to lowercase for $uid");
1353+
$uid = strtolower($uid);
1354+
}
1355+
if ($this->config->tolower == saml2_settings::OPTION_TOLOWER_CASE_INSENSITIVE) {
1356+
$this->log(__FUNCTION__ . " case insensitive compare for $uid");
1357+
$insensitive = true;
1358+
}
1359+
if ($this->config->tolower == saml2_settings::OPTION_TOLOWER_CASE_AND_ACCENT_INSENSITIVE) {
1360+
$this->log(__FUNCTION__ . " case and accent insensitive compare for $uid");
1361+
$insensitive = true;
1362+
$accentsensitive = false;
1363+
}
1364+
if ($user = user_extractor::get_user($mdlattr, $uid, $insensitive, $accentsensitive)) {
1365+
// We found a user.
1366+
break;
1367+
}
1368+
}
1369+
return $user;
1370+
}
1371+
13461372
}

lang/en/auth_saml2.php

+4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
$string['flagresponsetype_help'] = 'If access is blocked based on configured group restrictions, how should Moodle respond?';
9696
$string['idpattr_help'] = 'Which IdP attribute should be matched against a Moodle user field?';
9797
$string['idpattr'] = 'Mapping IdP';
98+
$string['idpattrsecondary_help'] = 'When the primary IdP attribute does not match a user, map this field to the secondary Moodle mapped field.';
99+
$string['idpattrsecondary'] = 'Secondary Mapping IdP';
98100
$string['idpmetadata_badurl'] = 'Invalid metadata at {$a}';
99101
$string['idpmetadata_help'] = 'To use multiple IdPs enter each public metadata url on a new line.<br/>To override a name, place text before the http. eg. "Forced IdP Name http://ssp.local/simplesaml/saml2/idp/metadata.php"';
100102
$string['idpmetadata'] = 'IdP metadata xml OR public xml URL';
@@ -115,6 +117,8 @@
115117
$string['manageidpsheading'] = 'Manage available Identity Providers (IdPs)';
116118
$string['mdlattr_help'] = 'Which Moodle user field should the IdP attribute be matched to?';
117119
$string['mdlattr'] = 'Mapping Moodle';
120+
$string['mdlattrsecondary_help'] = 'Which Moodle user field should the IdP secondary attribute be matched to?';
121+
$string['mdlattrsecondary'] = 'Secondary Mapping Moodle';
118122
$string['wantassertionssigned'] = 'Want assertions signed';
119123
$string['wantassertionssigned_help'] = 'Whether assertions received by this SP must be signed';
120124
$string['assertionsconsumerservices'] = 'Assertions consumer services';

settings.php

+14
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,20 @@
314314
saml2_settings::OPTION_TOLOWER_EXACT,
315315
$toloweroptions));
316316

317+
// IDP attribute (secondary).
318+
$settings->add(new admin_setting_configtext(
319+
'auth_saml2/idpattrsecondary',
320+
get_string('idpattrsecondary', 'auth_saml2'),
321+
get_string('idpattrsecondary_help', 'auth_saml2'),
322+
'', PARAM_TEXT));
323+
324+
// Moodle Field (secondary).
325+
$settings->add(new admin_setting_configselect(
326+
'auth_saml2/mdlattrsecondary',
327+
get_string('mdlattrsecondary', 'auth_saml2'),
328+
get_string('mdlattrsecondary_help', 'auth_saml2'),
329+
'', user_fields::get_supported_fields()));
330+
317331
// Requested Attributes.
318332
$settings->add(new admin_setting_configtextarea(
319333
'auth_saml2/requestedattributes',

0 commit comments

Comments
 (0)