Problem/Motivation
This error message appears when there is an exception when user information is retrieved with access token and $userinfo is set to FALSE.
Trying to access array offset on value of type bool in Drupal\openid_connect\Form\OpenIDConnectSettingsForm->buildForm() (line 273 of modules/contrib/openid_connect/src/Form/OpenIDConnectSettingsForm.php).
Steps to reproduce
Variable $userinfo is FALSE.
Variable $user_data is not empty.
Variable $results is FALSE.
private function buildContext(OpenIDConnectClientInterface $client, array $tokens) {
$user_data = $client->decodeIdToken($tokens['id_token']);
$userinfo = $client->retrieveUserInfo($tokens['access_token']);
$provider = $client->getPluginId();
$context = [
'tokens' => $tokens,
'plugin_id' => $provider,
'user_data' => $user_data,
];
$this->moduleHandler->alter('openid_connect_userinfo', $userinfo, $context);
// Whether we have no usable user information.
if (empty($user_data) && empty($userinfo)) {
$this->logger->error('No user information provided by @provider (@code @error). Details: @details', ['@provider' => $provider]);
return FALSE;
}
if ($userinfo && empty($userinfo['email'])) {
$this->logger->error('No e-mail address provided by @provider (@code @error). Details: @details', ['@provider' => $provider]);
return FALSE;
}
$sub = $this->extractSub($user_data, $userinfo);
if (empty($sub)) {
$this->logger->error('No "sub" found from @provider (@code @error). Details: @details', ['@provider' => $provider]);
return FALSE;
}
/** @var \Drupal\user\UserInterface|bool $account */
$account = $this->authmap->userLoadBySub($sub, $provider);
$context = [
'tokens' => $tokens,
'plugin_id' => $provider,
'user_data' => $user_data,
'userinfo' => $userinfo,
'sub' => $sub,
'account' => $account,
];
$results = $this->moduleHandler->invokeAll('openid_connect_pre_authorize', [
$account,
$context,
]);
// Deny access if any module returns FALSE.
if (in_array(FALSE, $results, TRUE)) {
$this->logger->error('Login denied for @email via pre-authorize hook.', ['@email' => $userinfo['email']]);
return FALSE;
}
// If any module returns an account, set local $account to that.
foreach ($results as $result) {
if ($result instanceof UserInterface) {
$context['account'] = $result;
break;
}
}
return $context;
}
Code will try to log an error with $userinfo['email'] but $userinfo is FALSE so we will get a warning.
Proposed resolution
Change this part of code:
if ($userinfo && empty($userinfo['email'])) {
$this->logger->error('No e-mail address provided by @provider (@code @error). Details: @details', ['@provider' => $provider]);
return FALSE;
}
By this one:
if (!$userinfo || empty($userinfo['email'])) {
$this->logger->error('No e-mail address provided by @provider (@code @error). Details: @details', ['@provider' => $provider]);
return FALSE;
}
This way, when $userinfo is FALSE, the error message "No e-mail address provided..." will be displayed instead of continuing code execution.
Remaining tasks
User interface changes
API changes
Data model changes