Skip to content

Commit d7ad700

Browse files
committed
Allow OIDC with Azure B2C
There are a couple of places where the client_secret should not be passed to Azure B2C as part of the authentication requests. B2C is picky about this, and will reject the token grant if passed. The data bindings also needed to be improved and allowed to suit custom values, as the B2C data bindings are different to the default bindings in AAD.
1 parent 7a9dbaa commit d7ad700

File tree

6 files changed

+35
-10
lines changed

6 files changed

+35
-10
lines changed

classes/form/application.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ protected function definition() {
9090
$mform->disabledIf('clientsecret', 'clientauthmethod', 'neq', AUTH_OIDC_AUTH_METHOD_SECRET);
9191
$mform->addElement('static', 'clientsecret_help', '', get_string('clientsecret_help', 'auth_oidc'));
9292

93+
// Auth token secret toggle.
94+
$mform->addElement('advcheckbox', 'accesstokenclientsecret', auth_oidc_config_name_in_form('accesstokenclientsecret'), '');
95+
$mform->setType('accesstokenclientsecret', PARAM_BOOL);
96+
$mform->addElement('static', 'accesstokenclientsecret_help', '', get_string('accesstokenclientsecret_help', 'auth_oidc'));
97+
9398
// Certificate private key.
9499
$mform->addElement('textarea', 'clientprivatekey', auth_oidc_config_name_in_form('clientprivatekey'),
95100
['rows' => 10, 'cols' => 80]);

classes/loginflow/base.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,19 +257,19 @@ public function get_userinfo($username) {
257257
if (!isset($userdata['email'])) {
258258
$email = $token->claim('email');
259259
if (!empty($email)) {
260-
$userdata['mail'] = $email;
260+
$userdata['email'] = $email;
261261
} else {
262262
if (!empty($upn)) {
263263
$aademailvalidateresult = filter_var($upn, FILTER_VALIDATE_EMAIL);
264264
if (!empty($aademailvalidateresult)) {
265-
$userdata['mail'] = $aademailvalidateresult;
265+
$userdata['email'] = $aademailvalidateresult;
266266
}
267267
}
268268
}
269269
}
270270
}
271271

272-
$updateduser = static::apply_configured_fieldmap_from_token($userdata, $eventtype);
272+
$updateduser = static::apply_configured_fieldmap_from_token($userdata, $eventtype, $token);
273273
$userinfo = (array)$updateduser;
274274
}
275275

@@ -281,9 +281,10 @@ public function get_userinfo($username) {
281281
*
282282
* @param array $userdata
283283
* @param string $eventtype
284+
* @param jwt $token
284285
* @return stdClass
285286
*/
286-
public static function apply_configured_fieldmap_from_token(array $userdata, string $eventtype) {
287+
public static function apply_configured_fieldmap_from_token(array $userdata, string $eventtype, jwt $token) {
287288
$user = new stdClass();
288289

289290
$fieldmappings = auth_oidc_get_field_mappings();
@@ -299,6 +300,12 @@ public static function apply_configured_fieldmap_from_token(array $userdata, str
299300

300301
if (isset($userdata[$remotefield])) {
301302
$user->$localfield = $userdata[$remotefield];
303+
} else {
304+
// Try a manual token claim on the value provided.
305+
$tokenval = $token->claim($remotefield);
306+
if (!is_null($tokenval)) {
307+
$user->$localfield = $tokenval;
308+
}
302309
}
303310
}
304311

classes/oidcclient.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,15 @@ public function tokenrequest($code) {
333333
'redirect_uri' => $this->redirecturi,
334334
];
335335

336+
$sendsecret = get_config('auth_oidc', 'accesstokenclientsecret');
336337
switch (get_config('auth_oidc', 'clientauthmethod')) {
337338
case AUTH_OIDC_AUTH_METHOD_CERTIFICATE:
338339
$params['client_assertion_type'] = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer';
339340
$params['client_assertion'] = static::generate_client_assertion();
340341
$params['tenant'] = 'common';
341342
break;
342343
default:
343-
$params['client_secret'] = $this->clientsecret;
344+
$params = $sendsecret ? ['client_secret' => $this->clientsecret] : [];
344345
}
345346
$returned = $this->httpclient->post($this->endpoints['token'], $params);
346347
return utils::process_json_response($returned, ['id_token' => null]);
@@ -365,6 +366,7 @@ public function app_access_token_request() {
365366
break;
366367
default:
367368
$params['client_secret'] = $this->clientsecret;
369+
$params = [];
368370
}
369371

370372
$tokenendpoint = $this->endpoints['token'];

lang/en/auth_oidc.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
$string['idp_type_microsoft'] = 'Microsoft identity platform (v2.0)';
6161
$string['idp_type_other'] = 'Other';
6262
$string['cfg_authenticationlink_desc'] = '<a href="{$a}" target="_blank">Link to IdP and authentication configuration</a>';
63+
$string['accesstokenclientsecret'] = 'Send client secret in access token requests.';
64+
$string['accesstokenclientsecret_help'] = 'Some IdPs like Azure B2C do not allow the client secret to be sent in token exchange requests. Disable this config to remove the client secret from the request.';
6365
$string['authendpoint'] = 'Authorization Endpoint';
6466
$string['authendpoint_help'] = 'The URI of the Authorization endpoint from your IdP to use.<br/>
6567
Note if the site is to be configured to allow users from other tenants to access, tenant specific authorization endpoint cannot be used.';
@@ -83,6 +85,8 @@
8385
$string['clientcert_help'] = 'When using <b>certificate</b> authentication method, this is the public key, or certificate, used in to authenticate with IdP.';
8486
$string['tenantnameorguid'] = 'Tenant name or GUID';
8587
$string['tenantnameorguid_help'] = 'Don\'t include https:// if use tenant name.';
88+
$string['cfg_custom_mapping'] = 'Use custom data mappings';
89+
$string['cfg_custom_mapping_desc'] = 'Allow custom attribute entry for data mappings.';
8690
$string['cfg_domainhint_key'] = 'Domain Hint';
8791
$string['cfg_domainhint_desc'] = 'When using the <b>Authorization Code</b> login flow, pass this value as the "domain_hint" parameter. "domain_hint" is used by some OpenID Connect IdP to make the login process easier for users. Check with your provider to see whether they support this parameter.';
8892
$string['cfg_err_invalidauthendpoint'] = 'Invalid Authorization Endpoint';

manageapplication.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
$form = new application(null, ['oidcconfig' => $oidcconfig]);
5656

5757
$formdata = [];
58-
foreach (['idptype', 'clientid', 'clientauthmethod', 'clientsecret', 'clientprivatekey', 'clientcert', 'tenantnameorguid',
58+
foreach (['idptype', 'clientid', 'clientauthmethod', 'clientsecret', 'accesstokenclientsecret', 'clientprivatekey', 'clientcert', 'tenantnameorguid',
5959
'authendpoint', 'tokenendpoint', 'oidcresource', 'oidcscope'] as $field) {
6060
if (isset($oidcconfig->$field)) {
6161
$formdata[$field] = $oidcconfig->$field;
@@ -73,7 +73,7 @@
7373
}
7474

7575
// Prepare config settings to save.
76-
$configstosave = ['idptype', 'clientid', 'tenantnameorguid', 'clientauthmethod', 'authendpoint', 'tokenendpoint',
76+
$configstosave = ['idptype', 'clientid', 'tenantnameorguid', 'clientauthmethod', 'accesstokenclientsecret', 'authendpoint', 'tokenendpoint',
7777
'oidcresource', 'oidcscope'];
7878

7979
// Depending on the value of clientauthmethod, save clientsecret or (clientprivatekey and clientcert).
@@ -110,4 +110,3 @@
110110
$form->display();
111111

112112
echo $OUTPUT->footer();
113-

settings.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,20 @@
225225

226226
// Other settings page and its settings.
227227
$fieldmappingspage = new admin_settingpage('auth_oidc_field_mapping', get_string('settings_page_field_mapping', 'auth_oidc'));
228+
$fieldmappingspage->add(new admin_setting_configcheckbox('auth_oidc/custom_field_mapping',
229+
get_string('cfg_custom_mapping', 'auth_oidc'), get_string('cfg_custom_mapping_desc', 'auth_oidc'), 0));
228230
$ADMIN->add('oidcfolder', $fieldmappingspage);
229231

230232
// Display locking / mapping of profile fields.
231233
$authplugin = get_auth_plugin('oidc');
232-
auth_oidc_display_auth_lock_options($fieldmappingspage, $authplugin->authtype, $authplugin->userfields,
233-
get_string('cfg_field_mapping_desc', 'auth_oidc'), true, false, $authplugin->get_custom_user_profile_fields());
234+
if (get_config('auth_oidc', 'custom_field_mapping')) {
235+
display_auth_lock_options($fieldmappingspage, $authplugin->authtype, $authplugin->userfields,
236+
get_string('cfg_field_mapping_desc', 'auth_oidc'), true, true, $authplugin->get_custom_user_profile_fields());
237+
} else {
238+
auth_oidc_display_auth_lock_options($fieldmappingspage, $authplugin->authtype, $authplugin->userfields,
239+
get_string('cfg_field_mapping_desc', 'auth_oidc'), true, false, $authplugin->get_custom_user_profile_fields());
240+
}
241+
234242
}
235243

236244
$settings = null;

0 commit comments

Comments
 (0)